| @@ -0,0 +1,2 @@ | |||
| build/ | |||
| .vscode/ | |||
| @@ -0,0 +1,3 @@ | |||
| [submodule "cmake/modules"] | |||
| path = cmake/modules | |||
| url = b3rgmann@git.bergmann89.de:cpp/CmakeModules.git | |||
| @@ -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 ) | |||
| @@ -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. | |||
| @@ -0,0 +1 @@ | |||
| Subproject commit 1e74005bc2f91434fecb2e5f698c21b73f7e3a13 | |||
| @@ -0,0 +1,6 @@ | |||
| #pragma once | |||
| #include "cppargs/option.h" | |||
| #include "cppargs/parser.h" | |||
| #include "cppargs/option.inl" | |||
| @@ -0,0 +1,161 @@ | |||
| #pragma once | |||
| #include <string> | |||
| 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<size_t>(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<typename T_predicate> | |||
| struct predicate_option | |||
| : public option | |||
| { | |||
| public: | |||
| using predicate_type = T_predicate; | |||
| private: | |||
| predicate_type _predicate; | |||
| public: | |||
| template<typename... T_args> | |||
| inline predicate_option( | |||
| const std::string& p_long_name, | |||
| const char p_short_name, | |||
| T_args&&... args); | |||
| virtual void parse(context& c) override; | |||
| }; | |||
| template<typename T_value> | |||
| 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<typename T_predicate> | |||
| 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<predicate_type>; | |||
| return std::make_unique<predicate_option_type>(long_name, short_name, std::forward<predicate_type>(predicate)); | |||
| } | |||
| template<typename T_value> | |||
| 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<value_type>; | |||
| return std::make_unique<reference_option_type>(long_name, short_name, value); | |||
| } | |||
| } | |||
| @@ -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<typename T_predicate> | |||
| template<typename... T_args> | |||
| predicate_option<T_predicate>::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<T_args>(args)...) | |||
| { } | |||
| template<typename T_predicate> | |||
| void predicate_option<T_predicate>::parse(context& c) | |||
| { _predicate(c); } | |||
| } | |||
| @@ -0,0 +1,96 @@ | |||
| #pragma once | |||
| #include <map> | |||
| #include <vector> | |||
| #include <memory> | |||
| #include <cstring> | |||
| #include "option.h" | |||
| namespace cppargs | |||
| { | |||
| struct parser | |||
| { | |||
| private: | |||
| using option_ptr_type = std::unique_ptr<option>; | |||
| using option_vector_type = std::vector<option_ptr_type>; | |||
| using option_map_type = std::map<std::string, option*>; | |||
| private: | |||
| option_ptr_type _default; | |||
| option_vector_type _options; | |||
| option_map_type _map; | |||
| inline void update_map() | |||
| { | |||
| _map.clear(); | |||
| for (auto& o : _options) | |||
| { | |||
| if (!o) | |||
| throw std::runtime_error("expectd option to not be null!"); | |||
| if (o->short_name) | |||
| _map.emplace(std::string("-") + o->short_name, o.get()); | |||
| if (!o->long_name.empty()) | |||
| _map.emplace(std::string("--") + o->long_name, o.get()); | |||
| } | |||
| } | |||
| inline void handle_invalid_arg(context& c) const | |||
| { | |||
| if (_default) | |||
| { | |||
| _default->parse(c); | |||
| } | |||
| else | |||
| { | |||
| throw std::runtime_error(std::string("invalid or unknown argument: ") + c.arg); | |||
| } | |||
| } | |||
| public: | |||
| template<typename... T_option> | |||
| inline parser(option_ptr_type&& default_option, T_option&&... option) | |||
| : _default(std::move(default_option)) | |||
| { | |||
| (void) (int[]) { 0, (_options.emplace_back(std::forward<T_option>(option)), 0)... }; | |||
| update_map(); | |||
| } | |||
| void parse(int argc, char const * argv[]) const | |||
| { | |||
| if (argc <= 0) { | |||
| return; | |||
| } | |||
| context c | |||
| { | |||
| argc, | |||
| argv, | |||
| argv[0], | |||
| }; | |||
| next_result ret; | |||
| std::string key; | |||
| while ((ret = c.next(&key)) != next_result::finished) | |||
| { | |||
| /* move to next option */ | |||
| if ( ret != next_result::option_short | |||
| && ret != next_result::option_long) | |||
| handle_invalid_arg(c); | |||
| /* find option */ | |||
| auto it = _map.find(key); | |||
| if (it == _map.end()) | |||
| { | |||
| handle_invalid_arg(c); | |||
| } | |||
| else | |||
| { | |||
| it->second->parse(c); | |||
| } | |||
| } | |||
| } | |||
| }; | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| # Initialize ###################################################################################### | |||
| Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) | |||
| Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | |||
| Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) | |||
| Set ( CMAKE_CXX_STANDARD 17 ) | |||
| # Project: cppargs ################################################################################ | |||
| Project ( cppargs VERSION 1.0.0.0 LANGUAGES CXX ) | |||
| Set ( CPPARGS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | |||
| Add_Library ( cppargs INTERFACE ) | |||
| Target_Include_Directories ( cppargs | |||
| INTERFACE ${CPPARGS_INCLUDE_DIR} ) | |||
| If ( HAS_PEDANTIC ) | |||
| Pedantic_Apply_Flags ( ALL ) | |||
| EndIf ( ) | |||
| # Optimize | |||
| If ( __COTIRE_INCLUDED ) | |||
| Cotire ( cppargs ) | |||
| EndIf ( ) | |||
| @@ -0,0 +1,35 @@ | |||
| # Initialize ###################################################################################### | |||
| Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) | |||
| Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | |||
| Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) | |||
| Include ( cmake_tests OPTIONAL RESULT_VARIABLE HAS_CMAKE_TESTS ) | |||
| Set ( CMAKE_CXX_STANDARD 17 ) | |||
| # Project: cppargs-test ########################################################################### | |||
| Find_Package ( GTest REQUIRED ) | |||
| Project ( cppargs-test ) | |||
| File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||
| Add_Executable ( cppargs-test EXCLUDE_FROM_ALL ${SOURCE_FILES} ) | |||
| Target_Link_Libraries ( cppargs-test | |||
| cppargs | |||
| GTest::Main ) | |||
| If ( HAS_PEDANTIC ) | |||
| Pedantic_Apply_Flags ( ALL ) | |||
| EndIf ( ) | |||
| # optimization | |||
| If ( HAS_COTIRE ) | |||
| Cotire ( cppargs-test ) | |||
| EndIf ( ) | |||
| # test | |||
| If ( HAS_CMAKE_TESTS ) | |||
| Add_CMake_Test ( NAME cppargs TARGET cppargs-test ) | |||
| Else ( ) | |||
| Add_Test ( NAME cppargs COMMAND cppargs-test ) | |||
| EndIf ( ) | |||
| @@ -0,0 +1,22 @@ | |||
| #include <gtest/gtest.h> | |||
| #include <cppargs.h> | |||
| TEST(cppargs, simple) | |||
| { | |||
| int x; | |||
| cppargs::parser p( | |||
| nullptr, | |||
| cppargs::make_reference_option("index", 'i', x), | |||
| cppargs::make_predicate_option("test", 't', [](auto& c){ | |||
| std::cout << c.arg << std::endl; | |||
| }) | |||
| ); | |||
| std::vector<const char*> args({ | |||
| "/fuu/bar/exe", | |||
| "-i", "6", | |||
| "--test" | |||
| }); | |||
| p.parse(static_cast<int>(args.size()), args.data()); | |||
| } | |||