poaflocParser Of Arguments For Lines Of Commands |
git clone git://git.dimitrijedobrota.com/poafloc.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
commit | 0ccb06358841f2d7b833bce0e5a5dca850597f1c |
parent | a14d57316e69826f82d9eca3581f89c7b1edf35c |
author | Dimitrije Dobrota < mail@dimitrijedobrota.com > |
date | Fri, 23 May 2025 23:46:23 +0200 |
Streamline the parser code
M | example/example.cpp | | | ++++++ ------ |
M | include/poafloc/poafloc.hpp | | | +++++++++++++++++++++++++++++ ----------------------------------------------------- |
2 files changed, 63 insertions(+), 112 deletions(-)
diff --git a/ example/example.cpp b/ example/example.cpp
@@ -31,27 +31,27 @@
int main()
const auto program = parser<arguments> {
option {
"-v --value",
"v value",
&arguments::val,
},
option {
"-m --multiply",
"m multiply",
&arguments::mul,
},
option {
"-n --name",
"n name",
&arguments::name,
},
option {
"-p --priv",
"p priv",
&arguments::set_priv,
},
option {
"-f --flag1",
"f flag1",
&arguments::flag1,
},
option {
"-F --flag2",
"F flag2",
&arguments::flag2,
},
};
diff --git a/ include/poafloc/poafloc.hpp b/ include/poafloc/poafloc.hpp
@@ -271,21 +271,13 @@
class parser
std::string str;
while (std::getline(istr, str, ' ')) {
if (std::size(str) < 2 || str[0] != '-') {
continue;
}
if (str[1] != '-') {
if (std::size(str) != 2) {
continue;
}
const auto opt = str[1];
if (std::size(str) == 1) {
const auto& opt = str[0];
if (!m_opt_short.set(opt, std::size(m_options))) {
throw error<error_t::duplicate_option>(opt);
}
} else {
const auto opt = str.substr(2);
const auto& opt = str;
if (!m_opt_long.set(opt, std::size(m_options))) {
throw error<error_t::duplicate_option>(opt);
}
@@ -320,84 +312,77 @@
class parser
};
}
enum class short_res : std::uint8_t
enum class handle_res : std::uint8_t
{
flag,
rest,
next,
missing,
ok,
};
[[nodiscard]] short_res handle_short(
Record& record,
char opt,
std::string_view rest,
std::span<std::string_view> next
handle_res handle_long_opt(
Record& record, std::string_view arg, std::span<std::string_view> next
) const
{
const auto option = get_option(opt);
const auto equal = arg.find('=');
if (equal != std::string::npos) {
auto opt = arg.substr(0, equal - 1);
const auto value = arg.substr(equal + 1);
if (!option.argument()) {
option(record, "true");
return short_res::flag;
}
if (!rest.empty()) {
option(record, rest);
return short_res::rest;
}
const auto option = get_option(opt);
if (!next.empty()) {
option(record, *std::begin(next));
return short_res::next;
}
if (!option.argument()) {
throw error<error_t::superfluous_argument>(opt);
}
return short_res::missing;
}
if (!value.empty()) {
option(record, value);
return handle_res::ok;
}
enum class long_res : std::uint8_t
{
flag,
next,
missing,
};
throw error<error_t::missing_argument>(opt);
}
[[nodiscard]] long_res handle_long(
Record& record, std::string_view opt, std::span<std::string_view> next
) const
{
const auto option = get_option(opt);
const auto option = get_option(arg);
if (!option.argument()) {
option(record, "true");
return long_res::flag;
return handle_res::ok;
}
if (!next.empty()) {
option(record, *std::begin(next));
return long_res::next;
return handle_res::next;
}
return long_res::missing;
throw error<error_t::missing_argument>(arg);
}
void handle_long_equal(
Record& record, std::string_view mix, std::string_view::size_type equal
handle_res handle_short_opts(
Record& record, std::string_view arg, std::span<std::string_view> next
) const
{
const auto opt = mix.substr(0, equal - 1);
const auto option = get_option(opt);
for (std::size_t opt_idx = 0; opt_idx < std::size(arg); opt_idx++) {
const auto opt = arg[opt_idx];
const auto option = get_option(opt);
if (!option.argument()) {
throw error<error_t::superfluous_argument>(opt);
}
if (!option.argument()) {
option(record, "true");
continue;
}
if (opt_idx + 1 != std::size(arg)) {
option(record, arg.substr(opt_idx + 1));
break;
}
if (!next.empty()) {
option(record, *std::begin(next));
return handle_res::next;
}
const auto arg = mix.substr(equal + 1);
if (arg.empty()) {
throw error<error_t::missing_argument>(opt);
}
option(record, arg);
return handle_res::ok;
}
public:
@@ -436,53 +421,19 @@
public:
continue;
}
if (arg_raw[1] != '-') {
// short options
auto arg = arg_raw.substr(1);
for (std::size_t opt_idx = 0; opt_idx < std::size(arg); opt_idx++) {
const auto res = handle_short(
record,
arg[opt_idx],
arg.substr(opt_idx + 1),
args.subspan(arg_idx + 1)
);
switch (res) {
case short_res::flag:
continue;
case short_res::rest:
break;
case short_res::next:
arg_idx++;
break;
case short_res::missing:
throw error<error_t::missing_argument>(arg);
break;
}
const auto res = arg_raw[1] != '-'
? handle_short_opts(
record, arg_raw.substr(1), args.subspan(arg_idx + 1)
)
: handle_long_opt(
record, arg_raw.substr(2), args.subspan(arg_idx + 1)
);
switch (res) {
case handle_res::ok:
break;
case handle_res::next:
arg_idx++;
break;
}
} else {
// long option
auto arg = arg_raw.substr(2);
const auto equal = arg.find('=');
if (equal != std::string::npos) {
handle_long_equal(record, arg, equal);
continue;
}
const auto res = handle_long(record, arg, args.subspan(arg_idx + 1));
switch (res) {
case long_res::flag:
break;
case long_res::next:
arg_idx++;
break;
case long_res::missing:
throw error<error_t::missing_argument>(arg);
break;
}
}
}