mirror of
https://github.com/sametersoylu/argument-parser.git
synced 2026-04-13 03:41:18 +00:00
fix: windows parsing
This commit is contained in:
@@ -8,16 +8,28 @@
|
||||
namespace argument_parser {
|
||||
using parser = linux_parser;
|
||||
}
|
||||
|
||||
namespace argument_parser::v2 {
|
||||
using parser = linux_parser;
|
||||
}
|
||||
#elif __APPLE__
|
||||
#include <macos_parser.hpp>
|
||||
namespace argument_parser {
|
||||
using parser = macos_parser;
|
||||
}
|
||||
|
||||
namespace argument_parser::v2 {
|
||||
using parser = macos_parser;
|
||||
}
|
||||
#elif _WIN32
|
||||
#include <windows_parser.hpp>
|
||||
namespace argument_parser {
|
||||
using parser = windows_parser;
|
||||
}
|
||||
|
||||
namespace argument_parser::v2 {
|
||||
using parser = windows_parser;
|
||||
}
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <type_traits>
|
||||
#ifndef ARGUMENT_PARSER_HPP
|
||||
#define ARGUMENT_PARSER_HPP
|
||||
|
||||
#include <any>
|
||||
#include <atomic>
|
||||
#include <base_convention.hpp>
|
||||
@@ -158,8 +157,9 @@ namespace argument_parser {
|
||||
auto id = find_argument_id(arg);
|
||||
if (id.has_value()) {
|
||||
auto value = stored_arguments.find(id.value());
|
||||
if (value != stored_arguments.end() && value->second.has_value())
|
||||
if (value != stored_arguments.end() && value->second.has_value()) {
|
||||
return std::any_cast<T>(value->second);
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace argument_parser::v2 {
|
||||
|
||||
template <typename T>
|
||||
void add_argument(std::unordered_map<add_argument_flags, typed_flag_value<T>> const &argument_pairs) {
|
||||
add_argument_impl<true, parametered_action<T>>(argument_pairs);
|
||||
add_argument_impl<true, parametered_action<T>, T>(argument_pairs);
|
||||
}
|
||||
|
||||
template <typename T> void add_argument(std::initializer_list<typed_argument_pair<T>> const &pairs) {
|
||||
@@ -62,7 +62,7 @@ namespace argument_parser::v2 {
|
||||
}
|
||||
|
||||
void add_argument(std::unordered_map<add_argument_flags, non_typed_flag_value> const &argument_pairs) {
|
||||
add_argument_impl<false, non_parametered_action>(argument_pairs);
|
||||
add_argument_impl<false, non_parametered_action, void>(argument_pairs);
|
||||
}
|
||||
|
||||
argument_parser::base_parser &to_v1() {
|
||||
@@ -91,7 +91,7 @@ namespace argument_parser::v2 {
|
||||
}
|
||||
|
||||
private:
|
||||
template <bool IsTyped, typename ActionType, typename ArgsMap>
|
||||
template <bool IsTyped, typename ActionType, typename T, typename ArgsMap>
|
||||
void add_argument_impl(ArgsMap const &argument_pairs) {
|
||||
std::unordered_map<extended_add_argument_flags, bool> found_params{
|
||||
{extended_add_argument_flags::IsTyped, IsTyped}};
|
||||
@@ -142,7 +142,7 @@ namespace argument_parser::v2 {
|
||||
required);
|
||||
break;
|
||||
case candidate_type::store_other:
|
||||
base::add_argument(short_arg, long_arg, help_text, required);
|
||||
base::add_argument<T>(short_arg, long_arg, help_text, required);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Could not match the arguments against any overload.");
|
||||
|
||||
17
src/main.cpp
17
src/main.cpp
@@ -160,9 +160,16 @@ int v1Examples() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void run_store_point(argument_parser::base_parser const &parser) {
|
||||
auto point = parser.get_optional<Point>("store-point");
|
||||
if (point) {
|
||||
std::cout << "Point(" << point->x << ", " << point->y << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int v2Examples() {
|
||||
using namespace argument_parser::v2::flags;
|
||||
argument_parser::v2::base_parser parser;
|
||||
argument_parser::v2::parser parser;
|
||||
|
||||
parser.add_argument<std::string>(
|
||||
{{ShortArgument, "e"}, {LongArgument, "echo"}, {Action, echo}, {HelpText, "echoes given variable"}});
|
||||
@@ -196,11 +203,17 @@ int v2Examples() {
|
||||
});
|
||||
|
||||
parser.on_complete(::run_grep);
|
||||
parser.on_complete(::run_store_point);
|
||||
|
||||
parser.handle_arguments(conventions);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
return v2Examples();
|
||||
try {
|
||||
return v2Examples();
|
||||
} catch (std::exception const &e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,6 @@ namespace argument_parser {
|
||||
|
||||
try {
|
||||
argument &corresponding_argument = get_argument(extracted);
|
||||
|
||||
if (corresponding_argument.expects_parameter()) {
|
||||
if (convention_type->requires_next_token() && (it + 1) == parsed_arguments.end()) {
|
||||
throw std::runtime_error("expected value for argument " + extracted.second);
|
||||
|
||||
@@ -3,26 +3,13 @@
|
||||
#include "windows_parser.hpp"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <shellapi.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
std::string utf8_from_wstring(const std::wstring &w) {
|
||||
if (w.empty())
|
||||
return {};
|
||||
int needed = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
||||
if (needed <= 0) {
|
||||
throw std::runtime_error("WideCharToMultiByte sizing failed (" + std::to_string(::GetLastError()) + ")");
|
||||
}
|
||||
std::string out;
|
||||
out.resize(static_cast<size_t>(needed - 1));
|
||||
int written =
|
||||
::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w.c_str(), -1, out.data(), needed - 1, nullptr, nullptr);
|
||||
if (written <= 0) {
|
||||
throw std::runtime_error("WideCharToMultiByte convert failed (" + std::to_string(::GetLastError()) + ")");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
using namespace std::string_literals;
|
||||
|
||||
struct local_free_deleter {
|
||||
void operator()(void *ptr) const {
|
||||
@@ -33,28 +20,81 @@ struct local_free_deleter {
|
||||
}
|
||||
};
|
||||
|
||||
void parse_windows_arguments(std::vector<std::string> &parsed_arguments) {
|
||||
std::string windows_error_message(DWORD error_code) {
|
||||
LPSTR messageBuffer = nullptr;
|
||||
|
||||
size_t size = FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
|
||||
error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPSTR>(&messageBuffer), 0, nullptr);
|
||||
|
||||
if (size == 0 || !messageBuffer) {
|
||||
return "Unknown Error ("s + std::to_string(error_code) + ")";
|
||||
}
|
||||
|
||||
std::unique_ptr<char, local_free_deleter> smartBuffer(messageBuffer);
|
||||
std::string result(smartBuffer.get(), size);
|
||||
result.erase(result.find_last_not_of(" \n\r\t") + 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string utf8_from_wstring(const std::wstring &w) {
|
||||
if (w.empty())
|
||||
return {};
|
||||
|
||||
int needed = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
||||
if (needed <= 0) {
|
||||
throw std::runtime_error("WideCharToMultiByte sizing failed ("s + windows_error_message(::GetLastError()) +
|
||||
")");
|
||||
}
|
||||
std::string out;
|
||||
out.resize(needed - 1);
|
||||
int written =
|
||||
::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w.c_str(), -1, out.data(), needed, nullptr, nullptr);
|
||||
if (written <= 0) {
|
||||
throw std::runtime_error(
|
||||
"WideCharToMultiByte convert failed, Error("s + windows_error_message(::GetLastError()) + ")" +
|
||||
" Size (Needed): " + std::to_string(needed) + " Size (Written): " + std::to_string(written) +
|
||||
" Size (Allocated): " + std::to_string(out.size()));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void parse_windows_arguments(std::vector<std::string> &parsed_arguments,
|
||||
std::function<void(std::string)> const &setProgramName) {
|
||||
int argc_w;
|
||||
std::unique_ptr<LPWSTR[], local_free_deleter> argv_w(CommandLineToArgvW(GetCommandLineW(), &argc_w));
|
||||
if (argv_w == nullptr) {
|
||||
throw std::runtime_error("CommandLineToArgvW failed");
|
||||
}
|
||||
|
||||
for (int i = 0; i < argc_w; i++) {
|
||||
std::string arg = utf8_from_wstring(argv_w[i]);
|
||||
parsed_arguments.emplace_back(arg);
|
||||
if (argc_w <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
setProgramName(utf8_from_wstring(argv_w[0]));
|
||||
|
||||
for (int i = 1; i < argc_w; i++) {
|
||||
try {
|
||||
std::string arg = utf8_from_wstring(argv_w[i]);
|
||||
parsed_arguments.emplace_back(arg);
|
||||
} catch (std::runtime_error e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace argument_parser {
|
||||
windows_parser::windows_parser() {
|
||||
parse_windows_arguments(parsed_arguments);
|
||||
parse_windows_arguments(parsed_arguments,
|
||||
[this](std::string const &program_name) { this->program_name = program_name; });
|
||||
}
|
||||
} // namespace argument_parser
|
||||
|
||||
namespace argument_parser::v2 {
|
||||
windows_parser::windows_parser() {
|
||||
parse_windows_arguments(ref_parsed_args());
|
||||
parse_windows_arguments(ref_parsed_args(),
|
||||
[this](std::string const &program_name) { this->set_program_name(program_name); });
|
||||
}
|
||||
} // namespace argument_parser::v2
|
||||
|
||||
|
||||
Reference in New Issue
Block a user