cmdopt: add positional argument support
This commit is contained in:
parent
8ea827aab0
commit
f13c4487c6
206
cmdopt.cpp
206
cmdopt.cpp
@ -11,7 +11,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
||||
* Copyright 2013-2016 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#include "cmdopt.hpp"
|
||||
@ -23,25 +23,11 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
using util::cmdopt::option::base;
|
||||
using util::cmdopt::option::bytes;
|
||||
using util::cmdopt::option::count;
|
||||
using util::cmdopt::option::null;
|
||||
using util::cmdopt::option::present;
|
||||
using util::cmdopt::option::value;
|
||||
using util::cmdopt::parser;
|
||||
using namespace util::cmdopt;
|
||||
using namespace util::cmdopt::option;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
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 ()
|
||||
{ ; }
|
||||
|
||||
@ -50,15 +36,15 @@ base::~base ()
|
||||
void
|
||||
base::execute (void)
|
||||
{
|
||||
throw invalid_null (m_name);
|
||||
throw invalid_null ();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
if (m_required && !m_seen)
|
||||
throw invalid_required (m_name);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const std::string&
|
||||
base::name (void) const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const std::string&
|
||||
base::description (void) const
|
||||
{
|
||||
return m_description;
|
||||
throw invalid_required ();
|
||||
}
|
||||
|
||||
|
||||
@ -128,12 +98,6 @@ base::seen (bool _seen)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
null::null (std::string _name, std::string _description):
|
||||
base (std::move (_name), std::move (_description))
|
||||
{ ; }
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
null::execute (void)
|
||||
{
|
||||
@ -159,8 +123,7 @@ null::example (void) const
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
present::present (std::string _name, std::string _description, bool &_data):
|
||||
base (std::move (_name), std::move (_description)),
|
||||
present::present (bool &_data):
|
||||
m_data (_data)
|
||||
{ ; }
|
||||
|
||||
@ -243,8 +206,8 @@ namespace util { namespace cmdopt { namespace option {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
count<T>::count (std::string _name, std::string _description, T &_data):
|
||||
value<T> (std::move (_name), std::move (_description), _data)
|
||||
count<T>::count (T &_data):
|
||||
value<T> (_data)
|
||||
{ ; }
|
||||
|
||||
|
||||
@ -294,7 +257,8 @@ suffix_to_multiplier (char c)
|
||||
return util::pow (1024UL, 1);
|
||||
|
||||
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);
|
||||
|
||||
if (tail == str) {
|
||||
throw invalid_value (name ());
|
||||
throw invalid_value (str);
|
||||
} else if (tail == last) {
|
||||
data (val);
|
||||
} else if (tail + 1 == last) {
|
||||
try {
|
||||
data (val * suffix_to_multiplier (*tail));
|
||||
} catch (const std::invalid_argument&)
|
||||
{ throw invalid_value (str); }
|
||||
} else
|
||||
throw invalid_value (name ());
|
||||
throw invalid_value (str);
|
||||
}
|
||||
|
||||
|
||||
@ -328,7 +295,7 @@ parser::scan (int argc, const char *const *argv)
|
||||
CHECK (argv);
|
||||
|
||||
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
|
||||
int i = 1;
|
||||
@ -337,7 +304,13 @@ parser::scan (int argc, const char *const *argv)
|
||||
|
||||
// bail if there's no potential for an option
|
||||
if (len < 2 || argv[i][0] != '-')
|
||||
return i;
|
||||
break;
|
||||
|
||||
// stop processing named options on '--'
|
||||
if (len == 2 && argv[i][1] == '-') {
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
|
||||
// parse longopt
|
||||
auto inc = argv[i][1] == '-'
|
||||
@ -348,8 +321,17 @@ parser::scan (int argc, const char *const *argv)
|
||||
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)
|
||||
std::get<2> (j)->finish ();
|
||||
std::get<std::unique_ptr<option::base>> (j)->finish ();
|
||||
|
||||
return i;
|
||||
}
|
||||
@ -379,11 +361,11 @@ parser::parse_long (int pos, int argc, const char *const *argv)
|
||||
// find the handler
|
||||
auto handle_pos = std::find_if (m_long.begin (),
|
||||
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 ())
|
||||
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
|
||||
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 (),
|
||||
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 ())
|
||||
throw invalid_key (std::to_string (letter));
|
||||
std::get<1> (*hpos).execute ();
|
||||
std::get<option::base&> (*hpos).execute ();
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -438,10 +420,10 @@ parser::parse_short (int pos, int argc, const char *const *argv)
|
||||
auto letter = argv[pos][1];
|
||||
auto hpos = std::find_if (m_short.begin (),
|
||||
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 ())
|
||||
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;
|
||||
}
|
||||
@ -492,13 +474,109 @@ parser::print_help (const int argc,
|
||||
std::cout << "usage: " << argv[0] << '\n';
|
||||
|
||||
for (auto &o: m_options) {
|
||||
std::cout << '\t'
|
||||
<< '-' << std::get<char> (o) << '\t'
|
||||
<< std::setw (longwidth) << std::get<std::string> (o) << '\t'
|
||||
<< std::setw (longexample) << std::get<std::unique_ptr<option::base>> (o)->example () << '\t'
|
||||
<< std::setw (0) << std::get<2> (o)->description ()
|
||||
auto ptr = std::get<std::unique_ptr<option::base>> (o).get ();
|
||||
|
||||
auto s = std::find_if (
|
||||
std::cbegin (m_short),
|
||||
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';
|
||||
}
|
||||
|
||||
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
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
||||
* Copyright 2013-2016 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __UTIL_CMDLINE_HPP
|
||||
#define __UTIL_CMDLINE_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace util { namespace cmdopt {
|
||||
namespace option {
|
||||
class base {
|
||||
protected:
|
||||
base (std::string name, std::string description);
|
||||
|
||||
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 void execute (void);
|
||||
@ -40,9 +44,6 @@ namespace util { namespace cmdopt {
|
||||
|
||||
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 (bool);
|
||||
|
||||
@ -50,18 +51,13 @@ namespace util { namespace cmdopt {
|
||||
bool seen (bool);
|
||||
|
||||
private:
|
||||
bool m_required;
|
||||
bool m_seen;
|
||||
|
||||
std::string m_name;
|
||||
std::string m_description;
|
||||
bool m_required = false;
|
||||
bool m_seen = false;
|
||||
};
|
||||
|
||||
|
||||
class null : public base {
|
||||
public:
|
||||
explicit null (std::string name, std::string description);
|
||||
|
||||
virtual void execute (void) override;
|
||||
virtual void execute (const char *restrict) override;
|
||||
|
||||
@ -71,7 +67,7 @@ namespace util { namespace cmdopt {
|
||||
|
||||
class present : public base {
|
||||
public:
|
||||
present (std::string name, std::string description, bool&);
|
||||
explicit present (bool&);
|
||||
|
||||
using base::execute;
|
||||
virtual void execute (void) override;
|
||||
@ -88,7 +84,7 @@ namespace util { namespace cmdopt {
|
||||
template <typename T>
|
||||
class value : public base {
|
||||
public:
|
||||
value (std::string name, std::string description, T&);
|
||||
explicit value (T&);
|
||||
|
||||
using base::execute;
|
||||
void execute (const char *restrict) override;
|
||||
@ -107,7 +103,7 @@ namespace util { namespace cmdopt {
|
||||
template <typename T = unsigned>
|
||||
class count : public value<T> {
|
||||
public:
|
||||
count (std::string name, std::string description, T&);
|
||||
explicit count (T&);
|
||||
|
||||
using value<T>::execute;
|
||||
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 {
|
||||
public:
|
||||
template <typename T, typename ...Args>
|
||||
@ -148,6 +128,10 @@ namespace util { namespace cmdopt {
|
||||
std::string description,
|
||||
Args&&...);
|
||||
|
||||
template <typename T, typename ...Args>
|
||||
T&
|
||||
append (std::string description, Args&&...);
|
||||
|
||||
int scan (int argc, const char *const *argv);
|
||||
|
||||
private:
|
||||
@ -161,14 +145,57 @@ namespace util { namespace cmdopt {
|
||||
|
||||
std::vector<short_t> m_short;
|
||||
std::vector<long_t> m_long;
|
||||
std::vector<std::reference_wrapper<option::base>> m_positional;
|
||||
|
||||
std::vector<
|
||||
std::tuple<
|
||||
char,
|
||||
std::string,
|
||||
std::unique_ptr<option::base>>
|
||||
std::string, // description
|
||||
std::unique_ptr<option::base>
|
||||
>
|
||||
> 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"
|
||||
|
25
cmdopt.ipp
25
cmdopt.ipp
@ -11,7 +11,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
||||
* Copyright 2013-2016 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifdef __UTIL_CMDLINE_IPP
|
||||
@ -27,8 +27,7 @@
|
||||
namespace util { namespace cmdopt {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
option::value<T>::value (std::string _name, std::string _description, T &_data):
|
||||
base (std::move (_name), std::move (_description)),
|
||||
option::value<T>::value (T &_data):
|
||||
m_data (_data)
|
||||
{ ; }
|
||||
|
||||
@ -130,14 +129,28 @@ namespace util { namespace cmdopt {
|
||||
std::string description,
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
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"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Check that null options don't strhrow anything
|
||||
static
|
||||
void
|
||||
test_null (util::TAP::logger &tap)
|
||||
{
|
||||
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" };
|
||||
tap.expect_nothrow ([&] () {
|
||||
@ -26,8 +27,9 @@ test_null (util::TAP::logger &tap)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Check if presence options can be used successfully
|
||||
static
|
||||
void
|
||||
test_present (util::TAP::logger &tap)
|
||||
{
|
||||
@ -62,8 +64,9 @@ test_present (util::TAP::logger &tap)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Check all forms of boolean inputs
|
||||
static
|
||||
void
|
||||
test_bool (util::TAP::logger &tap)
|
||||
{
|
||||
@ -102,8 +105,9 @@ test_bool (util::TAP::logger &tap)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template<typename T>
|
||||
static
|
||||
void
|
||||
test_numeric (util::TAP::logger &tap)
|
||||
{
|
||||
@ -152,7 +156,8 @@ test_numeric (util::TAP::logger &tap)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static
|
||||
void
|
||||
test_bytes (util::TAP::logger &tap)
|
||||
{
|
||||
@ -186,7 +191,8 @@ test_bytes (util::TAP::logger &tap)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static
|
||||
void
|
||||
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
|
||||
main (int, char **) {
|
||||
util::TAP::logger tap;
|
||||
@ -229,6 +260,7 @@ main (int, char **) {
|
||||
test_numeric<uint64_t> (tap);
|
||||
test_bytes (tap);
|
||||
test_required (tap);
|
||||
test_positional (tap);
|
||||
|
||||
return tap.status ();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user