cmdopt: add positional argument support
This commit is contained in:
parent
8ea827aab0
commit
f13c4487c6
208
cmdopt.cpp
208
cmdopt.cpp
|
@ -11,7 +11,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
*
|
||||||
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2013-2016 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cmdopt.hpp"
|
#include "cmdopt.hpp"
|
||||||
|
@ -23,25 +23,11 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
using util::cmdopt::option::base;
|
using namespace util::cmdopt;
|
||||||
using util::cmdopt::option::bytes;
|
using namespace util::cmdopt::option;
|
||||||
using util::cmdopt::option::count;
|
|
||||||
using util::cmdopt::option::null;
|
|
||||||
using util::cmdopt::option::present;
|
|
||||||
using util::cmdopt::option::value;
|
|
||||||
using util::cmdopt::parser;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
base::base (std::string _name, std::string _description):
|
|
||||||
m_required (false),
|
|
||||||
m_seen (false),
|
|
||||||
m_name (std::move (_name)),
|
|
||||||
m_description (std::move (_description))
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
base::~base ()
|
base::~base ()
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
|
@ -50,15 +36,15 @@ base::~base ()
|
||||||
void
|
void
|
||||||
base::execute (void)
|
base::execute (void)
|
||||||
{
|
{
|
||||||
throw invalid_null (m_name);
|
throw invalid_null ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void
|
void
|
||||||
base::execute (const char *restrict)
|
base::execute (const char *restrict value)
|
||||||
{
|
{
|
||||||
throw invalid_value (m_name);
|
throw invalid_value (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,23 +61,7 @@ void
|
||||||
base::finish (void)
|
base::finish (void)
|
||||||
{
|
{
|
||||||
if (m_required && !m_seen)
|
if (m_required && !m_seen)
|
||||||
throw invalid_required (m_name);
|
throw invalid_required ();
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
const std::string&
|
|
||||||
base::name (void) const
|
|
||||||
{
|
|
||||||
return m_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
const std::string&
|
|
||||||
base::description (void) const
|
|
||||||
{
|
|
||||||
return m_description;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,12 +98,6 @@ base::seen (bool _seen)
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
null::null (std::string _name, std::string _description):
|
|
||||||
base (std::move (_name), std::move (_description))
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void
|
void
|
||||||
null::execute (void)
|
null::execute (void)
|
||||||
{
|
{
|
||||||
|
@ -159,8 +123,7 @@ null::example (void) const
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
present::present (std::string _name, std::string _description, bool &_data):
|
present::present (bool &_data):
|
||||||
base (std::move (_name), std::move (_description)),
|
|
||||||
m_data (_data)
|
m_data (_data)
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
|
@ -243,8 +206,8 @@ namespace util { namespace cmdopt { namespace option {
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <typename T>
|
template <typename T>
|
||||||
count<T>::count (std::string _name, std::string _description, T &_data):
|
count<T>::count (T &_data):
|
||||||
value<T> (std::move (_name), std::move (_description), _data)
|
value<T> (_data)
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
@ -294,7 +257,8 @@ suffix_to_multiplier (char c)
|
||||||
return util::pow (1024UL, 1);
|
return util::pow (1024UL, 1);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw util::cmdopt::invalid_value ("bytes");
|
const char str[2] = { c, '\0' };
|
||||||
|
throw std::invalid_argument (str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,13 +274,16 @@ bytes::execute (const char *restrict str)
|
||||||
CHECK_LE (tail, last);
|
CHECK_LE (tail, last);
|
||||||
|
|
||||||
if (tail == str) {
|
if (tail == str) {
|
||||||
throw invalid_value (name ());
|
throw invalid_value (str);
|
||||||
} else if (tail == last) {
|
} else if (tail == last) {
|
||||||
data (val);
|
data (val);
|
||||||
} else if (tail + 1 == last) {
|
} else if (tail + 1 == last) {
|
||||||
data (val * suffix_to_multiplier (*tail));
|
try {
|
||||||
|
data (val * suffix_to_multiplier (*tail));
|
||||||
|
} catch (const std::invalid_argument&)
|
||||||
|
{ throw invalid_value (str); }
|
||||||
} else
|
} else
|
||||||
throw invalid_value (name ());
|
throw invalid_value (str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -328,7 +295,7 @@ parser::scan (int argc, const char *const *argv)
|
||||||
CHECK (argv);
|
CHECK (argv);
|
||||||
|
|
||||||
for (auto &j: m_options)
|
for (auto &j: m_options)
|
||||||
std::get<2> (j)->start ();
|
std::get<std::unique_ptr<option::base>> (j)->start ();
|
||||||
|
|
||||||
// start iterating after our program's name
|
// start iterating after our program's name
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
@ -337,7 +304,13 @@ parser::scan (int argc, const char *const *argv)
|
||||||
|
|
||||||
// bail if there's no potential for an option
|
// bail if there's no potential for an option
|
||||||
if (len < 2 || argv[i][0] != '-')
|
if (len < 2 || argv[i][0] != '-')
|
||||||
return i;
|
break;
|
||||||
|
|
||||||
|
// stop processing named options on '--'
|
||||||
|
if (len == 2 && argv[i][1] == '-') {
|
||||||
|
++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// parse longopt
|
// parse longopt
|
||||||
auto inc = argv[i][1] == '-'
|
auto inc = argv[i][1] == '-'
|
||||||
|
@ -348,8 +321,17 @@ parser::scan (int argc, const char *const *argv)
|
||||||
i += inc;
|
i += inc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process the positional arguments
|
||||||
|
for (size_t cursor = 0; i < argc && cursor < m_positional.size (); ++i, ++cursor)
|
||||||
|
m_positional[cursor].get ().execute (argv[i]);
|
||||||
|
|
||||||
|
// ensure we've processed all the arguments
|
||||||
|
if (i != argc)
|
||||||
|
throw unhandled_argument (i);
|
||||||
|
|
||||||
|
// allow arguments to check if they've been successfully handled
|
||||||
for (auto &j: m_options)
|
for (auto &j: m_options)
|
||||||
std::get<2> (j)->finish ();
|
std::get<std::unique_ptr<option::base>> (j)->finish ();
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -379,11 +361,11 @@ parser::parse_long (int pos, int argc, const char *const *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 (),
|
||||||
m_long.end (),
|
m_long.end (),
|
||||||
[&] (auto i) { return std::get<0> (i) == key; });
|
[&] (auto i) { return std::get<std::string> (i) == key; });
|
||||||
if (handle_pos == m_long.end ())
|
if (handle_pos == m_long.end ())
|
||||||
throw invalid_key (key);
|
throw invalid_key (key);
|
||||||
|
|
||||||
auto &handler = std::get<1> (*handle_pos);
|
auto &handler = std::get<option::base&> (*handle_pos);
|
||||||
|
|
||||||
// maybe grab a value from the next atom and dispatch
|
// maybe grab a value from the next atom and dispatch
|
||||||
if (!eq) {
|
if (!eq) {
|
||||||
|
@ -425,10 +407,10 @@ parser::parse_short (int pos, int argc, const char *const *argv)
|
||||||
|
|
||||||
auto hpos = std::find_if (m_short.begin (),
|
auto hpos = std::find_if (m_short.begin (),
|
||||||
m_short.end (),
|
m_short.end (),
|
||||||
[letter] (auto j) { return std::get<0> (j) == letter; });
|
[letter] (auto j) { return std::get<char> (j) == letter; });
|
||||||
if (hpos == m_short.end ())
|
if (hpos == m_short.end ())
|
||||||
throw invalid_key (std::to_string (letter));
|
throw invalid_key (std::to_string (letter));
|
||||||
std::get<1> (*hpos).execute ();
|
std::get<option::base&> (*hpos).execute ();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -438,10 +420,10 @@ parser::parse_short (int pos, int argc, const char *const *argv)
|
||||||
auto letter = argv[pos][1];
|
auto letter = argv[pos][1];
|
||||||
auto hpos = std::find_if (m_short.begin (),
|
auto hpos = std::find_if (m_short.begin (),
|
||||||
m_short.end (),
|
m_short.end (),
|
||||||
[letter] (auto i) { return std::get<0> (i) == letter; });
|
[letter] (auto i) { return std::get<char> (i) == letter; });
|
||||||
if (hpos == m_short.end ())
|
if (hpos == m_short.end ())
|
||||||
throw invalid_key (std::to_string (letter));
|
throw invalid_key (std::to_string (letter));
|
||||||
std::get<1> (*hpos).execute (argv[pos+1]);
|
std::get<option::base&> (*hpos).execute (argv[pos+1]);
|
||||||
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
@ -492,13 +474,109 @@ parser::print_help (const int argc,
|
||||||
std::cout << "usage: " << argv[0] << '\n';
|
std::cout << "usage: " << argv[0] << '\n';
|
||||||
|
|
||||||
for (auto &o: m_options) {
|
for (auto &o: m_options) {
|
||||||
std::cout << '\t'
|
auto ptr = std::get<std::unique_ptr<option::base>> (o).get ();
|
||||||
<< '-' << std::get<char> (o) << '\t'
|
|
||||||
<< std::setw (longwidth) << std::get<std::string> (o) << '\t'
|
auto s = std::find_if (
|
||||||
<< std::setw (longexample) << std::get<std::unique_ptr<option::base>> (o)->example () << '\t'
|
std::cbegin (m_short),
|
||||||
<< std::setw (0) << std::get<2> (o)->description ()
|
std::cend (m_short),
|
||||||
|
[ptr] (auto j) {
|
||||||
|
return &std::get<option::base&> (j) == ptr;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
auto l = std::find_if (
|
||||||
|
std::cbegin (m_long),
|
||||||
|
std::cend (m_long),
|
||||||
|
[ptr] (auto j) {
|
||||||
|
return &std::get<option::base&> (j) == ptr;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << '\t';
|
||||||
|
if (s != std::cend (m_short))
|
||||||
|
std::cout << '-' << std::get<char> (*s) << '\t';
|
||||||
|
else
|
||||||
|
std::cout << '\t';
|
||||||
|
|
||||||
|
std::cout << std::setw (longwidth);
|
||||||
|
if (l != std::cend (m_long))
|
||||||
|
std::cout << std::get<std::string> (*l) << '\t';
|
||||||
|
else
|
||||||
|
std::cout << ' ' << '\t';
|
||||||
|
|
||||||
|
std::cout << std::setw (longexample) << ptr->example () << '\t'
|
||||||
|
<< std::setw (0) << std::get<std::string> (o)
|
||||||
<< '\n';
|
<< '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
exit (0);
|
exit (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
invalid_key::invalid_key (std::string _key):
|
||||||
|
m_key (std::move (_key))
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
const char*
|
||||||
|
invalid_key::what (void) const noexcept
|
||||||
|
{
|
||||||
|
return m_key.c_str ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
invalid_value::invalid_value (std::string _value):
|
||||||
|
m_value (_value)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
const char*
|
||||||
|
invalid_value::what (void) const noexcept
|
||||||
|
{
|
||||||
|
return m_value.c_str ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
const char*
|
||||||
|
invalid_null::what (void) const noexcept
|
||||||
|
{
|
||||||
|
static const char WHAT[] = "unexpected null option was encountered";
|
||||||
|
return WHAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
const char*
|
||||||
|
invalid_required::what (void) const noexcept
|
||||||
|
{
|
||||||
|
static const char WHAT[] = "required option not seen";
|
||||||
|
return WHAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
unhandled_argument::unhandled_argument (int _index):
|
||||||
|
m_index (_index)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
int
|
||||||
|
unhandled_argument::index (void) const noexcept
|
||||||
|
{
|
||||||
|
return m_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
const char*
|
||||||
|
unhandled_argument::what (void) const noexcept
|
||||||
|
{
|
||||||
|
static const char WHAT[] = "unhandled argument";
|
||||||
|
return WHAT;
|
||||||
|
}
|
||||||
|
|
103
cmdopt.hpp
103
cmdopt.hpp
|
@ -11,26 +11,30 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
*
|
||||||
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2013-2016 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef __UTIL_CMDLINE_HPP
|
#ifndef __UTIL_CMDLINE_HPP
|
||||||
#define __UTIL_CMDLINE_HPP
|
#define __UTIL_CMDLINE_HPP
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <tuple>
|
|
||||||
#include <vector>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
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:
|
||||||
|
// we deal almost exclusively with vtables, so disable copying
|
||||||
|
// just in case we do something stupid.
|
||||||
|
base () { }
|
||||||
|
base (const base&) = delete;
|
||||||
|
base& operator= (const base&) = delete;
|
||||||
|
|
||||||
virtual ~base ();
|
virtual ~base ();
|
||||||
|
|
||||||
virtual void execute (void);
|
virtual void execute (void);
|
||||||
|
@ -40,9 +44,6 @@ namespace util { namespace cmdopt {
|
||||||
|
|
||||||
virtual const std::string& example (void) const = 0;
|
virtual const std::string& example (void) const = 0;
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
@ -50,18 +51,13 @@ namespace util { namespace cmdopt {
|
||||||
bool seen (bool);
|
bool seen (bool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_required;
|
bool m_required = false;
|
||||||
bool m_seen;
|
bool m_seen = false;
|
||||||
|
|
||||||
std::string m_name;
|
|
||||||
std::string m_description;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class null : public base {
|
class null : public base {
|
||||||
public:
|
public:
|
||||||
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;
|
||||||
|
|
||||||
|
@ -71,7 +67,7 @@ namespace util { namespace cmdopt {
|
||||||
|
|
||||||
class present : public base {
|
class present : public base {
|
||||||
public:
|
public:
|
||||||
present (std::string name, std::string description, bool&);
|
explicit present (bool&);
|
||||||
|
|
||||||
using base::execute;
|
using base::execute;
|
||||||
virtual void execute (void) override;
|
virtual void execute (void) override;
|
||||||
|
@ -88,7 +84,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, std::string description, T&);
|
explicit value (T&);
|
||||||
|
|
||||||
using base::execute;
|
using base::execute;
|
||||||
void execute (const char *restrict) override;
|
void execute (const char *restrict) override;
|
||||||
|
@ -107,7 +103,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, std::string description, T&);
|
explicit count (T&);
|
||||||
|
|
||||||
using value<T>::execute;
|
using value<T>::execute;
|
||||||
void execute (void) override;
|
void execute (void) override;
|
||||||
|
@ -124,22 +120,6 @@ namespace util { namespace cmdopt {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class error : public std::runtime_error
|
|
||||||
{ using runtime_error::runtime_error; };
|
|
||||||
|
|
||||||
class invalid_key : public error
|
|
||||||
{ using error::error; };
|
|
||||||
|
|
||||||
class invalid_value : public error
|
|
||||||
{ using error::error; };
|
|
||||||
|
|
||||||
class invalid_null : public error
|
|
||||||
{ using error::error; };
|
|
||||||
|
|
||||||
class invalid_required : public error
|
|
||||||
{ using error::error; };
|
|
||||||
|
|
||||||
|
|
||||||
class parser {
|
class parser {
|
||||||
public:
|
public:
|
||||||
template <typename T, typename ...Args>
|
template <typename T, typename ...Args>
|
||||||
|
@ -148,6 +128,10 @@ namespace util { namespace cmdopt {
|
||||||
std::string description,
|
std::string description,
|
||||||
Args&&...);
|
Args&&...);
|
||||||
|
|
||||||
|
template <typename T, typename ...Args>
|
||||||
|
T&
|
||||||
|
append (std::string description, Args&&...);
|
||||||
|
|
||||||
int scan (int argc, const char *const *argv);
|
int scan (int argc, const char *const *argv);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -161,14 +145,57 @@ 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::reference_wrapper<option::base>> m_positional;
|
||||||
|
|
||||||
std::vector<
|
std::vector<
|
||||||
std::tuple<
|
std::tuple<
|
||||||
char,
|
std::string, // description
|
||||||
std::string,
|
std::unique_ptr<option::base>
|
||||||
std::unique_ptr<option::base>>
|
>
|
||||||
> m_options;
|
> m_options;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class error : public std::exception { };
|
||||||
|
|
||||||
|
class invalid_key : public error {
|
||||||
|
public:
|
||||||
|
invalid_key (std::string _key);
|
||||||
|
virtual const char* what (void) const noexcept override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string m_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
class invalid_value : public error {
|
||||||
|
public:
|
||||||
|
invalid_value (std::string _value);
|
||||||
|
virtual const char* what (void) const noexcept override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class invalid_null : public error {
|
||||||
|
public:
|
||||||
|
virtual const char* what (void) const noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class invalid_required : public error {
|
||||||
|
public:
|
||||||
|
virtual const char* what (void) const noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class unhandled_argument : public error {
|
||||||
|
public:
|
||||||
|
unhandled_argument (int index);
|
||||||
|
virtual const char* what (void) const noexcept override;
|
||||||
|
|
||||||
|
int index (void) const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int m_index;
|
||||||
|
};
|
||||||
} }
|
} }
|
||||||
|
|
||||||
#include "cmdopt.ipp"
|
#include "cmdopt.ipp"
|
||||||
|
|
25
cmdopt.ipp
25
cmdopt.ipp
|
@ -11,7 +11,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
*
|
||||||
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2013-2016 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __UTIL_CMDLINE_IPP
|
#ifdef __UTIL_CMDLINE_IPP
|
||||||
|
@ -27,8 +27,7 @@
|
||||||
namespace util { namespace cmdopt {
|
namespace util { namespace cmdopt {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
template <typename T>
|
template <typename T>
|
||||||
option::value<T>::value (std::string _name, std::string _description, T &_data):
|
option::value<T>::value (T &_data):
|
||||||
base (std::move (_name), std::move (_description)),
|
|
||||||
m_data (_data)
|
m_data (_data)
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
|
@ -130,14 +129,28 @@ namespace util { namespace cmdopt {
|
||||||
std::string description,
|
std::string description,
|
||||||
Args&&... args)
|
Args&&... args)
|
||||||
{
|
{
|
||||||
auto handler = std::make_unique<T> (longname, description, std::forward<Args> (args)...);
|
auto handler = std::make_unique<T> (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 (std::move (longname), ref);
|
||||||
|
|
||||||
m_options.emplace_back (shortname, longname, std::move (handler));
|
m_options.emplace_back (std::move (description), std::move (handler));
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
template <typename T, typename ...Args>
|
||||||
|
T&
|
||||||
|
parser::append (std::string description,
|
||||||
|
Args &&...args)
|
||||||
|
{
|
||||||
|
auto handler = std::make_unique<T> (std::forward<Args> (args)...);
|
||||||
|
auto &ref = *handler;
|
||||||
|
m_positional.push_back (ref);
|
||||||
|
m_options.emplace_back (std::move (description), std::move (handler));
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
} }
|
} }
|
||||||
|
|
|
@ -6,13 +6,14 @@
|
||||||
#include "maths.hpp"
|
#include "maths.hpp"
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Check that null options don't strhrow anything
|
// Check that null options don't strhrow anything
|
||||||
|
static
|
||||||
void
|
void
|
||||||
test_null (util::TAP::logger &tap)
|
test_null (util::TAP::logger &tap)
|
||||||
{
|
{
|
||||||
util::cmdopt::parser p;
|
util::cmdopt::parser p;
|
||||||
auto n = p.add<util::cmdopt::option::null> ('n', "null", "testing null option");
|
p.add<util::cmdopt::option::null> ('n', "null", "testing null option");
|
||||||
|
|
||||||
static const char *argv1[] = { "./foo", "-n", "foo" };
|
static const char *argv1[] = { "./foo", "-n", "foo" };
|
||||||
tap.expect_nothrow ([&] () {
|
tap.expect_nothrow ([&] () {
|
||||||
|
@ -26,8 +27,9 @@ test_null (util::TAP::logger &tap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Check if presence options can be used successfully
|
// Check if presence options can be used successfully
|
||||||
|
static
|
||||||
void
|
void
|
||||||
test_present (util::TAP::logger &tap)
|
test_present (util::TAP::logger &tap)
|
||||||
{
|
{
|
||||||
|
@ -62,8 +64,9 @@ test_present (util::TAP::logger &tap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Check all forms of boolean inputs
|
// Check all forms of boolean inputs
|
||||||
|
static
|
||||||
void
|
void
|
||||||
test_bool (util::TAP::logger &tap)
|
test_bool (util::TAP::logger &tap)
|
||||||
{
|
{
|
||||||
|
@ -102,8 +105,9 @@ test_bool (util::TAP::logger &tap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
static
|
||||||
void
|
void
|
||||||
test_numeric (util::TAP::logger &tap)
|
test_numeric (util::TAP::logger &tap)
|
||||||
{
|
{
|
||||||
|
@ -152,7 +156,8 @@ test_numeric (util::TAP::logger &tap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
static
|
||||||
void
|
void
|
||||||
test_bytes (util::TAP::logger &tap)
|
test_bytes (util::TAP::logger &tap)
|
||||||
{
|
{
|
||||||
|
@ -186,7 +191,8 @@ test_bytes (util::TAP::logger &tap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
static
|
||||||
void
|
void
|
||||||
test_required (util::TAP::logger &tap)
|
test_required (util::TAP::logger &tap)
|
||||||
{
|
{
|
||||||
|
@ -213,7 +219,32 @@ test_required (util::TAP::logger &tap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_positional (util::TAP::logger &tap)
|
||||||
|
{
|
||||||
|
unsigned value = 0xdead;
|
||||||
|
constexpr unsigned expected = 0xbeef;
|
||||||
|
|
||||||
|
util::cmdopt::parser p;
|
||||||
|
p.append<util::cmdopt::option::value<unsigned>> ("unsigned test", value);
|
||||||
|
|
||||||
|
static const char *argv[] = {
|
||||||
|
"./cpptest",
|
||||||
|
"--",
|
||||||
|
"48879",
|
||||||
|
};
|
||||||
|
|
||||||
|
tap.expect_nothrow ([&] {
|
||||||
|
p.scan (elems (argv), argv);
|
||||||
|
}, "positional, nothrow");
|
||||||
|
|
||||||
|
tap.expect_eq (value, expected, "positiona, value success");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
int
|
int
|
||||||
main (int, char **) {
|
main (int, char **) {
|
||||||
util::TAP::logger tap;
|
util::TAP::logger tap;
|
||||||
|
@ -229,6 +260,7 @@ main (int, char **) {
|
||||||
test_numeric<uint64_t> (tap);
|
test_numeric<uint64_t> (tap);
|
||||||
test_bytes (tap);
|
test_bytes (tap);
|
||||||
test_required (tap);
|
test_required (tap);
|
||||||
|
test_positional (tap);
|
||||||
|
|
||||||
return tap.status ();
|
return tap.status ();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user