mirror of
https://github.com/sametersoylu/argument-parser.git
synced 2026-04-13 03:41:18 +00:00
feat: Introduce a modular argument convention system for GNU and Windows styles, add .clang-format, and update CMake configuration to C++17.
This commit is contained in:
12
.clang-format
Normal file
12
.clang-format
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
UseTab: Always
|
||||||
|
TabWidth: 4
|
||||||
|
IndentWidth: 4
|
||||||
|
NamespaceIndentation: All
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
ColumnLimit: 120
|
||||||
|
...
|
||||||
@@ -2,18 +2,18 @@ cmake_minimum_required(VERSION 3.15)
|
|||||||
|
|
||||||
project(argument_parser)
|
project(argument_parser)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_Release ${CMAKE_CURRENT_SOURCE_DIR}/bin/release)
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_Release ${CMAKE_CURRENT_SOURCE_DIR}/bin/release)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_Debug ${CMAKE_CURRENT_SOURCE_DIR}/bin/debug)
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_Debug ${CMAKE_CURRENT_SOURCE_DIR}/bin/debug)
|
||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
include_directories(include)
|
include_directories(src/headers)
|
||||||
include_directories(include/parser)
|
include_directories(src/headers/parser)
|
||||||
include_directories(include/conventions)
|
include_directories(src/headers/conventions)
|
||||||
include_directories(include/conventions/implementations)
|
include_directories(src/headers/conventions/implementations)
|
||||||
include_directories(include/parser/platform_headers)
|
include_directories(src/headers/parser/platform_headers)
|
||||||
include_directories(include/parser/parsing_traits)
|
include_directories(src/headers/parser/parsing_traits)
|
||||||
|
|
||||||
add_executable(test src/main.cpp)
|
add_executable(test src/main.cpp)
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"directory": "/Users/killua/Projects/argument-parser/build",
|
"directory": "C:/Users/samet/Documents/CPP/argparser/argument-parser/build",
|
||||||
"command": "/usr/bin/clang++ -I/Users/killua/Projects/argument-parser/include -I/Users/killua/Projects/argument-parser/include/parser -I/Users/killua/Projects/argument-parser/include/conventions -I/Users/killua/Projects/argument-parser/include/conventions/implementations -I/Users/killua/Projects/argument-parser/include/parser/platform_headers -I/Users/killua/Projects/argument-parser/include/parser/parsing_traits -g -std=gnu++2b -arch arm64 -o CMakeFiles/test.dir/src/main.cpp.o -c /Users/killua/Projects/argument-parser/src/main.cpp",
|
"command": "C:\\PROGRA~2\\MICROS~2\\18\\BUILDT~1\\VC\\Tools\\MSVC\\1450~1.357\\bin\\Hostx64\\x64\\cl.exe /nologo /TP -IC:\\Users\\samet\\Documents\\CPP\\argparser\\argument-parser\\src\\headers -IC:\\Users\\samet\\Documents\\CPP\\argparser\\argument-parser\\src\\headers\\parser -IC:\\Users\\samet\\Documents\\CPP\\argparser\\argument-parser\\src\\headers\\conventions -IC:\\Users\\samet\\Documents\\CPP\\argparser\\argument-parser\\src\\headers\\conventions\\implementations -IC:\\Users\\samet\\Documents\\CPP\\argparser\\argument-parser\\src\\headers\\parser\\platform_headers -IC:\\Users\\samet\\Documents\\CPP\\argparser\\argument-parser\\src\\headers\\parser\\parsing_traits /DWIN32 /D_WINDOWS /GR /EHsc /Zi /Ob0 /Od /RTC1 -std:c++17 -MDd /FoCMakeFiles\\test.dir\\src\\main.cpp.obj /FdCMakeFiles\\test.dir\\ /FS -c C:\\Users\\samet\\Documents\\CPP\\argparser\\argument-parser\\src\\main.cpp",
|
||||||
"file": "/Users/killua/Projects/argument-parser/src/main.cpp",
|
"file": "C:/Users/samet/Documents/CPP/argparser/argument-parser/src/main.cpp",
|
||||||
"output": "/Users/killua/Projects/argument-parser/build/CMakeFiles/test.dir/src/main.cpp.o"
|
"output": "C:/Users/samet/Documents/CPP/argparser/argument-parser/build/CMakeFiles/test.dir/src/main.cpp.obj"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <string>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#ifndef BASE_CONVENTION_HPP
|
|
||||||
#define BASE_CONVENTION_HPP
|
|
||||||
|
|
||||||
namespace argument_parser::conventions {
|
|
||||||
enum class argument_type {
|
|
||||||
SHORT,
|
|
||||||
LONG,
|
|
||||||
POSITIONAL,
|
|
||||||
INTERCHANGABLE,
|
|
||||||
ERROR
|
|
||||||
};
|
|
||||||
|
|
||||||
using parsed_argument = std::pair<argument_type, std::string>;
|
|
||||||
|
|
||||||
class base_convention {
|
|
||||||
public:
|
|
||||||
virtual std::string extract_value(std::string const&) const = 0;
|
|
||||||
virtual parsed_argument get_argument(std::string const&) const = 0;
|
|
||||||
virtual bool requires_next_token() const = 0;
|
|
||||||
virtual std::string name() const = 0;
|
|
||||||
virtual std::string short_prec() const = 0;
|
|
||||||
virtual std::string long_prec() const = 0;
|
|
||||||
protected:
|
|
||||||
base_convention() = default;
|
|
||||||
~base_convention() = default;
|
|
||||||
};
|
|
||||||
using convention = base_convention;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace argument_parser::conventions::helpers {
|
|
||||||
static std::string to_lower(std::string s) {
|
|
||||||
std::transform(s.begin(), s.end(), s.begin(),
|
|
||||||
[](unsigned char c) { return std::tolower(c); });
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string to_upper(std::string s) {
|
|
||||||
std::transform(s.begin(), s.end(), s.begin(),
|
|
||||||
[](unsigned char c) { return std::toupper(c); });
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "base_convention.hpp"
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#ifndef GNU_ARGUMENT_CONVENTION_HPP
|
|
||||||
#define GNU_ARGUMENT_CONVENTION_HPP
|
|
||||||
|
|
||||||
namespace argument_parser::conventions::implementations {
|
|
||||||
|
|
||||||
class gnu_argument_convention : public base_convention {
|
|
||||||
public:
|
|
||||||
parsed_argument get_argument(std::string const& raw) const override {
|
|
||||||
if (raw.starts_with(long_prec()))
|
|
||||||
return {argument_type::LONG, raw.substr(2)};
|
|
||||||
else if (raw.starts_with(short_prec()))
|
|
||||||
return {argument_type::SHORT, raw.substr(1)};
|
|
||||||
else
|
|
||||||
return {argument_type::ERROR, "GNU standard convention does not allow arguments without a preceding dash."};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string extract_value(std::string const& /*raw*/) const override {
|
|
||||||
// In non-equal GNU, value comes in next token
|
|
||||||
throw std::runtime_error("No inline value in standard GNU convention.");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool requires_next_token() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name() const override {
|
|
||||||
return "GNU-style long options";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string short_prec() const override {
|
|
||||||
return "-";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string long_prec() const override {
|
|
||||||
return "--";
|
|
||||||
}
|
|
||||||
|
|
||||||
static gnu_argument_convention instance;
|
|
||||||
private:
|
|
||||||
gnu_argument_convention() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
class gnu_equal_argument_convention : public base_convention {
|
|
||||||
public:
|
|
||||||
parsed_argument get_argument(std::string const& raw) const override {
|
|
||||||
auto pos = raw.find('=');
|
|
||||||
auto arg = pos != std::string::npos ? raw.substr(0, pos) : raw;
|
|
||||||
if (arg.starts_with(long_prec()))
|
|
||||||
return {argument_type::LONG, arg.substr(2) };
|
|
||||||
else if (arg.starts_with(short_prec()))
|
|
||||||
return {argument_type::SHORT, arg.substr(1) };
|
|
||||||
else
|
|
||||||
return {argument_type::ERROR, "GNU standard convention does not allow arguments without a preceding dash."};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string extract_value(std::string const& raw) const override {
|
|
||||||
auto pos = raw.find('=');
|
|
||||||
if (pos == std::string::npos || pos + 1 >= raw.size())
|
|
||||||
throw std::runtime_error("Expected value after '='.");
|
|
||||||
return raw.substr(pos + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool requires_next_token() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name() const override {
|
|
||||||
return "GNU-style long options (equal signed form)";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string short_prec() const override {
|
|
||||||
return "-";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string long_prec() const override {
|
|
||||||
return "--";
|
|
||||||
}
|
|
||||||
|
|
||||||
static gnu_equal_argument_convention instance;
|
|
||||||
private:
|
|
||||||
gnu_equal_argument_convention() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline gnu_argument_convention gnu_argument_convention::instance{};
|
|
||||||
inline gnu_equal_argument_convention gnu_equal_argument_convention::instance{};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace argument_parser::conventions {
|
|
||||||
static inline const implementations::gnu_argument_convention gnu_argument_convention = implementations::gnu_argument_convention::instance;
|
|
||||||
static inline const implementations::gnu_equal_argument_convention gnu_equal_argument_convention = implementations::gnu_equal_argument_convention::instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "base_convention.hpp"
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#ifndef WINDOWS_ARGUMENT_CONVENTION_HPP
|
|
||||||
#define WINDOWS_ARGUMENT_CONVENTION_HPP
|
|
||||||
|
|
||||||
#ifndef ALLOW_DASH_FOR_WINDOWS
|
|
||||||
#define ALLOW_DASH_FOR_WINDOWS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace argument_parser::conventions::implementations {
|
|
||||||
class windows_argument_convention : public base_convention {
|
|
||||||
public:
|
|
||||||
explicit windows_argument_convention(bool accept_dash = true)
|
|
||||||
: accept_dash_(accept_dash) {
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed_argument get_argument(std::string const& raw) const override {
|
|
||||||
if (raw.empty()) {
|
|
||||||
return { argument_type::ERROR, "Empty argument token." };
|
|
||||||
}
|
|
||||||
const char c0 = raw[0];
|
|
||||||
const bool ok_prefix = (c0 == '/') || (accept_dash_ && c0 == '-');
|
|
||||||
if (!ok_prefix) {
|
|
||||||
return { argument_type::ERROR,
|
|
||||||
accept_dash_
|
|
||||||
? "Windows-style expects options to start with '/' (or '-' in compat mode)."
|
|
||||||
: "Windows-style expects options to start with '/'." };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (raw.find_first_of("=:") != std::string::npos) {
|
|
||||||
return { argument_type::ERROR,
|
|
||||||
"Inline values are not allowed in this convention; provide the value in the next token." };
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name = helpers::to_lower(raw.substr(1));
|
|
||||||
if (name.empty()) {
|
|
||||||
return { argument_type::ERROR, "Option name cannot be empty after '/'." };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { argument_type::INTERCHANGABLE, std::move(name) };
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string extract_value(std::string const& /*raw*/) const override {
|
|
||||||
throw std::runtime_error("No inline value; value must be provided in the next token.");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool requires_next_token() const override { return true; }
|
|
||||||
|
|
||||||
std::string name() const override { return "Windows style options (next-token values)"; }
|
|
||||||
std::string short_prec() const override { return accept_dash_ ? "-" : "/"; }
|
|
||||||
std::string long_prec() const override { return "/"; }
|
|
||||||
|
|
||||||
static windows_argument_convention instance;
|
|
||||||
private:
|
|
||||||
bool accept_dash_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class windows_kv_argument_convention : public base_convention {
|
|
||||||
public:
|
|
||||||
explicit windows_kv_argument_convention(bool accept_dash = true)
|
|
||||||
: accept_dash_(accept_dash) {
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed_argument get_argument(std::string const& raw) const override {
|
|
||||||
if (raw.empty()) {
|
|
||||||
return { argument_type::ERROR, "Empty argument token." };
|
|
||||||
}
|
|
||||||
const char c0 = raw[0];
|
|
||||||
const bool ok_prefix = (c0 == '/') || (accept_dash_ && c0 == '-');
|
|
||||||
if (!ok_prefix) {
|
|
||||||
return { argument_type::ERROR,
|
|
||||||
accept_dash_
|
|
||||||
? "Windows-style expects options to start with '/' (or '-' in compat mode)."
|
|
||||||
: "Windows-style expects options to start with '/'." };
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::size_t sep = raw.find_first_of("=:");
|
|
||||||
if (sep == std::string::npos) {
|
|
||||||
return { argument_type::ERROR,
|
|
||||||
"Expected an inline value using '=' or ':' (e.g., /opt=value or /opt:value)." };
|
|
||||||
}
|
|
||||||
if (sep == 1) {
|
|
||||||
return { argument_type::ERROR, "Option name cannot be empty before '=' or ':'." };
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name = helpers::to_lower(raw.substr(1, sep - 1));
|
|
||||||
return { argument_type::INTERCHANGABLE, std::move(name) };
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string extract_value(std::string const& raw) const override {
|
|
||||||
const std::size_t sep = raw.find_first_of("=:");
|
|
||||||
if (sep == std::string::npos || sep + 1 >= raw.size())
|
|
||||||
throw std::runtime_error("Expected a value after '=' or ':'.");
|
|
||||||
return raw.substr(sep + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool requires_next_token() const override { return false; }
|
|
||||||
|
|
||||||
std::string name() const override { return "Windows style options (inline values via '=' or ':')"; }
|
|
||||||
std::string short_prec() const override { return accept_dash_ ? "-" : "/"; }
|
|
||||||
std::string long_prec() const override { return "/"; }
|
|
||||||
|
|
||||||
static windows_kv_argument_convention instance;
|
|
||||||
private:
|
|
||||||
bool accept_dash_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
inline windows_argument_convention windows_argument_convention::instance = windows_argument_convention(bool(ALLOW_DASH_FOR_WINDOWS));
|
|
||||||
inline windows_kv_argument_convention windows_kv_argument_convention::instance = windows_kv_argument_convention(bool(ALLOW_DASH_FOR_WINDOWS));
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace argument_parser::conventions {
|
|
||||||
static inline const implementations::windows_argument_convention windows_argument_convention = implementations::windows_argument_convention::instance;
|
|
||||||
static inline const implementations::windows_kv_argument_convention windows_equal_argument_convention = implementations::windows_kv_argument_convention::instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // WINDOWS_ARGUMENT_CONVENTION_HPP
|
|
||||||
@@ -6,17 +6,17 @@
|
|||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <linux_parser.hpp>
|
#include <linux_parser.hpp>
|
||||||
namespace argument_parser {
|
namespace argument_parser {
|
||||||
using parser = linux_parser;
|
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;
|
||||||
}
|
}
|
||||||
#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;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform"
|
#error "Unsupported platform"
|
||||||
35
src/headers/conventions/base_convention.hpp
Normal file
35
src/headers/conventions/base_convention.hpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#ifndef BASE_CONVENTION_HPP
|
||||||
|
#define BASE_CONVENTION_HPP
|
||||||
|
|
||||||
|
namespace argument_parser::conventions {
|
||||||
|
enum class argument_type { SHORT, LONG, POSITIONAL, INTERCHANGABLE, ERROR };
|
||||||
|
|
||||||
|
using parsed_argument = std::pair<argument_type, std::string>;
|
||||||
|
|
||||||
|
class base_convention {
|
||||||
|
public:
|
||||||
|
virtual std::string extract_value(std::string const &) const = 0;
|
||||||
|
virtual parsed_argument get_argument(std::string const &) const = 0;
|
||||||
|
virtual bool requires_next_token() const = 0;
|
||||||
|
virtual std::string name() const = 0;
|
||||||
|
virtual std::string short_prec() const = 0;
|
||||||
|
virtual std::string long_prec() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
base_convention() = default;
|
||||||
|
~base_convention() = default;
|
||||||
|
};
|
||||||
|
using convention = base_convention;
|
||||||
|
} // namespace argument_parser::conventions
|
||||||
|
|
||||||
|
namespace argument_parser::conventions::helpers {
|
||||||
|
static std::string to_lower(std::string s);
|
||||||
|
|
||||||
|
static std::string to_upper(std::string s);
|
||||||
|
} // namespace argument_parser::conventions::helpers
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "base_convention.hpp"
|
||||||
|
|
||||||
|
#ifndef GNU_ARGUMENT_CONVENTION_HPP
|
||||||
|
#define GNU_ARGUMENT_CONVENTION_HPP
|
||||||
|
|
||||||
|
namespace argument_parser::conventions::implementations {
|
||||||
|
|
||||||
|
class gnu_argument_convention : public base_convention {
|
||||||
|
public:
|
||||||
|
parsed_argument get_argument(std::string const &raw) const override;
|
||||||
|
std::string extract_value(std::string const & /*raw*/) const override;
|
||||||
|
|
||||||
|
bool requires_next_token() const override;
|
||||||
|
|
||||||
|
std::string name() const override;
|
||||||
|
|
||||||
|
std::string short_prec() const override;
|
||||||
|
|
||||||
|
std::string long_prec() const override;
|
||||||
|
|
||||||
|
static gnu_argument_convention instance;
|
||||||
|
|
||||||
|
private:
|
||||||
|
gnu_argument_convention() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class gnu_equal_argument_convention : public base_convention {
|
||||||
|
public:
|
||||||
|
parsed_argument get_argument(std::string const &raw) const override;
|
||||||
|
std::string extract_value(std::string const &raw) const override;
|
||||||
|
bool requires_next_token() const override;
|
||||||
|
std::string name() const override;
|
||||||
|
std::string short_prec() const override;
|
||||||
|
std::string long_prec() const override;
|
||||||
|
static gnu_equal_argument_convention instance;
|
||||||
|
|
||||||
|
private:
|
||||||
|
gnu_equal_argument_convention() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline gnu_argument_convention gnu_argument_convention::instance{};
|
||||||
|
inline gnu_equal_argument_convention gnu_equal_argument_convention::instance{};
|
||||||
|
} // namespace argument_parser::conventions::implementations
|
||||||
|
|
||||||
|
namespace argument_parser::conventions {
|
||||||
|
static const implementations::gnu_argument_convention gnu_argument_convention =
|
||||||
|
implementations::gnu_argument_convention::instance;
|
||||||
|
static const implementations::gnu_equal_argument_convention gnu_equal_argument_convention =
|
||||||
|
implementations::gnu_equal_argument_convention::instance;
|
||||||
|
} // namespace argument_parser::conventions
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "base_convention.hpp"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#ifndef WINDOWS_ARGUMENT_CONVENTION_HPP
|
||||||
|
#define WINDOWS_ARGUMENT_CONVENTION_HPP
|
||||||
|
|
||||||
|
#ifndef ALLOW_DASH_FOR_WINDOWS
|
||||||
|
#define ALLOW_DASH_FOR_WINDOWS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace argument_parser::conventions::implementations {
|
||||||
|
class windows_argument_convention : public base_convention {
|
||||||
|
public:
|
||||||
|
explicit windows_argument_convention(bool accept_dash = true);
|
||||||
|
|
||||||
|
parsed_argument get_argument(std::string const &raw) const override;
|
||||||
|
|
||||||
|
std::string extract_value(std::string const & /*raw*/) const override;
|
||||||
|
|
||||||
|
bool requires_next_token() const override;
|
||||||
|
|
||||||
|
std::string name() const override;
|
||||||
|
|
||||||
|
std::string short_prec() const override;
|
||||||
|
|
||||||
|
std::string long_prec() const override;
|
||||||
|
static windows_argument_convention instance;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool accept_dash_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class windows_kv_argument_convention : public base_convention {
|
||||||
|
public:
|
||||||
|
explicit windows_kv_argument_convention(bool accept_dash = true);
|
||||||
|
parsed_argument get_argument(std::string const &raw) const override;
|
||||||
|
std::string extract_value(std::string const &raw) const override;
|
||||||
|
bool requires_next_token() const override;
|
||||||
|
std::string name() const override;
|
||||||
|
std::string short_prec() const override;
|
||||||
|
std::string long_prec() const override;
|
||||||
|
static windows_kv_argument_convention instance;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool accept_dash_;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline windows_argument_convention windows_argument_convention::instance =
|
||||||
|
windows_argument_convention(bool(ALLOW_DASH_FOR_WINDOWS));
|
||||||
|
inline windows_kv_argument_convention windows_kv_argument_convention::instance =
|
||||||
|
windows_kv_argument_convention(bool(ALLOW_DASH_FOR_WINDOWS));
|
||||||
|
} // namespace argument_parser::conventions::implementations
|
||||||
|
|
||||||
|
namespace argument_parser::conventions {
|
||||||
|
static inline const implementations::windows_argument_convention windows_argument_convention =
|
||||||
|
implementations::windows_argument_convention::instance;
|
||||||
|
static inline const implementations::windows_kv_argument_convention windows_equal_argument_convention =
|
||||||
|
implementations::windows_kv_argument_convention::instance;
|
||||||
|
} // namespace argument_parser::conventions
|
||||||
|
|
||||||
|
#endif // WINDOWS_ARGUMENT_CONVENTION_HPP
|
||||||
14
src/source/conventions/base_convention.cpp
Normal file
14
src/source/conventions/base_convention.cpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#include "base_convention.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace argument_parser::conventions::helpers {
|
||||||
|
static std::string to_lower(std::string s) {
|
||||||
|
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string to_upper(std::string s) {
|
||||||
|
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::toupper(c); });
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
} // namespace argument_parser::conventions::helpers
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#include "gnu_argument_convention.hpp"
|
||||||
|
#include "base_convention.hpp"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
bool starts_with(std::string const &s, std::string const &prefix) {
|
||||||
|
return s.rfind(prefix, 0) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace argument_parser::conventions::implementations {
|
||||||
|
parsed_argument gnu_argument_convention::get_argument(std::string const &raw) const {
|
||||||
|
if (starts_with(raw, long_prec()))
|
||||||
|
return {argument_type::LONG, raw.substr(2)};
|
||||||
|
else if (starts_with(raw, short_prec()))
|
||||||
|
return {argument_type::SHORT, raw.substr(1)};
|
||||||
|
else
|
||||||
|
return {argument_type::ERROR, "GNU standard convention does not allow arguments without a preceding dash."};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gnu_argument_convention::extract_value(std::string const & /*raw*/) const {
|
||||||
|
throw std::runtime_error("No inline value in standard GNU convention.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gnu_argument_convention::requires_next_token() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gnu_argument_convention::name() const {
|
||||||
|
return "GNU-style long options";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gnu_argument_convention::short_prec() const {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gnu_argument_convention::long_prec() const {
|
||||||
|
return "--";
|
||||||
|
}
|
||||||
|
} // namespace argument_parser::conventions::implementations
|
||||||
|
|
||||||
|
namespace argument_parser::conventions::implementations {
|
||||||
|
parsed_argument gnu_equal_argument_convention::get_argument(std::string const &raw) const {
|
||||||
|
auto pos = raw.find('=');
|
||||||
|
auto arg = pos != std::string::npos ? raw.substr(0, pos) : raw;
|
||||||
|
if (starts_with(arg, long_prec()))
|
||||||
|
return {argument_type::LONG, arg.substr(2)};
|
||||||
|
else if (starts_with(arg, short_prec()))
|
||||||
|
return {argument_type::SHORT, arg.substr(1)};
|
||||||
|
else
|
||||||
|
return {argument_type::ERROR, "GNU standard convention does not allow arguments without a preceding dash."};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gnu_equal_argument_convention::extract_value(std::string const &raw) const {
|
||||||
|
auto pos = raw.find('=');
|
||||||
|
if (pos == std::string::npos || pos + 1 >= raw.size())
|
||||||
|
throw std::runtime_error("Expected value after '='.");
|
||||||
|
return raw.substr(pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gnu_equal_argument_convention::requires_next_token() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gnu_equal_argument_convention::name() const {
|
||||||
|
return "GNU-style long options (equal signed form)";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gnu_equal_argument_convention::short_prec() const {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gnu_equal_argument_convention::long_prec() const {
|
||||||
|
return "--";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace argument_parser::conventions::implementations
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#include "windows_argument_convention.hpp"
|
||||||
|
|
||||||
|
namespace argument_parser::conventions::implementations {
|
||||||
|
windows_argument_convention::windows_argument_convention(bool accept_dash) : accept_dash_(accept_dash) {}
|
||||||
|
|
||||||
|
parsed_argument windows_argument_convention::get_argument(std::string const &raw) const {
|
||||||
|
if (raw.empty()) {
|
||||||
|
return {argument_type::ERROR, "Empty argument token."};
|
||||||
|
}
|
||||||
|
const char c0 = raw[0];
|
||||||
|
const bool ok_prefix = (c0 == '/') || (accept_dash_ && c0 == '-');
|
||||||
|
if (!ok_prefix) {
|
||||||
|
return {argument_type::ERROR,
|
||||||
|
accept_dash_ ? "Windows-style expects options to start with '/' (or '-' in compat mode)."
|
||||||
|
: "Windows-style expects options to start with '/'."};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw.find_first_of("=:") != std::string::npos) {
|
||||||
|
return {argument_type::ERROR,
|
||||||
|
"Inline values are not allowed in this convention; provide the value in the next token."};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name = helpers::to_lower(raw.substr(1));
|
||||||
|
if (name.empty()) {
|
||||||
|
return {argument_type::ERROR, "Option name cannot be empty after '/'."};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {argument_type::INTERCHANGABLE, std::move(name)};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string windows_argument_convention::extract_value(std::string const & /*raw*/) const {
|
||||||
|
throw std::runtime_error("No inline value; value must be provided in the next token.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool windows_argument_convention::requires_next_token() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string windows_argument_convention::name() const {
|
||||||
|
return "Windows style options (next-token values)";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string windows_argument_convention::short_prec() const {
|
||||||
|
return accept_dash_ ? "-" : "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string windows_argument_convention::long_prec() const {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace argument_parser::conventions::implementations
|
||||||
|
|
||||||
|
namespace argument_parser::conventions::implementations {
|
||||||
|
windows_kv_argument_convention::windows_kv_argument_convention(bool accept_dash) : accept_dash_(accept_dash) {}
|
||||||
|
|
||||||
|
parsed_argument windows_kv_argument_convention::get_argument(std::string const &raw) const {
|
||||||
|
if (raw.empty()) {
|
||||||
|
return {argument_type::ERROR, "Empty argument token."};
|
||||||
|
}
|
||||||
|
const char c0 = raw[0];
|
||||||
|
const bool ok_prefix = (c0 == '/') || (accept_dash_ && c0 == '-');
|
||||||
|
if (!ok_prefix) {
|
||||||
|
return {argument_type::ERROR,
|
||||||
|
accept_dash_ ? "Windows-style expects options to start with '/' (or '-' in compat mode)."
|
||||||
|
: "Windows-style expects options to start with '/'."};
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t sep = raw.find_first_of("=:");
|
||||||
|
if (sep == std::string::npos) {
|
||||||
|
return {argument_type::ERROR,
|
||||||
|
"Expected an inline value using '=' or ':' (e.g., /opt=value or /opt:value)."};
|
||||||
|
}
|
||||||
|
if (sep == 1) {
|
||||||
|
return {argument_type::ERROR, "Option name cannot be empty before '=' or ':'."};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name = helpers::to_lower(raw.substr(1, sep - 1));
|
||||||
|
return {argument_type::INTERCHANGABLE, std::move(name)};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string windows_kv_argument_convention::extract_value(std::string const &raw) const {
|
||||||
|
const std::size_t sep = raw.find_first_of("=:");
|
||||||
|
if (sep == std::string::npos || sep + 1 >= raw.size())
|
||||||
|
throw std::runtime_error("Expected a value after '=' or ':'.");
|
||||||
|
return raw.substr(sep + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool windows_kv_argument_convention::requires_next_token() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string windows_kv_argument_convention::name() const {
|
||||||
|
return "Windows-style options (inline values via '=' or ':')";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string windows_kv_argument_convention::short_prec() const {
|
||||||
|
return accept_dash_ ? "-" : "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string windows_kv_argument_convention::long_prec() const {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
} // namespace argument_parser::conventions::implementations
|
||||||
Reference in New Issue
Block a user