21 enum struct custom_policy {FALSE, TRUE, MODIFIABLE};
28 const std::string& l_name;
29 const std::string& s_name;
30 const std::string& def =
"false";
31 const std::string& mod =
"";
32 const shared::vector valid = {};
33 const bool& must_set =
false;
34 const bool& flag_set =
false;
35 const custom_policy& custom = custom_policy::FALSE;
36 const bool& list =
false;
37 const uint_fast8_t& position = -1;
38 const std::string& help;
39 const bool& updates_sof =
false;
50 std::string long_name, short_name;
53 std::string value, def, modifier;
59 bool list =
false, update_sof =
false;
63 shared::set valid = {}, list_val = {};
64 shared::vector order = {};
70 bool mandatory =
false, set =
false, flag =
false;
73 custom_policy custom = custom_policy::FALSE;
76 uint_fast8_t positional = -1;
79 std::function<std::string(
const std::string_view&)> parser, m_parser;
89 bool digest_keypair(
const std::string_view& key,
const std::string_view& val,
const uint_fast8_t& pos) {
91 if (!list && custom == custom_policy::MODIFIABLE && val.contains(
':')) {
94 auto s = container::init<shared::vector>(container::split<shared::vector, char>, val,
':',
false);
95 if (s.size() < 2)
throw std::runtime_error(
"Invalid modifier: " + std::string(val));
98 auto v = s[0];
auto mod = val.substr(val.find(
':') + 1);
101 if (valid.size() <= 1 || valid.contains(v)) {
103 modifier = m_parser(
mod);
109 else if (key == long_name || key == short_name) {
110 if (long_name ==
"--help")
throw std::runtime_error(
"Help!");
121 else if (valid.size() <= 1 || custom == custom_policy::TRUE || std::find(valid.begin(), valid.end(), val) != valid.end()) {
125 if (val.contains(
',')) {
126 for (
const auto& x : container::init<shared::vector>(container::split<shared::vector, char>, val,
',',
false))
127 digest_keypair(key, x, pos);
131 else list_val.emplace(parser(val));
133 else value = parser(val);
138 else if (flag && val ==
"true")
return true;
155 if (i + 1 < valid.size())
156 value = order[i + 1];
158 std::cerr << long_name <<
": Already at highest level!" << std::endl;
166 uint_fast8_t
level(
const std::string_view& val)
const {
return std::find(order.begin(), order.end(), val) - order.begin();}
180 const std::function<std::string(
const std::string_view&)>& handler = [](
const std::string_view& value){
return std::string(value);},
181 const std::function<std::string(
const std::string_view&)>& m_handler = [](
const std::string_view& value){
return std::string(value);}
184 long_name = c.l_name;
185 short_name = c.s_name;
188 m_parser = m_handler;
189 update_sof = c.updates_sof;
193 if (!c.mod.empty()) modifier = m_parser(c.mod);
194 value = parser(c.def);
200 valid = {c.def}; order = {c.def};
201 for (
const auto& v : c.valid) {
202 if (v != c.def) {valid.emplace(v); order.emplace_back(v);}
204 mandatory = c.must_set;
207 positional = c.position;
217 bool digest(
const shared::vector& args, uint_fast8_t& x) {
220 const auto& key = args[x];
223 if (key ==
"--help")
throw std::runtime_error(
"Help!");
224 if (key ==
"--version")
throw std::runtime_error(
"Version");
231 if (key ==
"--")
return true;
234 if (key.contains(
"=")) {
235 auto keypair = container::init<shared::vector>(container::split<shared::vector, char>, key,
'=',
false);
236 ret = digest_keypair(keypair[0], keypair[1], x);
241 else if (key[0] ==
'-' && key[1] !=
'-' && key.length() > 2) {
242 for (uint_fast8_t x = 1; x < key.length(); ++x) {
243 if (key[x] == short_name[1]) {
252 else if (!key.empty() && (key == long_name || key == short_name)) {
253 if (x + 1 != args.size() && !args[x].empty() && args[x + 1][0] !=
'-') {
255 while (++x < args.size() && !args[x].empty() && args[x][0] !=
'-')
256 digest_keypair(key, args[x], x);
260 else ret = digest_keypair(key, args[++x], x);
263 else if (list)
throw std::runtime_error(
"List argument requires values: " + long_name);
266 else if (flag) ret =
true;
269 else if (valid.size() > 1) {
276 else if (positional == x) {
277 if (key.starts_with(
"-"))
278 throw std::runtime_error(
"Invalid argument passed to: " + long_name);
286 if (x == positional && !ret)
287 throw std::runtime_error(
"Positional argument not set: " + long_name);
297 if (mandatory && !set)
throw std::runtime_error(
"Missing mandatory argument: " + long_name);
298 value = parser(value); modifier = m_parser(modifier);
307 std::stringstream help_text;
308 help_text << long_name;
309 if (!short_name.empty()) help_text <<
'/' << short_name;
313 help_text <<
'[' <<
"VAL";
314 if (custom == custom_policy::MODIFIABLE) help_text <<
":MOD";
317 if (order.size() > 1) help_text <<
'{';
318 if (order.size() > 1) {
319 for (
const auto& v : order) {
321 if (custom == custom_policy::MODIFIABLE) help_text <<
":MOD";
322 if (v != *std::prev(order.end())) help_text <<
',';
326 if (list) help_text <<
"...]";
328 help_text <<
"\n\t" << help <<
'\n';
329 return help_text.str();
338 auto&&
get(
this auto&& self) {
339 if (self.list)
throw std::runtime_error(
"Not a discrete value: " + self.long_name);
353 void emplace(
const std::string& val) {set |= digest_keypair(long_name, val, -1);}
360 auto&&
mod(
this auto&& self) {
return self.modifier;}
390 if (!self.list && !self.flag)
throw std::runtime_error(
"Argument must be a list: " + self.long_name);
391 return self.list_val;
405 std::vector<std::pair<std::string, std::string>>
get_modlist()
const {
406 if (!list)
throw std::runtime_error(
"Argument is not a list: " + long_name);
407 if (custom != custom_policy::MODIFIABLE)
throw std::runtime_error(
"List must allowed modifiers!");
409 std::vector<std::pair<std::string, std::string>> ret;
410 for (
const auto& val : list_val) {
411 if (val.contains(
':')) {
412 auto s = container::init<shared::vector>(container::split<shared::vector, char>, val,
':',
false);
413 ret.emplace_back(std::pair{s[0], s[1]});
415 else ret.emplace_back(std::pair{val,
""});
420 const bool& updates_sof()
const {
return update_sof;}
427 const uint_fast8_t&
position()
const {
return positional;}
433 operator bool()
const {
return level() != 0 || (flag && set) || (list && !list_val.empty());}
453 extern std::map<std::string, arg::Arg> switches;
456 extern shared::vector unknown;
459 extern shared::vector args;
461 extern std::string hash;
465 inline Arg& at(
const std::string& key) {
466 if (!switches.contains(key))
throw std::runtime_error(
"Invalid argument" + key);
467 else return switches.at(key);
469 inline const std::string& get(
const std::string& key) {
return at(key).get();}
470 inline void emplace(
const std::string& key,
const std::string& val) {at(key).emplace(val);}
471 inline const std::string& mod(
const std::string& key) {
return at(key).mod();}
472 inline uint_fast8_t level(
const std::string& key) {
return at(key).level();}
473 inline const shared::set& list(
const std::string& key) {
return at(key).get_list();}
474 inline const shared::set& valid(
const std::string& key) {
return at(key).get_valid();}
475 inline const bool& is_list(
const std::string& key) {
return at(key).is_list();}
476 inline std::vector<std::pair<std::string, std::string>> modlist(
const std::string& key) {
return at(key).get_modlist();}
void update()
Update configurations.
Definition arguments.hpp:296
std::string get_help() const
Get the help text for the argument.
Definition arguments.hpp:306
uint_fast8_t level() const
Return the current level of the argument.
Definition arguments.hpp:381
std::vector< std::pair< std::string, std::string > > get_modlist() const
Return all values paired with their modifiers.
Definition arguments.hpp:405
Arg(const config &c, const std::function< std::string(const std::string_view &)> &handler=[](const std::string_view &value){return std::string(value);}, const std::function< std::string(const std::string_view &)> &m_handler=[](const std::string_view &value){return std::string(value);})
Construct an argument.
Definition arguments.hpp:178
const bool & is_list() const
Return whether the argument is a list.
Definition arguments.hpp:367
auto && mod(this auto &&self)
Get a mutable reference to the stored modifier.
Definition arguments.hpp:360
void emplace(const std::string &val)
Emplace a value.
Definition arguments.hpp:353
auto && get_list(this auto &&self)
Return a mutable reference to each unique value passed to the argument.
Definition arguments.hpp:389
const bool operator<(const std::string_view &val) const
Check if the current value is underneath the provided.
Definition arguments.hpp:440
auto && get(this auto &&self)
Get a mutable reference to the stored value.
Definition arguments.hpp:338
auto && get_valid(this auto &&self)
Return a set of all valid values.
Definition arguments.hpp:398
const uint_fast8_t & position() const
Return the position of the argument.
Definition arguments.hpp:427
const bool operator>=(const std::string_view &val) const
Check if the current value meets the provided.
Definition arguments.hpp:448
const bool & is_flagset() const
Return whether the argument is a flagset.
Definition arguments.hpp:374
bool digest(const shared::vector &args, uint_fast8_t &x)
Digest arguments.
Definition arguments.hpp:217
A general purpose, flexible command-line argument handler. This file includes definitions to create a...
Definition arguments.cpp:11
void parse_args()
Parse command line arguments.
Definition arguments.cpp:286
struct arg::config config
Definition arguments.hpp:27