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 {
|
namespace argument_parser {
|
||||||
using parser = linux_parser;
|
using parser = linux_parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace argument_parser::v2 {
|
||||||
|
using parser = linux_parser;
|
||||||
|
}
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
#include <macos_parser.hpp>
|
#include <macos_parser.hpp>
|
||||||
namespace argument_parser {
|
namespace argument_parser {
|
||||||
using parser = macos_parser;
|
using parser = macos_parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace argument_parser::v2 {
|
||||||
|
using parser = macos_parser;
|
||||||
|
}
|
||||||
#elif _WIN32
|
#elif _WIN32
|
||||||
#include <windows_parser.hpp>
|
#include <windows_parser.hpp>
|
||||||
namespace argument_parser {
|
namespace argument_parser {
|
||||||
using parser = windows_parser;
|
using parser = windows_parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace argument_parser::v2 {
|
||||||
|
using parser = windows_parser;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform"
|
#error "Unsupported platform"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#ifndef ARGUMENT_PARSER_HPP
|
#ifndef ARGUMENT_PARSER_HPP
|
||||||
#define ARGUMENT_PARSER_HPP
|
#define ARGUMENT_PARSER_HPP
|
||||||
|
|
||||||
#include <any>
|
#include <any>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <base_convention.hpp>
|
#include <base_convention.hpp>
|
||||||
@@ -158,9 +157,10 @@ namespace argument_parser {
|
|||||||
auto id = find_argument_id(arg);
|
auto id = find_argument_id(arg);
|
||||||
if (id.has_value()) {
|
if (id.has_value()) {
|
||||||
auto value = stored_arguments.find(id.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::any_cast<T>(value->second);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace argument_parser::v2 {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void add_argument(std::unordered_map<add_argument_flags, typed_flag_value<T>> const &argument_pairs) {
|
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) {
|
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) {
|
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() {
|
argument_parser::base_parser &to_v1() {
|
||||||
@@ -91,7 +91,7 @@ namespace argument_parser::v2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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) {
|
void add_argument_impl(ArgsMap const &argument_pairs) {
|
||||||
std::unordered_map<extended_add_argument_flags, bool> found_params{
|
std::unordered_map<extended_add_argument_flags, bool> found_params{
|
||||||
{extended_add_argument_flags::IsTyped, IsTyped}};
|
{extended_add_argument_flags::IsTyped, IsTyped}};
|
||||||
@@ -142,7 +142,7 @@ namespace argument_parser::v2 {
|
|||||||
required);
|
required);
|
||||||
break;
|
break;
|
||||||
case candidate_type::store_other:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("Could not match the arguments against any overload.");
|
throw std::runtime_error("Could not match the arguments against any overload.");
|
||||||
|
|||||||
15
src/main.cpp
15
src/main.cpp
@@ -160,9 +160,16 @@ int v1Examples() {
|
|||||||
return 0;
|
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() {
|
int v2Examples() {
|
||||||
using namespace argument_parser::v2::flags;
|
using namespace argument_parser::v2::flags;
|
||||||
argument_parser::v2::base_parser parser;
|
argument_parser::v2::parser parser;
|
||||||
|
|
||||||
parser.add_argument<std::string>(
|
parser.add_argument<std::string>(
|
||||||
{{ShortArgument, "e"}, {LongArgument, "echo"}, {Action, echo}, {HelpText, "echoes given variable"}});
|
{{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_grep);
|
||||||
|
parser.on_complete(::run_store_point);
|
||||||
|
|
||||||
parser.handle_arguments(conventions);
|
parser.handle_arguments(conventions);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
try {
|
||||||
return v2Examples();
|
return v2Examples();
|
||||||
|
} catch (std::exception const &e) {
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,6 @@ namespace argument_parser {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
argument &corresponding_argument = get_argument(extracted);
|
argument &corresponding_argument = get_argument(extracted);
|
||||||
|
|
||||||
if (corresponding_argument.expects_parameter()) {
|
if (corresponding_argument.expects_parameter()) {
|
||||||
if (convention_type->requires_next_token() && (it + 1) == parsed_arguments.end()) {
|
if (convention_type->requires_next_token() && (it + 1) == parsed_arguments.end()) {
|
||||||
throw std::runtime_error("expected value for argument " + extracted.second);
|
throw std::runtime_error("expected value for argument " + extracted.second);
|
||||||
|
|||||||
@@ -3,26 +3,13 @@
|
|||||||
#include "windows_parser.hpp"
|
#include "windows_parser.hpp"
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
std::string utf8_from_wstring(const std::wstring &w) {
|
using namespace std::string_literals;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct local_free_deleter {
|
struct local_free_deleter {
|
||||||
void operator()(void *ptr) const {
|
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;
|
int argc_w;
|
||||||
std::unique_ptr<LPWSTR[], local_free_deleter> argv_w(CommandLineToArgvW(GetCommandLineW(), &argc_w));
|
std::unique_ptr<LPWSTR[], local_free_deleter> argv_w(CommandLineToArgvW(GetCommandLineW(), &argc_w));
|
||||||
if (argv_w == nullptr) {
|
if (argv_w == nullptr) {
|
||||||
throw std::runtime_error("CommandLineToArgvW failed");
|
throw std::runtime_error("CommandLineToArgvW failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < argc_w; i++) {
|
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]);
|
std::string arg = utf8_from_wstring(argv_w[i]);
|
||||||
parsed_arguments.emplace_back(arg);
|
parsed_arguments.emplace_back(arg);
|
||||||
|
} catch (std::runtime_error e) {
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace argument_parser {
|
namespace argument_parser {
|
||||||
windows_parser::windows_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
|
||||||
|
|
||||||
namespace argument_parser::v2 {
|
namespace argument_parser::v2 {
|
||||||
windows_parser::windows_parser() {
|
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
|
} // namespace argument_parser::v2
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user