├── .clang-format ├── .github └── workflows │ └── codeql.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── include └── parser.hpp └── src ├── CMakeLists.txt ├── example.cpp └── test_parse.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Left 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: true 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: Empty 15 | AllowShortIfStatementsOnASingleLine: true 16 | AllowShortLoopsOnASingleLine: true 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: true 20 | AlwaysBreakTemplateDeclarations: Yes 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: false 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | AfterExternBlock: false 33 | BeforeCatch: false 34 | BeforeElse: false 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | BreakBeforeBinaryOperators: None 40 | BreakBeforeBraces: Attach 41 | BreakBeforeInheritanceComma: false 42 | BreakInheritanceList: BeforeComma 43 | BreakBeforeTernaryOperators: true 44 | BreakConstructorInitializersBeforeComma: true 45 | BreakConstructorInitializers: BeforeComma 46 | BreakAfterJavaFieldAnnotations: false 47 | BreakStringLiterals: true 48 | ColumnLimit: 100 49 | CommentPragmas: '^ IWYU pragma:' 50 | CompactNamespaces: false 51 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 52 | ConstructorInitializerIndentWidth: 4 53 | ContinuationIndentWidth: 4 54 | Cpp11BracedListStyle: true 55 | DerivePointerAlignment: false 56 | DisableFormat: false 57 | ExperimentalAutoDetectBinPacking: false 58 | FixNamespaceComments: true 59 | ForEachMacros: 60 | - foreach 61 | - Q_FOREACH 62 | - BOOST_FOREACH 63 | IncludeBlocks: Preserve 64 | IncludeCategories: 65 | - Regex: '^' 66 | Priority: 2 67 | - Regex: '^<.*\.h>' 68 | Priority: 1 69 | - Regex: '^<.*' 70 | Priority: 2 71 | - Regex: '.*' 72 | Priority: 3 73 | IncludeIsMainRegex: '([-_](test|unittest))?$' 74 | IndentCaseLabels: true 75 | IndentPPDirectives: None 76 | IndentWidth: 4 77 | IndentWrappedFunctionNames: false 78 | JavaScriptQuotes: Leave 79 | JavaScriptWrapImports: true 80 | KeepEmptyLinesAtTheStartOfBlocks: false 81 | MacroBlockBegin: '' 82 | MacroBlockEnd: '' 83 | MaxEmptyLinesToKeep: 1 84 | NamespaceIndentation: None 85 | ObjCBinPackProtocolList: Never 86 | ObjCBlockIndentWidth: 2 87 | ObjCSpaceAfterProperty: false 88 | ObjCSpaceBeforeProtocolList: true 89 | PenaltyBreakAssignment: 2 90 | PenaltyBreakBeforeFirstCallParameter: 1 91 | PenaltyBreakComment: 300 92 | PenaltyBreakFirstLessLess: 120 93 | PenaltyBreakString: 1000 94 | PenaltyBreakTemplateDeclaration: 10 95 | PenaltyExcessCharacter: 1000000 96 | PenaltyReturnTypeOnItsOwnLine: 200 97 | PointerAlignment: Left 98 | RawStringFormats: 99 | - Language: Cpp 100 | Delimiters: 101 | - cc 102 | - CC 103 | - cpp 104 | - Cpp 105 | - CPP 106 | - 'c++' 107 | - 'C++' 108 | CanonicalDelimiter: '' 109 | BasedOnStyle: google 110 | - Language: TextProto 111 | Delimiters: 112 | - pb 113 | - PB 114 | - proto 115 | - PROTO 116 | EnclosingFunctions: 117 | - EqualsProto 118 | - EquivToProto 119 | - PARSE_PARTIAL_TEXT_PROTO 120 | - PARSE_TEST_PROTO 121 | - PARSE_TEXT_PROTO 122 | - ParseTextOrDie 123 | - ParseTextProtoOrDie 124 | CanonicalDelimiter: '' 125 | BasedOnStyle: google 126 | ReflowComments: true 127 | SortIncludes: false 128 | SortUsingDeclarations: false 129 | SpaceAfterCStyleCast: false 130 | SpaceAfterTemplateKeyword: true 131 | SpaceBeforeAssignmentOperators: true 132 | SpaceBeforeCpp11BracedList: false 133 | SpaceBeforeCtorInitializerColon: true 134 | SpaceBeforeInheritanceColon: true 135 | SpaceBeforeParens: ControlStatements 136 | SpaceBeforeRangeBasedForLoopColon: true 137 | SpaceInEmptyParentheses: false 138 | SpacesBeforeTrailingComments: 2 139 | SpacesInAngles: false 140 | SpacesInContainerLiterals: true 141 | SpacesInCStyleCastParentheses: false 142 | SpacesInParentheses: false 143 | SpacesInSquareBrackets: false 144 | Standard: Auto 145 | StatementMacros: 146 | - Q_UNUSED 147 | - QT_REQUIRE_VERSION 148 | TabWidth: 8 149 | UseTab: Never 150 | ... 151 | 152 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [ "master" ] 9 | # schedule: 10 | # - cron: '31 16 * * 5' 11 | workflow_dispatch: 12 | 13 | jobs: 14 | analyze: 15 | name: Analyze 16 | runs-on: ${{ matrix.os }} 17 | strategy: 18 | matrix: 19 | os: [ ubuntu-latest,windows-latest,macos-latest ] 20 | permissions: 21 | actions: read 22 | contents: read 23 | security-events: write 24 | 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@v3 28 | 29 | # Initializes the CodeQL tools for scanning. 30 | - name: Initialize CodeQL 31 | uses: github/codeql-action/init@v2 32 | with: 33 | languages: ${{ matrix.language }} 34 | 35 | - name: ensure the cmake 36 | run: cmake --version 37 | 38 | - name: prepare folder 39 | run: cmake -E make_directory ./CMAKE_DEBUG_PATH 40 | 41 | - name: cmake prepare for compile 42 | working-directory: ./CMAKE_DEBUG_PATH 43 | run: cmake .. -DCMAKE_BUILD_TYPE=Release 44 | 45 | - name: cmake prepare for compile 46 | working-directory: ./CMAKE_DEBUG_PATH 47 | run: cmake --build . --config Release 48 | 49 | - name: cmake ctest 50 | working-directory: ./CMAKE_DEBUG_PATH 51 | run: ctest 52 | 53 | - name: Perform CodeQL Analysis 54 | uses: github/codeql-action/analyze@v2 55 | with: 56 | category: "/language:${{matrix.language}}" 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /src/build 2 | .DS_Store 3 | .idea/ 4 | [Cc]make-*/ 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | project(CMD_LINE_PARSER) 3 | 4 | add_library(CMD_LINE_PARSER INTERFACE) 5 | target_include_directories(CMD_LINE_PARSER 6 | INTERFACE 7 | ${CMAKE_CURRENT_SOURCE_DIR}/include) 8 | 9 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 10 | enable_testing() 11 | add_subdirectory(src) 12 | endif() -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2019 Giulio Ermanno Pibiri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CodeQL](https://github.com/jermp/cmd_line_parser/actions/workflows/codeql.yml/badge.svg)](https://github.com/jermp/cmd_line_parser/actions/workflows/codeql.yml) 2 | 3 | Command Line Parser for C++17 4 | ============================ 5 | 6 | This is a single-header command line parser for C++17. 7 | 8 | It offers, basically, the same funcionalities as other popular libraries, such as [cxxopts](https://github.com/jarro2783/cxxopts), 9 | [cmdline](https://github.com/tanakh/cmdline) and 10 | [argparse](https://github.com/hbristow/argparse), 11 | but relies on the powerful `if constexpr` construct of C++17 instead of dynamic casting. 12 | This results in a very compact code (~150 sloc). 13 | 14 | ### Integration 15 | 16 | Just add the file `include/parser.hpp` to your own project. 17 | 18 | Or if you use git: 19 | 20 | git submodule add https://github.com/jermp/cmd_line_parser.git 21 | 22 | ### Example 23 | 24 | ```C++ 25 | #include 26 | 27 | #include "../include/parser.hpp" 28 | 29 | void configure(cmd_line_parser::parser& parser) { 30 | parser.add("perc", // name 31 | "A percentage value.", // description 32 | "-p", // shorthand 33 | true, // required argument 34 | false // not boolean option (default is false) 35 | ); 36 | parser.add("input_filename", "An input file name.", "-i", true); 37 | 38 | parser.add("output_filename", // name 39 | "An output file name.", // description 40 | "-o", // shorthand 41 | false, false); 42 | parser.add("num_trials", "Number of trials.", "-n", false, false); 43 | 44 | parser.add("sorted", "Sort output.", "--sort", false, 45 | true // boolean option: a value is not expected after the shorthand 46 | ); 47 | parser.add("buffered", "Buffer input.", "--buffer", false, true); 48 | 49 | parser.add("ram", "Amount of ram to use.", "--ram", false, false); 50 | } 51 | 52 | int main(int argc, char** argv) { 53 | // declare the parser 54 | cmd_line_parser::parser parser(argc, argv); 55 | // configure the parser 56 | configure(parser); 57 | 58 | // parse command line and return on failure 59 | bool success = parser.parse(); 60 | if (!success) return 1; 61 | 62 | // now get some variables 63 | auto perc = parser.get("perc"); // deduced type is float 64 | auto input_filename = // deduced type is std::string 65 | parser.get("input_filename"); 66 | auto sorted_output = parser.get("sorted"); // deduced type is bool 67 | auto buffered_input = parser.get("buffered"); // deduced type is bool 68 | 69 | size_t ram = 999; // some default value 70 | if (parser.parsed("ram")) { 71 | ram = parser.get("ram"); // deduced type is size_t 72 | } 73 | 74 | std::cout << "perc: " << perc << std::endl; 75 | std::cout << "input_filename: " << input_filename << std::endl; 76 | std::cout << "sorted_output: " << sorted_output << std::endl; 77 | std::cout << "buffered_input: " << buffered_input << std::endl; 78 | std::cout << "ram: " << ram << std::endl; 79 | 80 | try { 81 | auto val = parser.get("bar"); // fail: no name 'bar' was specified 82 | (void)val; // shut up, compiler! 83 | } catch (std::runtime_error const& e) { 84 | std::cerr << e.what() << std::endl; 85 | return 1; 86 | } 87 | return 0; 88 | } 89 | ``` 90 | 91 | To compile and run the example, do as follows. 92 | 93 | cd src 94 | mkdir -p build 95 | cd build 96 | cmake .. 97 | make 98 | ./example 99 | 100 | Also run `./test_parse` for some testing. 101 | 102 | 103 | ### Interface 104 | 105 | ```C++ 106 | /* Constructor. */ 107 | parser(int argc, char** argv); 108 | 109 | /* Parse command line; return false on failure. */ 110 | bool parse(); 111 | 112 | /* Print help message. */ 113 | void help() const; 114 | 115 | /* Add an argument with a name, a description, and a shorthand. 116 | Return false if an argument with the same name already exists. 117 | The last two boolean parameters are used to specify if the argument 118 | is to be required and to be considered a boolean argument (no value after 119 | the shorthand). */ 120 | bool add(std::string const& name, std::string const& descr, 121 | std::string const& shorthand, 122 | bool is_required, bool is_boolean = false); 123 | 124 | /* Return true is an option with the given name was parsed; false otherwise. */ 125 | bool parsed(std::string const& name) const; 126 | 127 | /* Get a variable of type T by name. 128 | It throws an exception if an argument with the specified name 129 | is not found. */ 130 | template 131 | T get(std::string const& name) const; 132 | ``` 133 | -------------------------------------------------------------------------------- /include/parser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace cmd_line_parser { 13 | 14 | struct parser { 15 | parser(int argc, char** argv) 16 | : m_argc(argc) 17 | , m_argv(argv) 18 | , m_required(0) {} 19 | 20 | struct cmd { 21 | std::string shorthand, value, descr; 22 | bool is_required, is_boolean; 23 | }; 24 | 25 | bool parse() { 26 | assert(m_argc > 0); 27 | if (m_argc - 1 < m_required) return abort(); 28 | 29 | int num_required = 0; 30 | std::unordered_set parsed_shorthands; 31 | parsed_shorthands.reserve(m_argc); 32 | 33 | for (int i = 1; i != m_argc; ++i) { 34 | std::string parsed(m_argv[i]); 35 | if (parsed == "-h" || parsed == "--help") return abort(); 36 | int id = 0; 37 | if (const auto it = m_shorthands.find(parsed); it == m_shorthands.end()) { 38 | std::cerr << "== error: shorthand '" + parsed + "' not found" << std::endl; 39 | return abort(); 40 | } else { 41 | if (const auto it = parsed_shorthands.find(parsed); it != parsed_shorthands.end()) { 42 | std::cerr << "== error: shorthand '" + parsed + "' already parsed" << std::endl; 43 | return abort(); 44 | } 45 | parsed_shorthands.emplace(parsed); 46 | id = (*it).second; 47 | } 48 | assert(static_cast(id) < m_names.size()); 49 | auto const& name = m_names[id]; 50 | auto& cmd = m_cmds[name]; 51 | if (cmd.is_required) num_required += 1; 52 | if (cmd.is_boolean) { 53 | parsed = "true"; 54 | } else { 55 | ++i; 56 | if (i == m_argc) { return abort(); } 57 | parsed = m_argv[i]; 58 | } 59 | cmd.value = parsed; 60 | } 61 | 62 | if (num_required != m_required) return abort(); 63 | 64 | return true; 65 | } 66 | 67 | void help() const { 68 | std::cerr << "Usage: " << m_argv[0] << " [-h,--help]"; 69 | const auto print = [this](bool with_description) { 70 | for (size_t i = 0; i != m_names.size(); ++i) { 71 | auto const& cmd = m_cmds.at(m_names[i]); 72 | std::cerr << " [" << cmd.shorthand; 73 | if (!cmd.is_boolean) std::cerr << " " << m_names[i]; 74 | std::cerr << "]"; 75 | if (with_description) { 76 | std::cerr << "\n\t" << (cmd.is_required ? "REQUIRED: " : "") << cmd.descr 77 | << "\n\n"; 78 | } 79 | } 80 | }; 81 | print(false); 82 | std::cerr << "\n\n"; 83 | print(true); 84 | std::cerr << " [-h,--help]\n\tPrint this help text and silently exits." << std::endl; 85 | } 86 | 87 | bool add(std::string const& name, std::string const& descr, std::string const& shorthand, 88 | bool is_required, bool is_boolean = false) { 89 | bool ret = m_cmds 90 | .emplace(name, cmd{shorthand, is_boolean ? "false" : "", descr, is_required, 91 | is_boolean}) 92 | .second; 93 | if (ret) { 94 | if (is_required) m_required += 1; 95 | m_names.push_back(name); 96 | m_shorthands.emplace(shorthand, m_names.size() - 1); 97 | } 98 | return ret; 99 | } 100 | 101 | template 102 | T get(std::string const& name) const { 103 | auto it = m_cmds.find(name); 104 | if (it == m_cmds.end()) throw std::runtime_error("error: '" + name + "' not found"); 105 | auto const& value = (*it).second.value; 106 | return parse(value); 107 | } 108 | 109 | bool parsed(std::string const& name) const { 110 | auto it = m_cmds.find(name); 111 | if (it == m_cmds.end()) return false; 112 | auto const& cmd = (*it).second; 113 | if (cmd.is_boolean) { 114 | if (cmd.value == "true") return true; 115 | if (cmd.value == "false") return false; 116 | assert(false); // should never happen 117 | } 118 | return cmd.value != ""; 119 | } 120 | 121 | template 122 | T parse(std::string const& value) const { 123 | if constexpr (std::is_same::value) { 124 | return value; 125 | } else if constexpr (std::is_same::value || std::is_same::value || 126 | std::is_same::value) { 127 | return value.front(); 128 | } else if constexpr (std::is_same::value || std::is_same::value) { 129 | return std::strtol(value.c_str(), nullptr, 10); 130 | } else if constexpr (std::is_same::value || 131 | std::is_same::value) { 132 | return std::strtoul(value.c_str(), nullptr, 10); 133 | } else if constexpr (std::is_same::value || 134 | std::is_same::value) { 135 | return std::strtoll(value.c_str(), nullptr, 10); 136 | } else if constexpr (std::is_same::value || 137 | std::is_same::value) { 138 | return std::strtoull(value.c_str(), nullptr, 10); 139 | } else if constexpr (std::is_same::value || std::is_same::value || 140 | std::is_same::value) { 141 | return std::strtod(value.c_str(), nullptr); 142 | } else if constexpr (std::is_same::value) { 143 | std::istringstream stream(value); 144 | bool ret; 145 | if (value == "true" || value == "false") { 146 | stream >> std::boolalpha >> ret; 147 | } else { 148 | stream >> std::noboolalpha >> ret; 149 | } 150 | return ret; 151 | } 152 | assert(false); // should never happen 153 | throw std::runtime_error("unsupported type"); 154 | } 155 | 156 | private: 157 | int m_argc; 158 | char** m_argv; 159 | int m_required; 160 | std::unordered_map m_cmds; 161 | std::unordered_map m_shorthands; 162 | std::vector m_names; 163 | 164 | bool abort() const { 165 | help(); 166 | return false; 167 | } 168 | }; 169 | 170 | } // namespace cmd_line_parser 171 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(CMD_PARSER) 3 | set(CMAKE_CXX_STANDARD 17) 4 | 5 | if (NOT CMAKE_BUILD_TYPE) 6 | set(CMAKE_BUILD_TYPE "Release") 7 | endif () 8 | MESSAGE(STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE}) 9 | 10 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) 11 | 12 | if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") 13 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 14 | endif () 15 | if (UNIX) 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") 18 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") 19 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-missing-braces") 20 | if (USE_SANITIZERS) 21 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") 22 | endif () 23 | 24 | endif () 25 | 26 | enable_testing() 27 | 28 | add_executable(example ${CMAKE_CURRENT_SOURCE_DIR}/example.cpp) 29 | add_executable(test_parse ${CMAKE_CURRENT_SOURCE_DIR}/test_parse.cpp) 30 | 31 | add_test(test_parse_CTEST ${CMAKE_BINARY_DIR}/test_parse) 32 | -------------------------------------------------------------------------------- /src/example.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/parser.hpp" 2 | 3 | void configure(cmd_line_parser::parser& parser) { 4 | parser.add("perc", // name 5 | "A percentage value.", // description 6 | "-p", // shorthand 7 | true, // required argument 8 | false // not boolean option (default is false) 9 | ); 10 | parser.add("input_filename", "An input file name.", "-i", true); 11 | 12 | parser.add("output_filename", // name 13 | "An output file name.", // description 14 | "-o", // shorthand 15 | false, false); 16 | parser.add("num_trials", "Number of trials.", "-n", false, false); 17 | 18 | parser.add("sorted", "Sort output.", "--sort", false, 19 | true // boolean option: a value is not expected after the shorthand 20 | ); 21 | parser.add("buffered", "Buffer input.", "--buffer", false, true); 22 | 23 | parser.add("ram", "Amount of ram to use.", "--ram", false, false); 24 | } 25 | 26 | int main(int argc, char** argv) { 27 | // declare the parser 28 | cmd_line_parser::parser parser(argc, argv); 29 | // configure the parser 30 | configure(parser); 31 | 32 | // parse command line and return on failure 33 | bool success = parser.parse(); 34 | if (!success) return 1; 35 | 36 | // now get some variables 37 | auto perc = parser.get("perc"); // deduced type is float 38 | auto input_filename = parser.get("input_filename"); // deduced type is std::string 39 | auto sorted_output = parser.get("sorted"); // deduced type is bool 40 | auto buffered_input = parser.get("buffered"); // deduced type is bool 41 | 42 | size_t ram = 999; // some default value 43 | if (parser.parsed("ram")) { 44 | ram = parser.get("ram"); // deduced type is size_t 45 | } 46 | 47 | std::cout << "perc: " << perc << std::endl; 48 | std::cout << "input_filename: " << input_filename << std::endl; 49 | std::cout << "sorted_output: " << sorted_output << std::endl; 50 | std::cout << "buffered_input: " << buffered_input << std::endl; 51 | std::cout << "ram: " << ram << std::endl; 52 | 53 | try { 54 | auto val = parser.get("bar"); // fail: no name 'bar' was specified 55 | (void)val; // shut up, compiler! 56 | } catch (std::runtime_error const& e) { 57 | std::cerr << e.what() << std::endl; 58 | return 1; 59 | } 60 | return 0; 61 | } -------------------------------------------------------------------------------- /src/test_parse.cpp: -------------------------------------------------------------------------------- 1 | #ifdef __GNUC__ 2 | #include 3 | #endif 4 | 5 | #include "../include/parser.hpp" 6 | 7 | std::string demangle(std::string const& name) { 8 | #ifdef __GNUC__ 9 | int status = 0; 10 | char* tmp = abi::__cxa_demangle(name.c_str(), 0, 0, &status); 11 | std::string demagled(tmp); 12 | free(tmp); 13 | return demagled; 14 | #else 15 | return name; 16 | #endif 17 | } 18 | 19 | template 20 | void info(T val) { 21 | std::cout << "value: " << val << "; type: " << demangle(typeid(val).name()) << std::endl; 22 | } 23 | 24 | template 25 | void test(cmd_line_parser::parser const& parser, std::string const& value) { 26 | info(parser.parse(value)); 27 | } 28 | 29 | int main(int argc, char** argv) { 30 | cmd_line_parser::parser parser(argc, argv); 31 | 32 | test(parser, "a"); 33 | test(parser, "a"); 34 | test(parser, "a"); 35 | 36 | test(parser, "-2423"); 37 | test(parser, "-93811"); 38 | test(parser, "-8284239"); 39 | 40 | test(parser, "1452"); 41 | test(parser, "1841"); 42 | test(parser, "82757188104"); 43 | 44 | test(parser, "234.2"); 45 | test(parser, "0.11"); 46 | test(parser, "-22.1111"); 47 | 48 | test(parser, "true"); 49 | test(parser, "false"); 50 | 51 | // not supported: test(parser, "c"); 52 | 53 | return 0; 54 | } --------------------------------------------------------------------------------