poafloc

Parser 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

Diffstat:
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;
}
}
}