cmdopt: use concrete structs for data holders
Tuples are quite verbose and don't document intention.
This commit is contained in:
parent
395b5ae557
commit
6f45f9514d
76
cmdopt.cpp
76
cmdopt.cpp
@ -247,31 +247,32 @@ bytes::execute (const char *restrict str)
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
int
|
int
|
||||||
parser::scan (int argc, const char *const *argv)
|
parser::scan (int argc, char const *const *argv)
|
||||||
{
|
{
|
||||||
CHECK_GE (argc, 0);
|
CHECK_GT (argc, 0);
|
||||||
CHECK (argv);
|
CHECK (argv);
|
||||||
|
|
||||||
for (auto &j: m_options)
|
for (auto &j: m_options)
|
||||||
std::get<std::unique_ptr<option::base>> (j)->start ();
|
j.handler->start ();
|
||||||
|
|
||||||
// start iterating after our program's name
|
// start iterating after our program's name
|
||||||
int i = 1;
|
int i = 1;
|
||||||
while (i < argc) {
|
while (i < argc) {
|
||||||
auto len = strlen (argv[i]);
|
auto arg = argv[i];
|
||||||
|
auto len = strlen (arg);
|
||||||
|
|
||||||
// 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 || arg[0] != '-')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// stop processing named options on '--'
|
// stop processing named options on '--'
|
||||||
if (len == 2 && argv[i][1] == '-') {
|
if (len == 2 && arg[1] == '-') {
|
||||||
++i;
|
++i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse longopt
|
// parse longopt
|
||||||
auto inc = argv[i][1] == '-'
|
auto inc = arg[1] == '-'
|
||||||
? parse_long (i, argc, argv)
|
? parse_long (i, argc, argv)
|
||||||
: parse_short (i, argc, argv);
|
: parse_short (i, argc, argv);
|
||||||
|
|
||||||
@ -289,7 +290,7 @@ parser::scan (int argc, const char *const *argv)
|
|||||||
|
|
||||||
// allow arguments to check if they've been successfully handled
|
// allow arguments to check if they've been successfully handled
|
||||||
for (auto &j: m_options)
|
for (auto &j: m_options)
|
||||||
std::get<std::unique_ptr<option::base>> (j)->finish ();
|
j.handler->finish ();
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -316,14 +317,7 @@ parser::parse_long (int pos, int argc, const char *const *argv)
|
|||||||
if (key == "help")
|
if (key == "help")
|
||||||
print_help (argc, argv);
|
print_help (argc, argv);
|
||||||
|
|
||||||
// find the handler
|
auto &handler = m_long.at (key).get ();
|
||||||
auto handle_pos = std::find_if (m_long.begin (),
|
|
||||||
m_long.end (),
|
|
||||||
[&] (auto i) { return std::get<std::string> (i) == key; });
|
|
||||||
if (handle_pos == m_long.end ())
|
|
||||||
throw invalid_key (key);
|
|
||||||
|
|
||||||
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) {
|
||||||
@ -363,12 +357,7 @@ parser::parse_short (int pos, int argc, const char *const *argv)
|
|||||||
if (letter == 'h')
|
if (letter == 'h')
|
||||||
print_help (argc, argv);
|
print_help (argc, argv);
|
||||||
|
|
||||||
auto hpos = std::find_if (m_short.begin (),
|
m_short.at(letter).get ().execute ();
|
||||||
m_short.end (),
|
|
||||||
[letter] (auto j) { return std::get<char> (j) == letter; });
|
|
||||||
if (hpos == m_short.end ())
|
|
||||||
throw invalid_key (std::string (1, letter));
|
|
||||||
std::get<option::base&> (*hpos).execute ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -376,13 +365,7 @@ parser::parse_short (int pos, int argc, const char *const *argv)
|
|||||||
|
|
||||||
// we have a value following
|
// we have a value following
|
||||||
auto letter = argv[pos][1];
|
auto letter = argv[pos][1];
|
||||||
auto hpos = std::find_if (m_short.begin (),
|
m_short.at (letter).get ().execute (argv[pos + 1]);
|
||||||
m_short.end (),
|
|
||||||
[letter] (auto i) { return std::get<char> (i) == letter; });
|
|
||||||
if (hpos == m_short.end ())
|
|
||||||
throw invalid_key (std::string (1, letter));
|
|
||||||
std::get<option::base&> (*hpos).execute (argv[pos+1]);
|
|
||||||
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,9 +389,13 @@ parser::print_help (const int argc,
|
|||||||
m_long.end (),
|
m_long.end (),
|
||||||
[] (const auto &a, const auto &b)
|
[] (const auto &a, const auto &b)
|
||||||
{
|
{
|
||||||
return std::get<std::string> (a).size () < std::get<std::string> (b).size ();
|
auto const &[a_key,a_obj] = a;
|
||||||
|
auto const &[b_key,b_obj] = b;
|
||||||
|
|
||||||
|
return a_key.size () < b_key.size ();
|
||||||
});
|
});
|
||||||
auto longwidth = std::get<std::string> (*largestwidth).size ();
|
|
||||||
|
auto longwidth = largestwidth->first.size ();
|
||||||
|
|
||||||
// find the longest example text
|
// find the longest example text
|
||||||
auto largestexample = std::max_element (
|
auto largestexample = std::max_element (
|
||||||
@ -416,13 +403,10 @@ parser::print_help (const int argc,
|
|||||||
m_options.cend (),
|
m_options.cend (),
|
||||||
[] (const auto &a, const auto &b)
|
[] (const auto &a, const auto &b)
|
||||||
{
|
{
|
||||||
const auto &example_a = std::get<std::unique_ptr<option::base>> (a)->example ();
|
return a.handler->example ().size () > b.handler->example ().size ();
|
||||||
const auto &example_b = std::get<std::unique_ptr<option::base>> (b)->example ();
|
|
||||||
|
|
||||||
return example_a.size () > example_b.size ();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
auto longexample = std::get<std::unique_ptr<option::base>> (*largestexample)->example ().size ();
|
auto longexample = largestexample->handler->example ().size ();
|
||||||
|
|
||||||
// field width requires an alignment. we don't care about preserving
|
// field width requires an alignment. we don't care about preserving
|
||||||
// state as we're about to bail anyway
|
// state as we're about to bail anyway
|
||||||
@ -431,39 +415,33 @@ parser::print_help (const int argc,
|
|||||||
// print all the option info
|
// print all the option info
|
||||||
std::cout << "usage: " << argv[0] << '\n';
|
std::cout << "usage: " << argv[0] << '\n';
|
||||||
|
|
||||||
for (auto &o: m_options) {
|
for (auto &opt: m_options) {
|
||||||
auto ptr = std::get<std::unique_ptr<option::base>> (o).get ();
|
|
||||||
|
|
||||||
auto s = std::find_if (
|
auto s = std::find_if (
|
||||||
std::cbegin (m_short),
|
std::cbegin (m_short),
|
||||||
std::cend (m_short),
|
std::cend (m_short),
|
||||||
[ptr] (auto j) {
|
[&] (auto j) { return &j.second.get () == opt.handler.get (); }
|
||||||
return &std::get<option::base&> (j) == ptr;
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
auto l = std::find_if (
|
auto l = std::find_if (
|
||||||
std::cbegin (m_long),
|
std::cbegin (m_long),
|
||||||
std::cend (m_long),
|
std::cend (m_long),
|
||||||
[ptr] (auto j) {
|
[&] (auto j) { return &j.second.get () == opt.handler.get (); }
|
||||||
return &std::get<option::base&> (j) == ptr;
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
std::cout << '\t';
|
std::cout << '\t';
|
||||||
if (s != std::cend (m_short))
|
if (s != std::cend (m_short))
|
||||||
std::cout << '-' << std::get<char> (*s) << '\t';
|
std::cout << '-' << s->first << '\t';
|
||||||
else
|
else
|
||||||
std::cout << '\t';
|
std::cout << '\t';
|
||||||
|
|
||||||
std::cout << std::setw (util::cast::lossless<int> (longwidth));
|
std::cout << std::setw (util::cast::lossless<int> (longwidth));
|
||||||
if (l != std::cend (m_long))
|
if (l != std::cend (m_long))
|
||||||
std::cout << std::get<std::string> (*l) << '\t';
|
std::cout << l->first << '\t';
|
||||||
else
|
else
|
||||||
std::cout << ' ' << '\t';
|
std::cout << ' ' << '\t';
|
||||||
|
|
||||||
std::cout << std::setw (util::cast::lossless<int> (longexample)) << ptr->example () << '\t'
|
std::cout << std::setw (util::cast::lossless<int> (longexample)) << opt.handler->example () << '\t'
|
||||||
<< std::setw (0) << std::get<std::string> (o)
|
<< std::setw (0) << opt.description
|
||||||
<< '\n';
|
<< '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
cmdopt.hpp
27
cmdopt.hpp
@ -27,6 +27,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
@ -290,10 +291,10 @@ namespace util::cmdopt {
|
|||||||
auto handler = std::make_unique<T> (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.insert({ shortname, ref });
|
||||||
m_long .emplace_back (std::move (longname), ref);
|
m_long.insert({ std::move (longname), ref });
|
||||||
|
|
||||||
m_options.emplace_back (std::move (description), std::move (handler));
|
m_options.push_back ({ std::move (description), std::move (handler) });
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
@ -305,7 +306,7 @@ namespace util::cmdopt {
|
|||||||
auto handler = std::make_unique<T> (std::forward<Args> (args)...);
|
auto handler = std::make_unique<T> (std::forward<Args> (args)...);
|
||||||
auto &ref = *handler;
|
auto &ref = *handler;
|
||||||
m_positional.push_back (ref);
|
m_positional.push_back (ref);
|
||||||
m_options.emplace_back (std::move (description), std::move (handler));
|
m_options.push_back ({ std::move (description), std::move (handler) });
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,19 +318,17 @@ namespace util::cmdopt {
|
|||||||
|
|
||||||
void print_help [[noreturn]] (int argc, const char *const *argv) const;
|
void print_help [[noreturn]] (int argc, const char *const *argv) const;
|
||||||
|
|
||||||
using short_t = std::tuple<char,option::base&>;
|
std::map<char,std::reference_wrapper<option::base>> m_short;
|
||||||
using long_t = std::tuple<std::string,option::base&>;
|
std::map<std::string,std::reference_wrapper<option::base>> m_long;
|
||||||
|
|
||||||
std::vector<short_t> m_short;
|
|
||||||
std::vector<long_t> m_long;
|
|
||||||
std::vector<std::reference_wrapper<option::base>> m_positional;
|
std::vector<std::reference_wrapper<option::base>> m_positional;
|
||||||
|
|
||||||
std::vector<
|
struct entry {
|
||||||
std::tuple<
|
std::string description;
|
||||||
std::string, // description
|
std::unique_ptr<option::base> handler;
|
||||||
std::unique_ptr<option::base>
|
};
|
||||||
>
|
|
||||||
> m_options;
|
std::vector<entry> m_options;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user