cmdopt: add a simple omnipresent help option
This commit is contained in:
parent
ad2f3261de
commit
736fe9a156
79
cmdopt.cpp
79
cmdopt.cpp
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
using util::cmdopt::option::base;
|
using util::cmdopt::option::base;
|
||||||
using util::cmdopt::option::bytes;
|
using util::cmdopt::option::bytes;
|
||||||
@ -31,10 +32,11 @@ using util::cmdopt::parser;
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
base::base (std::string _name):
|
base::base (std::string _name, std::string _description):
|
||||||
m_name (_name),
|
|
||||||
m_required (false),
|
m_required (false),
|
||||||
m_seen (false)
|
m_seen (false),
|
||||||
|
m_name (std::move (_name)),
|
||||||
|
m_description (std::move (_description))
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
@ -77,13 +79,21 @@ base::finish (void)
|
|||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
std::string
|
const std::string&
|
||||||
base::name (void) const
|
base::name (void) const
|
||||||
{
|
{
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
const std::string&
|
||||||
|
base::description (void) const
|
||||||
|
{
|
||||||
|
return m_description;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
bool
|
bool
|
||||||
base::required (void) const
|
base::required (void) const
|
||||||
@ -117,8 +127,8 @@ base::seen (bool _seen)
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
null::null (std::string _name):
|
null::null (std::string _name, std::string _description):
|
||||||
base (std::move (_name))
|
base (std::move (_name), std::move (_description))
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
@ -139,8 +149,8 @@ null::execute (const char *restrict)
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
present::present (std::string _name, bool &_data):
|
present::present (std::string _name, std::string _description, bool &_data):
|
||||||
base (std::move (_name)),
|
base (std::move (_name), std::move (_description)),
|
||||||
m_data (_data)
|
m_data (_data)
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
@ -214,8 +224,8 @@ namespace util { namespace cmdopt { namespace option {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <typename T>
|
template <typename T>
|
||||||
count<T>::count (std::string _name, T &_data):
|
count<T>::count (std::string _name, std::string _description, T &_data):
|
||||||
value<T> (std::move (_name), _data)
|
value<T> (std::move (_name), std::move (_description), _data)
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
@ -270,6 +280,7 @@ suffix_to_multiplier (char c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
void
|
void
|
||||||
bytes::execute (const char *restrict str)
|
bytes::execute (const char *restrict str)
|
||||||
{
|
{
|
||||||
@ -298,7 +309,7 @@ parser::scan (int argc, const char *const *argv)
|
|||||||
CHECK (argv);
|
CHECK (argv);
|
||||||
|
|
||||||
for (auto &j: m_options)
|
for (auto &j: m_options)
|
||||||
j->start ();
|
std::get<2> (j)->start ();
|
||||||
|
|
||||||
// start iterating after our program's name
|
// start iterating after our program's name
|
||||||
int i = 1;
|
int i = 1;
|
||||||
@ -319,7 +330,7 @@ parser::scan (int argc, const char *const *argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto &j: m_options)
|
for (auto &j: m_options)
|
||||||
j->finish ();
|
std::get<2> (j)->finish ();
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -343,6 +354,8 @@ parser::parse_long (int pos, int argc, const char *const *argv)
|
|||||||
const char *last = start + strlen (start);
|
const char *last = start + strlen (start);
|
||||||
|
|
||||||
std::string key { start, eq ? eq : last };
|
std::string key { start, eq ? eq : last };
|
||||||
|
if (key == "help")
|
||||||
|
print_help (argc, argv);
|
||||||
|
|
||||||
// find the handler
|
// find the handler
|
||||||
auto handle_pos = std::find_if (m_long.begin (),
|
auto handle_pos = std::find_if (m_long.begin (),
|
||||||
@ -388,6 +401,8 @@ parser::parse_short (int pos, int argc, const char *const *argv)
|
|||||||
if (len > 2 || pos + 1 == argc || argv[pos+1][0] == '-') {
|
if (len > 2 || pos + 1 == argc || argv[pos+1][0] == '-') {
|
||||||
for (size_t i = 1; i < len; ++i) {
|
for (size_t i = 1; i < len; ++i) {
|
||||||
auto letter = argv[pos][i];
|
auto letter = argv[pos][i];
|
||||||
|
if (letter == 'h')
|
||||||
|
print_help (argc, argv);
|
||||||
|
|
||||||
auto hpos = std::find_if (m_short.begin (),
|
auto hpos = std::find_if (m_short.begin (),
|
||||||
m_short.end (),
|
m_short.end (),
|
||||||
@ -411,3 +426,43 @@ parser::parse_short (int pos, int argc, const char *const *argv)
|
|||||||
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
void
|
||||||
|
parser::print_help (const int argc,
|
||||||
|
const char *const *argv) const
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
|
||||||
|
CHECK_EQ (m_short.size (), m_options.size ());
|
||||||
|
CHECK_EQ (m_long.size (), m_options.size ());
|
||||||
|
|
||||||
|
if (m_options.empty ())
|
||||||
|
exit (0);
|
||||||
|
|
||||||
|
// find the longest long form argument so we can set field alignment
|
||||||
|
auto largest = std::max_element (m_long.begin (),
|
||||||
|
m_long.end (),
|
||||||
|
[] (const auto &a, const auto &b) {
|
||||||
|
return std::get<0> (a).size () < std::get<0> (b).size ();
|
||||||
|
});
|
||||||
|
int longwidth = std::get<0> (*largest).size ();
|
||||||
|
|
||||||
|
// field width requires an alignment. we don't care about preserving
|
||||||
|
// state as we're about to bail anyway
|
||||||
|
std::cout << std::left;
|
||||||
|
|
||||||
|
// print all the option info
|
||||||
|
std::cout << "usage: " << argv[0] << '\n';
|
||||||
|
|
||||||
|
for (auto &o: m_options) {
|
||||||
|
std::cout << '\t'
|
||||||
|
<< '-' << std::get<0> (o) << '\t'
|
||||||
|
<< std::setw (longwidth) << std::get<1> (o) << '\t'
|
||||||
|
<< std::setw (0) << std::get<2> (o)->description ()
|
||||||
|
<< '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
27
cmdopt.hpp
27
cmdopt.hpp
@ -27,8 +27,10 @@
|
|||||||
namespace util { namespace cmdopt {
|
namespace util { namespace cmdopt {
|
||||||
namespace option {
|
namespace option {
|
||||||
class base {
|
class base {
|
||||||
|
protected:
|
||||||
|
base (std::string name, std::string description);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
base (std::string name);
|
|
||||||
virtual ~base ();
|
virtual ~base ();
|
||||||
|
|
||||||
virtual void execute (void);
|
virtual void execute (void);
|
||||||
@ -36,7 +38,8 @@ namespace util { namespace cmdopt {
|
|||||||
virtual void start (void);
|
virtual void start (void);
|
||||||
virtual void finish (void);
|
virtual void finish (void);
|
||||||
|
|
||||||
std::string name (void) const;
|
const std::string& name (void) const;
|
||||||
|
const std::string& description (void) const;
|
||||||
|
|
||||||
bool required (void) const;
|
bool required (void) const;
|
||||||
bool required (bool);
|
bool required (bool);
|
||||||
@ -45,15 +48,17 @@ namespace util { namespace cmdopt {
|
|||||||
bool seen (bool);
|
bool seen (bool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_name;
|
|
||||||
bool m_required;
|
bool m_required;
|
||||||
bool m_seen;
|
bool m_seen;
|
||||||
|
|
||||||
|
std::string m_name;
|
||||||
|
std::string m_description;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class null : public base {
|
class null : public base {
|
||||||
public:
|
public:
|
||||||
null (std::string name);
|
explicit null (std::string name, std::string description);
|
||||||
|
|
||||||
virtual void execute (void) override;
|
virtual void execute (void) override;
|
||||||
virtual void execute (const char *restrict) override;
|
virtual void execute (const char *restrict) override;
|
||||||
@ -62,7 +67,7 @@ namespace util { namespace cmdopt {
|
|||||||
|
|
||||||
class present : public base {
|
class present : public base {
|
||||||
public:
|
public:
|
||||||
present (std::string name, bool&);
|
present (std::string name, std::string description, bool&);
|
||||||
|
|
||||||
using base::execute;
|
using base::execute;
|
||||||
virtual void execute (void) override;
|
virtual void execute (void) override;
|
||||||
@ -77,7 +82,7 @@ namespace util { namespace cmdopt {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
class value : public base {
|
class value : public base {
|
||||||
public:
|
public:
|
||||||
value (std::string name, T&);
|
value (std::string name, std::string description, T&);
|
||||||
|
|
||||||
using base::execute;
|
using base::execute;
|
||||||
void execute (const char *restrict) override;
|
void execute (const char *restrict) override;
|
||||||
@ -94,7 +99,7 @@ namespace util { namespace cmdopt {
|
|||||||
template <typename T = unsigned>
|
template <typename T = unsigned>
|
||||||
class count : public value<T> {
|
class count : public value<T> {
|
||||||
public:
|
public:
|
||||||
count (std::string name, T&);
|
count (std::string name, std::string description, T&);
|
||||||
|
|
||||||
using value<T>::execute;
|
using value<T>::execute;
|
||||||
void execute (void) override;
|
void execute (void) override;
|
||||||
@ -141,6 +146,7 @@ namespace util { namespace cmdopt {
|
|||||||
int parse_long (int pos, int argc, const char *const *argv);
|
int parse_long (int pos, int argc, const char *const *argv);
|
||||||
int parse_short (int pos, int argc, const char *const *argv);
|
int parse_short (int pos, int argc, const char *const *argv);
|
||||||
|
|
||||||
|
void print_help [[noreturn]] (int argc, const char *const *argv) const;
|
||||||
|
|
||||||
using short_t = std::tuple<char,option::base&>;
|
using short_t = std::tuple<char,option::base&>;
|
||||||
using long_t = std::tuple<std::string,option::base&>;
|
using long_t = std::tuple<std::string,option::base&>;
|
||||||
@ -148,7 +154,12 @@ namespace util { namespace cmdopt {
|
|||||||
std::vector<short_t> m_short;
|
std::vector<short_t> m_short;
|
||||||
std::vector<long_t> m_long;
|
std::vector<long_t> m_long;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<option::base>> m_options;
|
std::vector<
|
||||||
|
std::tuple<
|
||||||
|
char,
|
||||||
|
std::string,
|
||||||
|
std::unique_ptr<option::base>>
|
||||||
|
> m_options;
|
||||||
};
|
};
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
11
cmdopt.ipp
11
cmdopt.ipp
@ -24,8 +24,8 @@
|
|||||||
namespace util { namespace cmdopt {
|
namespace util { namespace cmdopt {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
template <typename T>
|
template <typename T>
|
||||||
option::value<T>::value (std::string _name, T &_data):
|
option::value<T>::value (std::string _name, std::string _description, T &_data):
|
||||||
base (std::move (_name)),
|
base (std::move (_name), std::move (_description)),
|
||||||
m_data (_data)
|
m_data (_data)
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
@ -88,16 +88,13 @@ namespace util { namespace cmdopt {
|
|||||||
std::string description,
|
std::string description,
|
||||||
Args&&... args)
|
Args&&... args)
|
||||||
{
|
{
|
||||||
// TODO: make use of the description with the help option
|
auto handler = std::make_unique<T> (longname, description, std::forward<Args> (args)...);
|
||||||
(void)description;
|
|
||||||
|
|
||||||
auto handler = std::make_unique<T> (longname, std::forward<Args> (args)...);
|
|
||||||
T& ref = *handler;
|
T& ref = *handler;
|
||||||
|
|
||||||
m_short.emplace_back (shortname, ref);
|
m_short.emplace_back (shortname, ref);
|
||||||
m_long .emplace_back (longname, ref);
|
m_long .emplace_back (longname, ref);
|
||||||
|
|
||||||
m_options.emplace_back (std::move (handler));
|
m_options.emplace_back (shortname, longname, std::move (handler));
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user