List of example source files.
#include <arg_router/arg_router.hpp>
#include <cstdlib>
#include <filesystem>
#include <fstream>
namespace arp = ar::policy;
namespace ard = ar::dependency;
using namespace std::string_view_literals;
using namespace std::string_literals;
using namespace ar::utility::string_view_ops;
namespace
{
enum class theme_t {
none, classic, solarized };
enum class verbosity_level_t { error, warning, info, debug };
constexpr auto version = "v3.14"sv;
constexpr auto no_line_limit = -1;
constexpr auto tab_num = std::uint8_t{9};
constexpr auto nl_num = std::uint8_t{10};
constexpr auto printing_range = std::pair{std::uint8_t{32}, std::uint8_t{126}};
constexpr auto ascii_max = std::uint8_t{127};
constexpr auto offset = std::uint8_t{64};
theme_t theme_from_string(std::string_view
arg)
{
return theme_t::none;
}
return theme_t::classic;
}
if (
arg ==
"solarized") {
return theme_t::solarized;
}
throw ar::parse_exception{
"Unknown theme argument: "s +
arg};
}
void set_theme(theme_t theme)
{
switch (theme) {
case theme_t::classic: std::cout << "\033[31m"; break;
case theme_t::solarized: std::cout << "\033[32m"; break;
default: std::cout << "\033[0m"; break;
}
}
std::string m_notation(std::string&& input)
{
auto result = ""s;
result.reserve(input.size() * 2);
for (auto c : input) {
const auto num = static_cast<std::uint8_t>(c);
if ((num >= printing_range.first && num <= printing_range.second) ||
num == tab_num ||
num == nl_num) {
result.push_back(c);
} else if (num <= ascii_max) {
result += "^"s + static_cast<char>(num + offset);
} else {
result += "M-^"s + static_cast<char>(num - offset);
}
}
return result;
}
void cat(bool show_ends,
bool show_non_printing,
int max_lines,
std::optional<std::size_t> max_line_length,
std::variant<bool, std::string_view> max_line_handling,
std::vector<std::string_view>&& files)
{
if (max_lines == no_line_limit) {
max_lines = std::numeric_limits<int>::max();
}
for (auto file : files) {
if (!std::filesystem::exists(file)) {
throw std::invalid_argument{"File does not exist: "s + file};
}
auto stream = std::ifstream{file.data()};
auto line_number = 0;
for (auto line = ""s; std::getline(stream, line);) {
if (line_number++ == max_lines) {
break;
}
if (max_line_length && (line.size() > *max_line_length)) {
if (max_line_handling.index() == 0) {
continue;
}
const auto suffix = std::get<1>(max_line_handling);
line = line.substr(0, *max_line_length) + suffix;
}
if (show_non_printing) {
line = m_notation(std::move(line));
}
std::cout << line;
if (show_ends) {
std::cout << "$";
}
std::cout << "\n";
}
}
}
}
template <>
struct ar::parser<verbosity_level_t> {
[[nodiscard]] static inline verbosity_level_t parse(std::string_view arg)
{
if (arg == "error") {
return verbosity_level_t::error;
}
if (arg == "warning") {
return verbosity_level_t::warning;
}
if (arg == "info") {
return verbosity_level_t::info;
}
if (arg == "debug") {
return verbosity_level_t::debug;
}
throw ar::parse_exception{
"Unknown verbosity argument: "s +
arg};
}
};
int main(int argc, char* argv[])
{
ar::root(arp::validation::default_validator,
S_(
"Display this help and exit"){},
arp::program_name<
S_(
"my-cat")>,
arp::program_version<
S_(version)>,
arp::program_addendum<
S_(
"An example program for arg_router.")>),
ar::flag(
S_(
"version"){},
S_(
"Output version information and exit"){},
arp::router{[](bool) {
std::cout << version << std::endl;
std::exit(EXIT_SUCCESS);
}}),
ar::mode(ar::flag(
S_(
"show-all"){},
S_(
"Equivalent to -nE"){},
arp::alias(arp::short_name<'E'>, arp::short_name<'n'>)),
ar::flag(
S_(
"show-ends"){},
S_(
"Display $ at end of each line"){},
S_(
'E'){}),
ar::flag(
S_(
"show-nonprinting"){},
S_(
"Use ^ and M- notation, except for LFD and TAB"){},
ar::arg<int>(
S_(
"max-lines"){},
S_(
"Maximum lines to output"){},
arp::value_separator<'='>,
arp::default_value{-1}),
ar::arg<std::optional<std::size_t>>(
S_(
"Maximum line length"){},
arp::value_separator<'='>,
arp::default_value{std::optional<std::size_t>{}}),
ard::one_of(arp::default_value{"..."},
ar::flag(arp::dependent(arp::long_name<
S_(
"max-line-length")>),
S_(
"Skips line output if max line length reached"){}),
ar::arg<std::string_view>(
arp::dependent(arp::long_name<
S_(
"max-line-length")>),
S_(
"Shortens line length to maximum with the given "
"suffix if max line length reached"){},
arp::value_separator<'='>)),
ar::arg<theme_t>(
S_(
"theme"){},
S_(
"Set the output colour theme"){},
arp::value_separator<'='>,
arp::default_value{theme_t::none},
arp::custom_parser<theme_t>{[](std::string_view
arg) {
return theme_from_string(arg);
}}),
ard::alias_group(
arp::default_value{verbosity_level_t::info},
ar::counting_flag<verbosity_level_t>(
arp::description<
S_(
"Verbosity level, number of 'v's sets level")>),
ar::arg<verbosity_level_t>(
S_(
"verbose"){},
arp::value_separator<'='>),
arp::min_max_value<verbosity_level_t::error, verbosity_level_t::debug>()),
ar::positional_arg<std::vector<std::string_view>>(arp::required,
arp::min_count<1>,
arp::router{[](bool show_ends,
bool show_non_printing,
int max_lines,
std::optional<std::size_t> max_line_length,
std::variant<bool, std::string_view> max_line_handling,
theme_t theme,
verbosity_level_t ,
std::vector<std::string_view> files) {
set_theme(theme);
cat(show_ends,
show_non_printing,
max_lines,
max_line_length,
max_line_handling,
std::move(files));
set_theme(theme_t::none);
}}))
.parse(argc, argv);
return EXIT_SUCCESS;
}
constexpr auto arg(Policies... policies) noexcept