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 | a14d57316e69826f82d9eca3581f89c7b1edf35c |
parent | 1d6c74943aa185bcde7b33da4cf27d8fcf647e95 |
author | Dimitrije Dobrota < mail@dimitrijedobrota.com > |
date | Fri, 23 May 2025 23:01:20 +0200 |
Centralized error reporting
A | include/poafloc/error.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | include/poafloc/poafloc.hpp | | | +++++++++++++ ------------------------------------------------ |
2 files changed, 73 insertions(+), 48 deletions(-)
diff --git a/ include/poafloc/error.hpp b/ include/poafloc/error.hpp
@@ -0,0 +1,60 @@
#pragma once
#include <format>
#include <stdexcept>
#include <based/enum/enum.hpp>
#include <based/types/types.hpp>
#include <based/utility/forward.hpp>
namespace poafloc
{
#define ENUM_ERROR \
invalid_char, missing_argument, superfluous_argument, unknown_option, \
duplicate_option
BASED_DECLARE_ENUM(error_t, based::bu8, 0, ENUM_ERROR)
BASED_DEFINE_ENUM(error_t, based::bu8, 0, ENUM_ERROR)
#undef ENUM_ERROR
static constexpr const char* error_get_message(error_t::enum_type error)
{
switch (error()) {
case error_t::invalid_char():
return "Invalid char in option: {}";
case error_t::missing_argument():
return "Missing argument for option: {}";
case error_t::superfluous_argument():
return "Option doesn't require an argument: {}";
case error_t::unknown_option():
return "Unknown option: {}";
case error_t::duplicate_option():
return "Duplicate option: {}";
default:
return "poafloc error, should not happen...";
}
}
class runtime_error : public std::runtime_error
{
public:
explicit runtime_error(const std::string& err)
: std::runtime_error(err)
{
}
};
template<error_t::enum_type e>
class error : public runtime_error
{
public:
template<class... Args>
explicit error(Args... args)
: runtime_error(
std::format(error_get_message(e), based::forward<Args>(args)...)
)
{
}
};
} // namespace poafloc
diff --git a/ include/poafloc/poafloc.hpp b/ include/poafloc/poafloc.hpp
@@ -13,6 +13,8 @@
#include <string_view>
#include <vector>
#include "poafloc/error.hpp"
namespace poafloc
{
@@ -141,20 +143,13 @@
struct option_base
static auto convert(char chr)
{
if (!is_valid(chr)) {
invalid_char(chr);
throw error<error_t::invalid_char>(chr);
}
return mapping[static_cast<container_type::size_type>(
static_cast<unsigned char>(chr)
)];
}
[[noreturn]] static void invalid_char(char c)
{
throw std::runtime_error {
std::format("Invalid char in option: {}", c),
};
}
};
class option_short : option_base
@@ -282,23 +277,17 @@
class parser
if (str[1] != '-') {
if (std::size(str) != 2) {
throw std::runtime_error {std::format(
"Short option requires one character: {}", str.substr(1)
)};
continue;
}
const auto opt = str[1];
if (!m_opt_short.set(opt, std::size(m_options))) {
throw std::runtime_error {
std::format("Duplicate short option: {}", opt)
};
throw error<error_t::duplicate_option>(opt);
}
} else {
const auto opt = str.substr(2);
if (!m_opt_long.set(opt, std::size(m_options))) {
throw std::runtime_error {
std::format("Duplicate long option: {}", opt)
};
throw error<error_t::duplicate_option>(opt);
}
}
}
@@ -310,7 +299,7 @@
class parser
{
const auto idx = m_opt_short.get(opt);
if (!idx.has_value()) {
unknown_option(opt);
throw error<error_t::unknown_option>(opt);
}
return m_options[idx.value()];
}
@@ -319,35 +308,11 @@
class parser
{
const auto idx = m_opt_long.get(opt);
if (!idx.has_value()) {
unknown_option(opt);
throw error<error_t::unknown_option>(opt);
}
return m_options[idx.value()];
}
template<class T>
[[noreturn]] static void missing_argument(T opt)
{
throw std::runtime_error {
std::format("Missing argument for option: {}", opt)
};
}
template<class T>
[[noreturn]] static void superfluous_argument(T opt)
{
throw std::runtime_error {
std::format("Option doesn't require an argument: {}", opt)
};
}
template<class T>
[[noreturn]] static void unknown_option(T opt)
{
throw std::runtime_error {
std::format("Unknown option: {}", opt),
};
}
[[noreturn]] static void unhandled_positional(std::string_view arg)
{
throw std::runtime_error {
@@ -424,12 +389,12 @@
class parser
const auto option = get_option(opt);
if (!option.argument()) {
superfluous_argument(opt);
throw error<error_t::superfluous_argument>(opt);
}
const auto arg = mix.substr(equal + 1);
if (arg.empty()) {
missing_argument(opt);
throw error<error_t::missing_argument>(opt);
}
option(record, arg);
@@ -459,7 +424,7 @@
public:
const auto arg_raw = args[arg_idx];
if (arg_raw.size() < 2) {
unknown_option(arg_raw);
throw error<error_t::unknown_option>(arg_raw);
}
if (arg_raw == "--") {
@@ -491,7 +456,7 @@
public:
arg_idx++;
break;
case short_res::missing:
missing_argument(arg);
throw error<error_t::missing_argument>(arg);
break;
}
@@ -515,7 +480,7 @@
public:
arg_idx++;
break;
case long_res::missing:
missing_argument(arg);
throw error<error_t::missing_argument>(arg);
break;
}
}