From 8c344e684be2157474f99bf17f38528245636fce Mon Sep 17 00:00:00 2001 From: bergmann Date: Mon, 6 May 2019 18:13:20 +0200 Subject: [PATCH] * initial commit --- .gitignore | 2 + .gitmodules | 3 + CMakeLists.txt | 15 ++++ LICENSE.txt | 21 +++++ cmake/modules | 1 + include/cppargs.h | 6 ++ include/cppargs/option.h | 161 +++++++++++++++++++++++++++++++++++++ include/cppargs/option.inl | 33 ++++++++ include/cppargs/parser.h | 96 ++++++++++++++++++++++ src/CMakeLists.txt | 24 ++++++ test/CMakeLists.txt | 35 ++++++++ test/cppargs.cpp | 22 +++++ 12 files changed, 419 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 LICENSE.txt create mode 160000 cmake/modules create mode 100644 include/cppargs.h create mode 100644 include/cppargs/option.h create mode 100644 include/cppargs/option.inl create mode 100644 include/cppargs/parser.h create mode 100644 src/CMakeLists.txt create mode 100644 test/CMakeLists.txt create mode 100644 test/cppargs.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6f31401 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +.vscode/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a89889c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cmake/modules"] + path = cmake/modules + url = b3rgmann@git.bergmann89.de:cpp/CmakeModules.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..845d23f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,15 @@ +# Initialize CMake ################################################################################ + +CMake_Minimum_Required ( VERSION 3.5.1 FATAL_ERROR ) +Include ( CTest ) +If ( NOT CMAKE_BUILD_TYPE ) + Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) +EndIf ( NOT CMAKE_BUILD_TYPE ) +Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) + +# Projects ######################################################################################## + +Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) +Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..aa0da62 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Erik Junghanns (aka Bergmann89) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/cmake/modules b/cmake/modules new file mode 160000 index 0000000..1e74005 --- /dev/null +++ b/cmake/modules @@ -0,0 +1 @@ +Subproject commit 1e74005bc2f91434fecb2e5f698c21b73f7e3a13 diff --git a/include/cppargs.h b/include/cppargs.h new file mode 100644 index 0000000..c3c2448 --- /dev/null +++ b/include/cppargs.h @@ -0,0 +1,6 @@ +#pragma once + +#include "cppargs/option.h" +#include "cppargs/parser.h" + +#include "cppargs/option.inl" diff --git a/include/cppargs/option.h b/include/cppargs/option.h new file mode 100644 index 0000000..a7703ea --- /dev/null +++ b/include/cppargs/option.h @@ -0,0 +1,161 @@ +#pragma once + +#include + +namespace cppargs +{ + + enum class next_result + { + finished = 0, //!< context does not have any further arguments + option_short = 1, //!< moving to next argument was successfull (argument starts with - or --) + option_long = 2, //!< moving to next argument was successfull (argument starts with - or --) + argument = 3, //!< moving to next argument was successfull (argument does not starts with - or --) + }; + + struct context + { + int const argc; + char const * const * const argv; + char const * const exe; + char const * arg { nullptr }; + char const * value { nullptr }; + int index { 0 }; + + inline next_result next(std::string* key = nullptr) + { + if (key) + key->clear(); + + if (index + 1 >= argc) + return next_result::finished; + + ++index; + arg = argv[index]; + value = nullptr; + + /* check argument */ + int i = 0; + value = nullptr; + while (arg[i] == '-') + ++i; + + /* parse value */ + if (i == 1) + { + if (key) + *key = std::string("-") + arg[1]; + if (arg[2] != '\0') + value = &arg[2]; + return next_result::option_short; + } + else if (i == 2) + { + auto tmp = strchr(arg, '='); + if (tmp) + { + value = tmp + 1; + if (key) + *key = std::string(arg, static_cast(tmp - arg - 1)); + } + else if (key) + { + *key = arg; + } + return next_result::option_long; + } + else + { + return next_result::argument; + } + } + }; + + struct option + { + public: + const std::string long_name; + const char short_name; + + public: + inline option( + const std::string& p_long_name, + const char p_short_name); + + virtual ~option() = default; + + virtual void parse(context& c) = 0; + }; + + template + struct predicate_option + : public option + { + public: + using predicate_type = T_predicate; + + private: + predicate_type _predicate; + + public: + template + inline predicate_option( + const std::string& p_long_name, + const char p_short_name, + T_args&&... args); + + virtual void parse(context& c) override; + }; + + template + struct reference_option + : public option + { + public: + using value_type = T_value; + + private: + value_type& _value; + + public: + inline reference_option( + const std::string& p_long_name, + const char p_short_name, + value_type& p_value) + : option(p_long_name, p_short_name) + , _value(p_value) + { } + + virtual void parse(context& c) override + { + auto old = c; + auto value = c.value; + if (!value) + { + auto ret = c.next(); + if (ret != next_result::argument) + throw std::runtime_error(std::string("option ") + old.arg + " expected one argument"); + value = c.arg; + } + + std::cout << value << std::endl; + } + }; + + template + constexpr decltype(auto) make_predicate_option(const std::string& long_name, char short_name, T_predicate&& predicate) + { + using predicate_type = T_predicate; + using predicate_option_type = predicate_option; + return std::make_unique(long_name, short_name, std::forward(predicate)); + } + + template + constexpr decltype(auto) make_reference_option(const std::string& long_name, char short_name, T_value& value) + { + using value_type = T_value; + using reference_option_type = reference_option; + return std::make_unique(long_name, short_name, value); + } + +} diff --git a/include/cppargs/option.inl b/include/cppargs/option.inl new file mode 100644 index 0000000..fd53510 --- /dev/null +++ b/include/cppargs/option.inl @@ -0,0 +1,33 @@ +#pragma once + +#include "option.h" + +namespace cppargs +{ + + /* option */ + + option::option( + const std::string& p_long_name, + const char p_short_name) + : long_name (p_long_name) + , short_name(p_short_name) + { } + + /* predicate_option */ + + template + template + predicate_option::predicate_option( + const std::string& p_long_name, + const char p_short_name, + T_args&&... args) + : option(p_long_name, p_short_name) + , _predicate(std::forward(args)...) + { } + + template + void predicate_option::parse(context& c) + { _predicate(c); } + +} diff --git a/include/cppargs/parser.h b/include/cppargs/parser.h new file mode 100644 index 0000000..33ac3e8 --- /dev/null +++ b/include/cppargs/parser.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include +#include + +#include "option.h" + +namespace cppargs +{ + + struct parser + { + private: + using option_ptr_type = std::unique_ptr