mirror of
https://github.com/sametersoylu/argument-parser.git
synced 2026-04-13 03:41:18 +00:00
Merge pull request #1 from sametersoylu/v2
PoC: better argument building.
This commit is contained in:
10
TODO.md
10
TODO.md
@@ -38,3 +38,13 @@ Configure CMAKE to ensure the library can be built as a library and can be insta
|
|||||||
|
|
||||||
# TODO 5: Display help
|
# TODO 5: Display help
|
||||||
Display help doesn't reflect the conventions right now. Also it should come automatically, and should be allowed to overriden by user.
|
Display help doesn't reflect the conventions right now. Also it should come automatically, and should be allowed to overriden by user.
|
||||||
|
|
||||||
|
# TODO 6: Accumulate repeated calls
|
||||||
|
Add support to letting users accumulate repeated calls to a flag. If the flag is called x times, the result should be x items stored in a vector,
|
||||||
|
instead of an action doing it.
|
||||||
|
|
||||||
|
# TODO 7: Defaults/Implicits
|
||||||
|
If given, an arguments default store value could be changed. If nothing was given use that value instead.
|
||||||
|
|
||||||
|
# TODO 8: Validators
|
||||||
|
If given, validate the argument before passing to the storage or action. If fail, let user decide fail loud or fail skip.
|
||||||
|
|||||||
@@ -360,8 +360,6 @@ namespace argument_parser {
|
|||||||
friend class macos_parser;
|
friend class macos_parser;
|
||||||
friend class fake_parser;
|
friend class fake_parser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ARGUMENT_PARSER_HPP
|
#endif // ARGUMENT_PARSER_HPP
|
||||||
@@ -10,8 +10,10 @@
|
|||||||
namespace argument_parser {
|
namespace argument_parser {
|
||||||
class fake_parser : public base_parser {
|
class fake_parser : public base_parser {
|
||||||
public:
|
public:
|
||||||
fake_parser(std::string const& program_name, std::vector<std::string> const& arguments) {
|
fake_parser() = default;
|
||||||
this->program_name = program_name;
|
|
||||||
|
fake_parser(std::string program_name, std::vector<std::string> const& arguments) {
|
||||||
|
this->program_name = std::move(program_name);
|
||||||
parsed_arguments = arguments;
|
parsed_arguments = arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,6 +24,14 @@ namespace argument_parser {
|
|||||||
|
|
||||||
fake_parser(std::string const& program_name, std::initializer_list<std::string> const& arguments) :
|
fake_parser(std::string const& program_name, std::initializer_list<std::string> const& arguments) :
|
||||||
fake_parser(program_name, std::vector<std::string>(arguments)) {}
|
fake_parser(program_name, std::vector<std::string>(arguments)) {}
|
||||||
|
|
||||||
|
void set_program_name(std::string const& program_name) {
|
||||||
|
this->program_name = program_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_parsed_arguments(std::vector<std::string> const& parsed_arguments) {
|
||||||
|
this->parsed_arguments = parsed_arguments;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
249
include/parser/parser_v2.hpp
Normal file
249
include/parser/parser_v2.hpp
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <argument_parser.hpp>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <exception>
|
||||||
|
#include <fake_parser.hpp>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace argument_parser::v2 {
|
||||||
|
namespace internal {
|
||||||
|
static inline fake_parser fake_parser{};
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class add_argument_flags {
|
||||||
|
ShortArgument,
|
||||||
|
LongArgument,
|
||||||
|
HelpText,
|
||||||
|
Action,
|
||||||
|
Required
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace flags {
|
||||||
|
constexpr static inline add_argument_flags ShortArgument = add_argument_flags::ShortArgument;
|
||||||
|
constexpr static inline add_argument_flags LongArgument = add_argument_flags::LongArgument;
|
||||||
|
constexpr static inline add_argument_flags HelpText = add_argument_flags::HelpText;
|
||||||
|
constexpr static inline add_argument_flags Action = add_argument_flags::Action;
|
||||||
|
constexpr static inline add_argument_flags Required = add_argument_flags::Required;
|
||||||
|
}
|
||||||
|
|
||||||
|
class base_parser : private argument_parser::base_parser {
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
using typed_flag_value = std::variant<std::string, parametered_action<T>, bool>;
|
||||||
|
using non_typed_flag_value = std::variant<std::string, non_parametered_action, bool>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using typed_argument_pair = std::pair<add_argument_flags, typed_flag_value<T>>;
|
||||||
|
using non_typed_argument_pair = std::pair<add_argument_flags, non_typed_flag_value>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void add_argument(std::unordered_map<add_argument_flags, typed_flag_value<T>> const& argument_pairs) {
|
||||||
|
std::unordered_map<extended_add_argument_flags, bool> found_params {{
|
||||||
|
extended_add_argument_flags::IsTyped, true
|
||||||
|
}};
|
||||||
|
|
||||||
|
std::string short_arg, long_arg, help_text;
|
||||||
|
std::unique_ptr<action_base> action;
|
||||||
|
bool required = false;
|
||||||
|
|
||||||
|
if (argument_pairs.contains(add_argument_flags::ShortArgument)) {
|
||||||
|
found_params[extended_add_argument_flags::ShortArgument] = true;
|
||||||
|
short_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::ShortArgument), "short");
|
||||||
|
}
|
||||||
|
if (argument_pairs.contains(add_argument_flags::LongArgument)) {
|
||||||
|
found_params[extended_add_argument_flags::LongArgument] = true;
|
||||||
|
long_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::LongArgument), "long");
|
||||||
|
if (short_arg.empty()) short_arg = long_arg;
|
||||||
|
} else {
|
||||||
|
if (!short_arg.empty()) long_arg = short_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument_pairs.contains(add_argument_flags::Action)) {
|
||||||
|
found_params[extended_add_argument_flags::Action] = true;
|
||||||
|
action = get_or_throw<parametered_action<T>>(argument_pairs.at(add_argument_flags::Action), "action").clone();
|
||||||
|
}
|
||||||
|
if (argument_pairs.contains(add_argument_flags::HelpText)) {
|
||||||
|
help_text = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::HelpText), "help");
|
||||||
|
} else {
|
||||||
|
help_text = short_arg + ", " + long_arg;
|
||||||
|
}
|
||||||
|
if (argument_pairs.contains(add_argument_flags::Required) && get_or_throw<bool>(argument_pairs.at(add_argument_flags::Required), "required")) {
|
||||||
|
required = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto suggested_add = suggest_candidate(found_params);
|
||||||
|
if (suggested_add == candidate_type::unknown) {
|
||||||
|
throw std::runtime_error("Could not match any add argument overload to given parameters. Are you missing some required parameter?");
|
||||||
|
}
|
||||||
|
switch (suggested_add) {
|
||||||
|
case candidate_type::typed_action:
|
||||||
|
base::add_argument(short_arg, long_arg, help_text, *static_cast<parametered_action<T>*>(&(*action)), required);
|
||||||
|
break;
|
||||||
|
case candidate_type::store_other:
|
||||||
|
base::add_argument(short_arg, long_arg, help_text, required);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Could not match the arguments against any overload.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void add_argument(std::initializer_list<typed_argument_pair<T>> const& pairs) {
|
||||||
|
std::unordered_map<add_argument_flags, typed_flag_value<T>> args;
|
||||||
|
|
||||||
|
for (auto& [k, v]: pairs) {
|
||||||
|
args[k] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_argument<T>(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_argument(std::initializer_list<non_typed_argument_pair> const& pairs) {
|
||||||
|
std::unordered_map<add_argument_flags, non_typed_flag_value> args;
|
||||||
|
|
||||||
|
for (auto& [k, v] : pairs) {
|
||||||
|
args[k] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_argument(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_argument(std::unordered_map<add_argument_flags, non_typed_flag_value> const& argument_pairs) {
|
||||||
|
std::unordered_map<extended_add_argument_flags, bool> found_params {{
|
||||||
|
extended_add_argument_flags::IsTyped, false
|
||||||
|
}};
|
||||||
|
|
||||||
|
std::string short_arg, long_arg, help_text;
|
||||||
|
std::unique_ptr<action_base> action;
|
||||||
|
bool required = false;
|
||||||
|
|
||||||
|
if (argument_pairs.contains(add_argument_flags::ShortArgument)) {
|
||||||
|
found_params[extended_add_argument_flags::ShortArgument] = true;
|
||||||
|
short_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::ShortArgument), "short");
|
||||||
|
}
|
||||||
|
if (argument_pairs.contains(add_argument_flags::LongArgument)) {
|
||||||
|
found_params[extended_add_argument_flags::LongArgument] = true;
|
||||||
|
long_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::LongArgument), "long");
|
||||||
|
if (short_arg.empty()) short_arg = long_arg;
|
||||||
|
} else {
|
||||||
|
if (!short_arg.empty()) long_arg = short_arg;
|
||||||
|
}
|
||||||
|
if (argument_pairs.contains(add_argument_flags::Action)) {
|
||||||
|
found_params[extended_add_argument_flags::Action] = true;
|
||||||
|
action = get_or_throw<non_parametered_action>(argument_pairs.at(add_argument_flags::Action), "action").clone();
|
||||||
|
|
||||||
|
}
|
||||||
|
if (argument_pairs.contains(add_argument_flags::HelpText)) {
|
||||||
|
help_text = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::HelpText), "help");
|
||||||
|
} else {
|
||||||
|
help_text = short_arg + ", " + long_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument_pairs.contains(add_argument_flags::Required) && get_or_throw<bool>(argument_pairs.at(add_argument_flags::Required), "required")) {
|
||||||
|
required = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto suggested_add = suggest_candidate(found_params);
|
||||||
|
if (suggested_add == candidate_type::unknown) {
|
||||||
|
throw std::runtime_error("Could not match any add argument overload to given parameters. Are you missing some required parameter?");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (suggested_add) {
|
||||||
|
case candidate_type::non_typed_action:
|
||||||
|
base::add_argument(short_arg, long_arg, help_text, *static_cast<non_parametered_action*>(&(*action)), required);
|
||||||
|
break;
|
||||||
|
case candidate_type::store_boolean:
|
||||||
|
base::add_argument(short_arg, long_arg, help_text, required);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Could not match the arguments against any overload. The suggested candidate was: " + std::to_string((int(suggested_add))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argument_parser::base_parser& to_v1() {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_arguments(std::initializer_list<conventions::convention const* const> convention_types) {
|
||||||
|
base::handle_arguments(convention_types);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T> get_optional(std::string const& arg) {
|
||||||
|
return base::get_optional<T>(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_complete(std::function<void(argument_parser::base_parser const&)> const& action) {
|
||||||
|
base::on_complete(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void set_program_name(std::string p) {
|
||||||
|
base::program_name = std::move(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string>& ref_parsed_args() {
|
||||||
|
return base::parsed_arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
using base = argument_parser::base_parser;
|
||||||
|
enum class extended_add_argument_flags {
|
||||||
|
ShortArgument,
|
||||||
|
LongArgument,
|
||||||
|
Action,
|
||||||
|
IsTyped
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class candidate_type {
|
||||||
|
store_boolean,
|
||||||
|
store_other,
|
||||||
|
typed_action,
|
||||||
|
non_typed_action,
|
||||||
|
unknown
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, size_t S>
|
||||||
|
bool satisfies_at_least_one(std::array<T, S> const& arr, std::unordered_map<T, bool> const& map) {
|
||||||
|
for (const auto& req: arr) {
|
||||||
|
if (map.contains(req)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
candidate_type suggest_candidate(std::unordered_map<extended_add_argument_flags, bool> const& available_vars) {
|
||||||
|
auto constexpr required_at_least_one = std::array<extended_add_argument_flags, 2> { extended_add_argument_flags::ShortArgument, extended_add_argument_flags::LongArgument };
|
||||||
|
if (!satisfies_at_least_one(required_at_least_one, available_vars)) return candidate_type::unknown;
|
||||||
|
|
||||||
|
if (available_vars.contains(extended_add_argument_flags::Action)) {
|
||||||
|
if (available_vars.at(extended_add_argument_flags::IsTyped))
|
||||||
|
return candidate_type::typed_action;
|
||||||
|
else return candidate_type::non_typed_action;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (available_vars.at(extended_add_argument_flags::IsTyped)) return candidate_type::store_other;
|
||||||
|
return candidate_type::store_boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename I>
|
||||||
|
T get_or_throw(typed_flag_value<I> const& v, std::string_view key) {
|
||||||
|
if (auto p = std::get_if<T>(&v)) return *p;
|
||||||
|
throw std::invalid_argument(std::string("variant type mismatch for key: ") + std::string(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T get_or_throw(non_typed_flag_value const& v, std::string_view key) {
|
||||||
|
if (auto p = std::get_if<T>(&v)) return *p;
|
||||||
|
throw std::invalid_argument(std::string("variant type mismatch for key: ") + std::string(key));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <argument_parser.hpp>
|
#include <argument_parser.hpp>
|
||||||
#include <crt_externs.h>
|
#include <crt_externs.h>
|
||||||
|
#include <parser_v2.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace argument_parser {
|
namespace argument_parser {
|
||||||
@@ -13,13 +14,28 @@ namespace argument_parser {
|
|||||||
macos_parser() {
|
macos_parser() {
|
||||||
const int argc = *_NSGetArgc();
|
const int argc = *_NSGetArgc();
|
||||||
if (char **argv = *_NSGetArgv(); argc > 0 && argv != nullptr && argv[0] != nullptr) {
|
if (char **argv = *_NSGetArgv(); argc > 0 && argv != nullptr && argv[0] != nullptr) {
|
||||||
program_name = argv[0];
|
program_name = (argv[0]);
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (int i = 1; i < argc; ++i) {
|
||||||
if (argv[i] != nullptr) parsed_arguments.emplace_back(argv[i]);
|
if (argv[i] != nullptr) parsed_arguments.emplace_back(argv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace v2 {
|
||||||
|
class macos_parser : public v2::base_parser {
|
||||||
|
public:
|
||||||
|
macos_parser() {
|
||||||
|
const int argc = *_NSGetArgc();
|
||||||
|
if (char **argv = *_NSGetArgv(); argc > 0 && argv != nullptr && argv[0] != nullptr) {
|
||||||
|
set_program_name(argv[0]);
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
if (argv[i] != nullptr) ref_parsed_args().emplace_back(argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,98 +1,61 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifndef WINDOWS_PARSER_HPP
|
|
||||||
|
|
||||||
// compiler bitches if you don't use lean and mean and remove shit ton of other macros that comes preloaded with the windows api.
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#ifndef NOMINMAX
|
|
||||||
#define NOMINMAX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// I'm speaking to you Microsoft, STOP MAKING EVERYTHING A FUCKING MACRO. IT BREAKES CPP!
|
|
||||||
#define NOGDI
|
|
||||||
#define NOHELP
|
|
||||||
#define NOMCX
|
|
||||||
#define NOIME
|
|
||||||
#define NOCOMM
|
|
||||||
#define NOKANJI
|
|
||||||
#define NOSERVICE
|
|
||||||
#define NOMDI
|
|
||||||
#define NOSOUND
|
|
||||||
|
|
||||||
// also this fixes error about no architecture being targeted (somehow)
|
|
||||||
#if defined(_M_AMD64) && !defined(_AMD64_)
|
|
||||||
# define _AMD64_
|
|
||||||
#endif
|
|
||||||
#if defined(_M_IX86) && !defined(_X86_)
|
|
||||||
# define _X86_
|
|
||||||
#endif
|
|
||||||
#if defined(_M_ARM64) && !defined(_ARM64_)
|
|
||||||
# define _ARM64_
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <argument_parser.hpp>
|
#include <argument_parser.hpp>
|
||||||
#include <fstream>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
// THIS HAS TO BE THE FIRST. DON'T CHANGE THEIR ORDER.
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <processenv.h>
|
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
|
||||||
namespace argument_parser {
|
namespace argument_parser {
|
||||||
|
|
||||||
class windows_parser : public base_parser {
|
class windows_parser : public base_parser {
|
||||||
public:
|
public:
|
||||||
windows_parser() {
|
windows_parser() {
|
||||||
int nArgs;
|
int nArgs = 0;
|
||||||
LPWSTR commandLineA = GetCommandLineW();
|
LPWSTR* raw = ::CommandLineToArgvW(::GetCommandLineW(), &nArgs);
|
||||||
auto argvW = std::unique_ptr<LPWSTR, local_free_deleter> { CommandLineToArgvW(commandLineA, &nArgs) };
|
if (!raw) {
|
||||||
|
throw std::runtime_error("CommandLineToArgvW failed (" +
|
||||||
if (argvW == nullptr) {
|
std::to_string(::GetLastError()) + ")");
|
||||||
throw std::runtime_error("Failed to get command line arguments.");
|
|
||||||
}
|
}
|
||||||
|
std::unique_ptr<LPWSTR, void(*)(LPWSTR*)> argvW{ raw, [](LPWSTR* p){ if (p) ::LocalFree(p); } };
|
||||||
|
|
||||||
if (nArgs <= 0) {
|
if (nArgs <= 0) {
|
||||||
throw std::runtime_error("No command line arguments found, including program name.");
|
throw std::runtime_error("No command line arguments found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
program_name = utf8_from_wstring(argvW.get()[0]);
|
{
|
||||||
parsed_arguments.reserve(static_cast<size_t>(nArgs - 1));
|
std::wstring w0 = argvW.get()[0];
|
||||||
|
auto pos = w0.find_last_of(L"\\/");
|
||||||
|
std::wstring base = (pos == std::wstring::npos) ? w0 : w0.substr(pos + 1);
|
||||||
|
program_name = utf8_from_wstring(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed_arguments.reserve(static_cast<size_t>(nArgs > 0 ? nArgs - 1 : 0));
|
||||||
for (int i = 1; i < nArgs; ++i) {
|
for (int i = 1; i < nArgs; ++i) {
|
||||||
parsed_arguments.emplace_back(utf8_from_wstring(argvW.get()[i]));
|
parsed_arguments.emplace_back(utf8_from_wstring(argvW.get()[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct local_free_deleter {
|
|
||||||
void operator()(HLOCAL ptr) const noexcept {
|
|
||||||
if (ptr != nullptr) ::LocalFree(ptr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::string utf8_from_wstring(const std::wstring& w) {
|
static std::string utf8_from_wstring(const std::wstring& w) {
|
||||||
if (w.empty()) return {};
|
if (w.empty()) return {};
|
||||||
int needed = ::WideCharToMultiByte(CP_UTF8, 0, w.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
int needed = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
|
||||||
if (needed == 0) {
|
w.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
||||||
throw std::runtime_error("WideCharToMultiByte sizing failed ("
|
if (needed <= 0) {
|
||||||
+ std::to_string(GetLastError()) + ")");
|
throw std::runtime_error("WideCharToMultiByte sizing failed (" +
|
||||||
|
std::to_string(::GetLastError()) + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string out;
|
std::string out;
|
||||||
out.resize(static_cast<size_t>(needed - 1));
|
out.resize(static_cast<size_t>(needed - 1));
|
||||||
int written = ::WideCharToMultiByte(CP_UTF8, 0, w.c_str(), -1,
|
int written = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
|
||||||
out.data(), needed, nullptr, nullptr);
|
w.c_str(), -1, out.data(), needed - 1, nullptr, nullptr);
|
||||||
if (written == 0) {
|
if (written <= 0) {
|
||||||
throw std::runtime_error("WideCharToMultiByte convert failed ("
|
throw std::runtime_error("WideCharToMultiByte convert failed (" +
|
||||||
+ std::to_string(GetLastError()) + ")");
|
std::to_string(::GetLastError()) + ")");
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using parser = windows_parser;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
60
src/main.cpp
60
src/main.cpp
@@ -1,7 +1,10 @@
|
|||||||
|
#include "macos_parser.hpp"
|
||||||
|
#include <string>
|
||||||
#define ALLOW_DASH_FOR_WINDOWS 0
|
#define ALLOW_DASH_FOR_WINDOWS 0
|
||||||
|
|
||||||
|
#include <parser_v2.hpp>
|
||||||
#include <argparse>
|
#include <argparse>
|
||||||
#include <cstdlib>
|
#include <expected>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
@@ -135,7 +138,9 @@ void run_grep(argument_parser::base_parser const& parser) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
|
||||||
|
int v1Examples() {
|
||||||
|
|
||||||
auto parser = argument_parser::parser{};
|
auto parser = argument_parser::parser{};
|
||||||
|
|
||||||
parser.add_argument("e", "echo", "echoes given variable", echo, false);
|
parser.add_argument("e", "echo", "echoes given variable", echo, false);
|
||||||
@@ -174,6 +179,55 @@ int main() {
|
|||||||
std::cout << item << std::endl;
|
std::cout << item << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int v2Examples() {
|
||||||
|
using namespace argument_parser::v2::flags;
|
||||||
|
argument_parser::v2::macos_parser parser;
|
||||||
|
|
||||||
|
parser.add_argument<std::string>({
|
||||||
|
{ ShortArgument, "e" },
|
||||||
|
{ LongArgument, "echo" },
|
||||||
|
{ Action, echo }
|
||||||
|
});
|
||||||
|
|
||||||
|
parser.add_argument<Point>({
|
||||||
|
{ ShortArgument, "ep" },
|
||||||
|
{ LongArgument, "echo-point" },
|
||||||
|
{ Action, echo_point }
|
||||||
|
});
|
||||||
|
|
||||||
|
parser.add_argument<std::string>({ // stores string for f/file flag
|
||||||
|
{ ShortArgument, "f" },
|
||||||
|
{ LongArgument, "file"},
|
||||||
|
// if no action, falls to store operation with given type.
|
||||||
|
});
|
||||||
|
|
||||||
|
parser.add_argument<std::regex>({ // stores string for g/grep flag
|
||||||
|
{ ShortArgument, "g" },
|
||||||
|
{ LongArgument, "grep" },
|
||||||
|
// same as 'file' flag
|
||||||
|
});
|
||||||
|
|
||||||
|
parser.add_argument<std::string>({
|
||||||
|
{ ShortArgument, "c" },
|
||||||
|
{ LongArgument, "cat" },
|
||||||
|
{ Action, cat }
|
||||||
|
});
|
||||||
|
|
||||||
|
parser.add_argument<Point>({
|
||||||
|
// { ShortArgument, "sp" }, // now if ShortArgument or LongArgument is missing, it will use it for the other.
|
||||||
|
{ LongArgument, "store-point" },
|
||||||
|
{ Required, true } // makes this flag required
|
||||||
|
});
|
||||||
|
|
||||||
|
parser.on_complete(::run_grep);
|
||||||
|
|
||||||
|
parser.handle_arguments(conventions);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return v2Examples();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user