├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── appveyor.yml ├── docs └── doxyfile ├── examples ├── Makefile ├── actions.cpp ├── align.cpp ├── alternatives.cpp ├── annotate.cpp ├── argv0.cpp ├── commands.cpp ├── complex_nesting.cpp ├── convert.cpp ├── counter.cpp ├── doc_filter.cpp ├── documentation.cpp ├── finder.cpp ├── float_vector.cpp ├── groups.cpp ├── joinable_flags.cpp ├── model.cpp ├── naval_fate.cpp ├── nested_alternatives.cpp ├── numbers.cpp ├── options.cpp ├── options_values.cpp ├── parsing.cpp ├── positional_values.cpp ├── repeatable.cpp ├── required_flags.cpp ├── sanity.cpp ├── send.cpp ├── simplify.cpp ├── switches.cpp ├── tagnames.cpp ├── text_formatting.cpp ├── timing.cpp └── transform.cpp ├── include └── clipp.h └── test ├── CMakeLists.txt ├── actions_test.cpp ├── alternative_groups_test.cpp ├── alternative_options_test.cpp ├── alternative_required_test.cpp ├── blocking_test01.cpp ├── blocking_test02.cpp ├── blocking_test03.cpp ├── blocking_test04.cpp ├── blocking_test05.cpp ├── blocking_test06.cpp ├── blocking_test07.cpp ├── blocking_test08.cpp ├── blocking_test09.cpp ├── blocking_test10.cpp ├── documentation_test.cpp ├── empty_args.cpp ├── flag_param_factories_test.cpp ├── joined_flags_test1.cpp ├── joined_flags_test2.cpp ├── joined_flags_test3.cpp ├── joined_flags_test4.cpp ├── joined_flags_test5.cpp ├── joined_flags_test6.cpp ├── joined_params_test1.cpp ├── joined_params_test2.cpp ├── joined_sequence_test.cpp ├── mixed_params_test.cpp ├── nesting_test.cpp ├── options_test.cpp ├── prefix_free_test.cpp ├── prefix_test.cpp ├── repeatability_test.cpp ├── repeatable_alternatives_test.cpp ├── required_params_test1.cpp ├── required_params_test2.cpp ├── run_tests.py ├── testing.h ├── usage_lines_test.cpp ├── values_conversion_test.cpp ├── values_filter_test.cpp └── values_sequencing_test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | /build* 2 | /dev 3 | /issues 4 | /examples/* 5 | !/examples/*.cpp 6 | !/examples/Makefile 7 | !/examples/runall 8 | /docs/* 9 | !/docs/doxyfile 10 | .settings 11 | .project 12 | .cproject 13 | .pydevproject 14 | tags 15 | *.out 16 | *.json 17 | *.exe 18 | *.o 19 | 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: false 3 | language: cpp 4 | 5 | 6 | matrix: 7 | include: 8 | - env: COMPILER=g++-5 TEST_FLAGS="-c gcc" LIBCXX=NO 9 | addons: 10 | apt: 11 | sources: ["ubuntu-toolchain-r-test"] 12 | packages: ["g++-5"] 13 | 14 | - env: COMPILER=g++-6 TEST_FLAGS="-c gcc" LIBCXX=NO 15 | addons: 16 | apt: 17 | sources: ["ubuntu-toolchain-r-test"] 18 | packages: ["g++-6"] 19 | 20 | - env: COMPILER=g++-7 TEST_FLAGS="-c gcc --valgrind" LIBCXX=NO 21 | addons: 22 | apt: 23 | sources: ["ubuntu-toolchain-r-test"] 24 | packages: ["g++-7", "valgrind"] 25 | 26 | - env: COMPILER=g++-8 TEST_FLAGS="-c gcc" LIBCXX=NO 27 | addons: 28 | apt: 29 | sources: ["ubuntu-toolchain-r-test"] 30 | packages: ["g++-8", "valgrind"] 31 | 32 | # - env: COMPILER=clang++-3.8 TEST_FLAGS="-c clang" LIBCXX=NO 33 | # addons: 34 | # apt: 35 | # sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-precise-3.8"] 36 | # packages: ["clang-3.8", "g++-6"] 37 | 38 | # - env: COMPILER=clang++-3.9 TEST_FLAGS="-c clang" LIBCXX=NO 39 | # addons: 40 | # apt: 41 | # sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-3.9"] 42 | # packages: ["clang-3.9", "g++-6"] 43 | 44 | # - env: COMPILER=clang++-4.0 TEST_FLAGS="-c clang" LIBCXX=NO 45 | # addons: 46 | # apt: 47 | # sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-4.0"] 48 | # packages: ["clang-4.0", "g++-6"] 49 | 50 | # - env: COMPILER=clang++-5.0 TEST_FLAGS="-c clang --valgrind" LIBCXX=NO 51 | # addons: 52 | # apt: 53 | # sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-5.0"] 54 | # packages: ["clang-5.0", "g++-6", "valgrind"] 55 | 56 | 57 | install: 58 | - if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi 59 | - ${CXX} --version 60 | 61 | script: 62 | - cd test && ./run_tests.py $TEST_FLAGS 63 | 64 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(clipp 3 | VERSION 1.2.3 4 | LANGUAGES CXX) 5 | 6 | include(GNUInstallDirs) 7 | set(CMAKE_VERBOSE_MAKEFILE ON) 8 | 9 | message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") 10 | add_library(${PROJECT_NAME} INTERFACE) 11 | add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) 12 | target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_11) 13 | target_include_directories(${PROJECT_NAME} INTERFACE 14 | $ 15 | $ 16 | ) 17 | 18 | set(CONFIG_VERSION_FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake) 19 | include(CMakePackageConfigHelpers) 20 | write_basic_package_version_file( 21 | ${CONFIG_VERSION_FILE} COMPATIBILITY AnyNewerVersion 22 | ) 23 | 24 | install(DIRECTORY include/ 25 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 26 | FILES_MATCHING PATTERN "*.h" 27 | ) 28 | install(TARGETS ${PROJECT_NAME} 29 | EXPORT ${PROJECT_NAME}-config 30 | ) 31 | install(EXPORT ${PROJECT_NAME}-config 32 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME} 33 | NAMESPACE ${PROJECT_NAME}:: 34 | ) 35 | install(FILES ${CONFIG_VERSION_FILE} 36 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME} 37 | ) 38 | 39 | option(BUILD_TESTING "Do not build tests by default" OFF) 40 | include(CTest) 41 | if(BUILD_TESTING AND ${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR}) 42 | add_subdirectory(test) 43 | endif() 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 André Müller; foss@andremueller-online.de 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | 3 | # branches: 4 | # only: 5 | # - master 6 | # - production 7 | # except: 8 | # - gh-pages 9 | 10 | image: Visual Studio 2017 11 | 12 | platform: 13 | - x64 14 | 15 | clone_folder: c:\projects\clipp 16 | 17 | install: 18 | - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" 19 | 20 | build: off 21 | 22 | test_script: 23 | - cd test 24 | - python run_tests.py -c msvc --clean 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean 2 | 3 | CXX = g++ 4 | FILTER = * 5 | INCLUDE = ../include 6 | SOURCES = $(wildcard $(FILTER).cpp) 7 | EXECS = $(notdir $(SOURCES:.cpp=)) 8 | FLAGS = -I $(INCLUDE) -std=c++11 -Wall -Wextra -Wpedantic -g -O0 9 | 10 | .PHONY: all clean 11 | 12 | all: $(EXECS) 13 | 14 | clean: 15 | find -type f -not -name "*.cpp" -not -name "Makefile" -not -name "runall" | xargs rm 16 | 17 | % : %.cpp $(INCLUDE)/clipp.h 18 | $(CXX) $(FLAGS) -o $@ $< 19 | -------------------------------------------------------------------------------- /examples/actions.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | 23 | bool a = false, b = false; 24 | int i = 1, n = 0, m = 0; 25 | float x = 0.0f; 26 | 27 | auto cli = ( //INFORMAL description 28 | option("-a").set(a), //if(found("-a")) a = true; 29 | option("-b") >> b, //if(found("-b")) b = true; 30 | option("--toggle").call(flip(b)), //if(found("--toggle")) flip(b); 31 | 32 | //if(found("-z")) call_lambda("-z"); 33 | option("-y").call([](const char* s) { cout << s << '\n'; }), 34 | 35 | //using 'operator()' instead of 'call' 36 | //if(found("bob")) call_lambda("bob"); 37 | option("bob")([](std::string s) { cout << s; }), 38 | 39 | //for_each_occurence("-x arg", call_lambda(arg)); 40 | option("-x") & values("X")([&](const char* s) { x = std::stof(s); }), 41 | 42 | //if(parsing_error_on("-z") call_lambda(get_errors()) 43 | required("-z").if_missing([](){ cout << "-z is missing\n"; }), 44 | 45 | option("--all") 46 | >> []() { cout << "found --all\n"; } 47 | >> [](const char* s) { cout << "found flag " << s << '\n'; }, 48 | 49 | value("n").set(n), //n = std::atoi(arg); 50 | option("-i") & value("#",i), //if(found("-i arg")) i = std::atoi(arg); 51 | option("-1").set(m,1), //if(found("-1")) m = 1; 52 | option("-2").set(m,2) //if(found("-2")) m = 2; 53 | ); 54 | 55 | 56 | parse(argc, argv, cli); 57 | 58 | } 59 | -------------------------------------------------------------------------------- /examples/align.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | 22 | enum class imode { file, args, stdio, random }; 23 | enum class omode { file, stdio }; 24 | auto input = imode::file; 25 | auto output = omode::stdio; 26 | std::int64_t minlen = 256; 27 | std::int64_t maxlen = 1024; 28 | std::string query, subject; 29 | std::string outfile; 30 | std::vector wrong; 31 | 32 | auto cli = ( 33 | (option("-o", "--out").set(output,omode::file) & 34 | value("file", outfile)) % "write results to file" 35 | , 36 | "read sequences from input files" % ( 37 | command("-i", "--in"), 38 | value("query file", query), 39 | value("subject file", subject) 40 | ) | 41 | "specify sequences on the command line" % ( 42 | command("-a", "--args").set(input,imode::args), 43 | value("query string", query), 44 | value("subject string", subject) 45 | ) | 46 | "generate random input sequences" % ( 47 | command("-r", "--rand").set(input,imode::random), 48 | opt_integer("min len", minlen) & 49 | opt_integer("max len", maxlen) 50 | ) | ( 51 | "read sequences from stdin" % 52 | command("-").set(input,imode::stdio) 53 | ), 54 | any_other(wrong) 55 | ); 56 | 57 | 58 | if(!parse(argc,argv, cli) || !wrong.empty()) { 59 | if(!wrong.empty()) { 60 | std::cout << "Unknown command line arguments:\n"; 61 | for(const auto& a : wrong) std::cout << "'" << a << "'\n"; 62 | std::cout << '\n'; 63 | } 64 | std::cout << make_man_page(cli, argv[0]) << '\n'; 65 | return 0; 66 | } 67 | 68 | switch(input) { 69 | default: 70 | case imode::file: /* ... */ break; 71 | case imode::args: /* ... */ break; 72 | case imode::stdio: /* ... */ break; 73 | case imode::random: /* ... */ break; 74 | } 75 | 76 | switch(output) { 77 | default: 78 | case omode::stdio: /* ... */ break; 79 | case omode::file: /* ... */ break; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /examples/alternatives.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | 23 | std::vector files; 24 | std::string expr; 25 | bool ifany = false, ifall = false; 26 | 27 | auto cli = ( 28 | values("file", files) % "input filenames", 29 | (required("-s") & value("expr", expr)) % "string to look for", 30 | option("any").set(ifany) % "report as soon as any matches" | 31 | option("all").set(ifall) % "report only if all match" 32 | ); 33 | 34 | if(parse(argc, argv, cli)) { 35 | cout << "find '" << expr << "' in files: "; 36 | for(const auto& f : files) { cout << "'" << f << "' "; } cout << '\n'; 37 | if(ifany) cout << "using 'any' mode\n"; 38 | if(ifall) cout << "using 'all' mode\n"; 39 | } 40 | else { 41 | cout << make_man_page(cli, argv[0]) << '\n'; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /examples/annotate.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | auto is_char = [](const std::string& arg) { 23 | return arg.size() == 1 && std::isalpha(arg[0]); 24 | }; 25 | 26 | char lbl = ' '; 27 | auto cli = ( 28 | command("auto").set(lbl, '_') | 29 | ( command("label"), value(is_char, "character", lbl) ) 30 | ); 31 | 32 | if(parse(argc, argv, cli)) { 33 | cout << "Label: " << lbl << '\n'; 34 | } 35 | else { 36 | cout << "Usage:\n" << usage_lines(cli,argv[0]) << '\n'; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/argv0.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | 23 | std::string progcall; 24 | bool x = false; 25 | bool y = false; 26 | 27 | auto cli = ( 28 | value("", progcall), 29 | option("-x").set(x), 30 | option("-y").set(y) 31 | ); 32 | 33 | //parse all args including argv[0] 34 | if(parse(argv, argv+argc, cli)) { 35 | cout << "program call: " << progcall << '\n'; 36 | if(x) cout << "x\n"; 37 | if(y) cout << "y\n"; 38 | } else { 39 | cout << "Usage:\n" << usage_lines(cli,argv[0]) << '\n'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/commands.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | std::string fname; 23 | std::string enc = "utf8"; 24 | 25 | auto cli = ( 26 | command("new"), 27 | value("filename", fname), 28 | (option("-e", "--encoding") & value("enc", enc)).doc("'utf8' or 'cp1252', default is " + enc) 29 | 30 | ); 31 | 32 | if(parse(argc, argv, cli)) { 33 | cout << "making file " << fname << " with encoding " << enc << '\n'; 34 | } 35 | else { 36 | cout << "Usage:\n" << usage_lines(cli,argv[0]) << '\n'; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/complex_nesting.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | using std::string; 23 | 24 | auto copyMode = "copy mode:" % ( 25 | command("copy") | command("move"), 26 | option("--all") % "copy all", 27 | option("--replace") % "replace existing files", 28 | option("-f", "--force") % "don't ask for confirmation" 29 | ); 30 | 31 | auto compareMode = "compare mode:" % ( 32 | command("compare"), 33 | (command("date") | command("content")), 34 | option("-b", "--binary") % "compare files byte by byte", 35 | option("-q", "--quick") % "use heuristics for faster comparison" 36 | ); 37 | 38 | auto mergeAlgo = ( 39 | command("diff") % "merge using diff" | 40 | command("patch") % "merge using patch" | 41 | ( command("content") % "merge based on content", 42 | "content based merge options:" % ( 43 | option("--git-style") % "emulate git's merge behavior", 44 | option("-m", "--marker") & value("marker") % "merge marker symbol" 45 | ) 46 | ) 47 | ); 48 | 49 | auto mergeMode = "merge mode:" % ( 50 | command("merge"), 51 | mergeAlgo, 52 | required("-o") & value("outdir") % "target directory for merge result", 53 | option("--show-conflicts") % "show merge conflicts during run" 54 | ); 55 | 56 | auto firstOpt = "user interface options:" % ( 57 | option("-v", "--verbose") % "show detailed output", 58 | option("-i", "--interactive") % "use interactive mode" 59 | ); 60 | auto lastOpt = "mode-independent options:" % ( 61 | values("files") % "input files", 62 | option("-r", "--recursive") % "descend into subdirectories", 63 | option("-h", "--help") % "show help" 64 | ); 65 | 66 | auto cli = ( 67 | firstOpt, 68 | copyMode | compareMode | mergeMode | command("list"), 69 | lastOpt 70 | ); 71 | 72 | if(parse(argc, argv, cli)) { 73 | // program logic... 74 | } else { 75 | auto fmt = doc_formatting{}.doc_column(31).last_column(80); 76 | cout << make_man_page(cli, argv[0], fmt) << '\n'; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /examples/convert.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include "clipp.h" 13 | 14 | 15 | int main(int argc, char* argv[]) 16 | { 17 | using namespace clipp; 18 | using std::cout; 19 | 20 | bool rec = false, utf16 = false; 21 | std::string infile = ""; 22 | std::string fmt = "csv"; 23 | 24 | auto cli = ( 25 | value("input file", infile), 26 | option("-r", "--recursive").set(rec).doc("convert files recursively"), 27 | option("-o") & value("output format", fmt), 28 | option("-utf16").set(utf16).doc("use UTF-16 encoding") 29 | ); 30 | 31 | if(!parse(argc, argv, cli)) { 32 | cout << make_man_page(cli, "convert"); 33 | } 34 | else { 35 | cout << "input file: " << infile << '\n' 36 | << "format: " << fmt << '\n' 37 | << "recursive: " << (rec ? "yes\n" : "no\n") 38 | << "UTF-16: " << (utf16 ? "yes\n" : "no\n"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/counter.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | int as = 0; 23 | int bs = 0; 24 | 25 | auto cli = joinable( 26 | repeatable( 27 | option("a")([&]{++as;}) | 28 | option("b")([&]{++bs;}) 29 | ) 30 | ); 31 | 32 | if(parse(argc, argv, cli)) { 33 | cout << "as: " << as << '\n'; 34 | cout << "bs: " << bs << '\n'; 35 | } else { 36 | cout << "Usage:\n" << usage_lines(cli, argv[0]) << '\n'; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /examples/doc_filter.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include "clipp.h" 13 | 14 | 15 | int main(int argc, char* argv[]) 16 | { 17 | using namespace clipp; 18 | using std::cout; 19 | 20 | bool rec = false, utf16 = false; 21 | std::string infile = ""; 22 | std::string fmt = "csv"; 23 | 24 | auto cli = ( 25 | value("input file", infile), 26 | option("-r", "--recursive").set(rec).doc("convert files recursively"), 27 | option("-o") & value("output format", fmt), 28 | option("-utf16").set(utf16).doc("use UTF-16 encoding") 29 | ); 30 | 31 | if(!parse(argc, argv, cli)) { 32 | auto fmt = doc_formatting{}.doc_column(28); 33 | 34 | auto filter = param_filter{}.prefix("--"); 35 | 36 | cout << "Usage:\n" << usage_lines(cli, argv[0]) << "\n\n" 37 | << "Parameters:\n" << documentation(cli, fmt, filter) << '\n'; 38 | } 39 | else { 40 | cout << "input file: " << infile << '\n' 41 | << "format: " << fmt << '\n' 42 | << "recursive: " << (rec ? "yes\n" : "no\n") 43 | << "UTF-16: " << (utf16 ? "yes\n" : "no\n"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /examples/documentation.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main() 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | auto cli = ( 23 | command("help") | 24 | ( command("build"), 25 | "build commands" % 26 | ( command("new") % "make new database" 27 | | command("add") % "append to existing database" 28 | ), 29 | value("file") 30 | ) | 31 | ( command("query"), 32 | "query settings" % 33 | ( required("-i", "--input") & value("infile") % "input file", 34 | option("-p", "--pretty-print") % "human friendly output") 35 | ) | 36 | ( command("info"), 37 | "database info modes" % ( 38 | command("space") % "detailed memory occupation analysis" | 39 | ( 40 | command("statistics"), 41 | "statistics analysis" % ( 42 | command("words") % "word frequency table" | 43 | command("chars") % "character frequency table" 44 | ) 45 | ) 46 | ) 47 | ) | 48 | "remove mode" % ( 49 | command("remove"), 50 | "modify" % ( command("any") | command("all") ), 51 | value("regex") % "regular expression filter" 52 | ) | 53 | ( command("modify"), 54 | "modification opererations" % ( 55 | option("-c", "--compress") % "compress database in-memory", 56 | option("-u", "--unique") % "keep only unique entries", 57 | option("-m", "--memlimit") % "max. size in RAM" & value("size") 58 | ) 59 | ) 60 | ); 61 | 62 | auto fmt = doc_formatting{} .first_column(4) .doc_column(28); 63 | 64 | cout << make_man_page(cli, "worddb", fmt) 65 | .prepend_section("DESCRIPTION", " Builds a database of words from text files.") 66 | .append_section("LICENSE", " GPL3") << '\n'; 67 | } 68 | -------------------------------------------------------------------------------- /examples/finder.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | using std::string; 23 | 24 | enum class mode {make, find, help}; 25 | mode selected = mode::help; 26 | std::vector input; 27 | string dict, out; 28 | bool split = false, progr = false; 29 | 30 | auto makeMode = ( 31 | command("make").set(selected,mode::make), 32 | value("wordfile", input), 33 | required("-dict") & value("dictionary", dict), 34 | option("--progress", "-p").set(progr) % "show progress" ); 35 | 36 | auto findMode = ( 37 | command("find").set(selected,mode::find), 38 | values("infile", input), 39 | required("-dict") & value("dictionary", dict), 40 | (option("-o", "--output") & value("outfile", out)) % "write to file instead of stdout", 41 | ( option("-split" ).set(split,true) | 42 | option("-nosplit").set(split,false) ) % "(do not) split output" ); 43 | 44 | auto cli = ( 45 | (makeMode | findMode | command("help").set(selected,mode::help) ), 46 | option("-v", "--version").call([]{cout << "version 1.0\n\n"; }) % "show version" ); 47 | 48 | string execname = argv[0]; 49 | 50 | if(parse(argc, argv, cli)) { 51 | switch(selected) { 52 | case mode::make: 53 | cout << "make new dictionary " << dict << " from wordfile(s) "; 54 | for(const auto& s : input) { cout << s << ' '; } cout << '\n'; 55 | break; 56 | case mode::find: 57 | cout << "find words from dictionary " << dict << " in files "; 58 | for(const auto& s : input) { cout << s << ' '; } cout << '\n'; 59 | cout << "output: "; 60 | if(split) cout << "splitted "; 61 | cout << "to "; 62 | if(!out.empty()) cout << "file " << out; else cout << "stdin"; 63 | cout << '\n'; 64 | if(progr) cout << "Progres: [ ] 0%\n"; 65 | break; 66 | case mode::help: 67 | cout << make_man_page(cli, execname) << '\n'; 68 | break; 69 | } 70 | } else { 71 | cout << usage_lines(cli, execname) << '\n'; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /examples/float_vector.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | 23 | std::vector nums; 24 | 25 | auto cli = required("--data") & numbers("number", nums); 26 | 27 | if(parse(argc, argv, cli)) { 28 | cout << "numbers:\n"; 29 | for(auto n : nums) cout << n << '\n'; 30 | } else { 31 | cout << "Usage:\n" << usage_lines(cli, argv[0]) << '\n'; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/groups.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | bool x = false, y = false, a = false, b = false; 23 | bool g = false, h = false, e = false, f = false; 24 | 25 | auto cli = ( 26 | ( option("x").set(x) % "sets X", //simple group 27 | option("y").set(y) % "sets Y" 28 | ), 29 | ( option("a").set(a) % "activates A", 30 | option("b").set(b) % "activates B" 31 | ) % "documented group 1:" //docstring after group 32 | , 33 | "documented group 2:" % ( //docstring before group 34 | option("-g").set(g) % "activates G", 35 | option("-h").set(h) % "activates H" 36 | ), 37 | "activates E or F" % ( 38 | option("-e").set(e), //no docstrings inside group 39 | option("-f").set(f) 40 | ) 41 | ); 42 | 43 | if(!parse(argc, argv, cli)) { 44 | cout << make_man_page(cli, argv[0]) << '\n'; 45 | } 46 | else { 47 | cout << std::boolalpha 48 | << "x = " << x << '\n' 49 | << "y = " << y << '\n' 50 | << "a = " << a << '\n' 51 | << "b = " << b << '\n' 52 | << "g = " << g << '\n' 53 | << "h = " << h << '\n' 54 | << "e = " << e << '\n' 55 | << "f = " << f << '\n'; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /examples/joinable_flags.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | std::string file; 23 | bool readonly = false; 24 | bool usebackup = false; 25 | bool useswap = false; 26 | enum class editor {vim, sublime3, atom, emacs}; 27 | std::vector editors; 28 | auto add = [&](editor e){ return [&]{ editors.push_back(e); }; }; 29 | 30 | auto cli = ( 31 | value("file", file), 32 | joinable( 33 | option("-r").set(readonly) % "open read-only", 34 | option("-b").set(usebackup) % "use backup file", 35 | option("-s").set(useswap) % "use swap file" 36 | ), 37 | joinable( 38 | option(":vim") >> add(editor::vim), 39 | option(":st3") >> add(editor::sublime3), 40 | option(":atom") >> add(editor::atom), 41 | option(":emacs") >> add(editor::emacs) 42 | ) % "editor(s) to use; multiple possible" 43 | ); 44 | 45 | 46 | if(parse(argc, argv, cli)) { 47 | cout << "open " << file 48 | << (readonly ? " read-only" : "") 49 | << (usebackup ? " using backup" : "") 50 | << (useswap ? " using swap" : ""); 51 | 52 | if(!editors.empty()) { 53 | bool first = true; 54 | cout << "\nwith editor(s): "; 55 | for(auto e : editors) { 56 | if(first) first = false; else cout << ", "; 57 | switch(e) { 58 | case editor::vim: cout << "vim"; break; 59 | case editor::sublime3: cout << "Sublime Text 3"; break; 60 | case editor::atom: cout << "Atom"; break; 61 | case editor::emacs: cout << "GNU Emacs"; break; 62 | } 63 | } 64 | } 65 | cout << '\n'; 66 | } 67 | else { 68 | cout << make_man_page(cli, argv[0]) << '\n'; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /examples/model.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | 19 | //------------------------------------------------------------------- 20 | enum class mode { 21 | none, train, validate, classify 22 | }; 23 | 24 | struct settings { 25 | mode selected = mode::none; 26 | std::string imageFile; 27 | std::string labelFile; 28 | std::string modelFile = "out.mdl"; 29 | std::size_t batchSize = 128; 30 | std::size_t threads = 0; 31 | std::size_t inputLimit = 0; 32 | std::vector inputFiles; 33 | }; 34 | 35 | 36 | //------------------------------------------------------------------- 37 | settings configuration(int argc, char* argv[]) 38 | { 39 | using namespace clipp; 40 | 41 | settings s; 42 | 43 | std::vector unrecognized; 44 | 45 | auto isfilename = clipp::match::prefix_not("-"); 46 | 47 | auto inputOptions = ( 48 | required("-i", "-I", "--img") & !value(isfilename, "image file", s.imageFile), 49 | required("-l", "-L", "--lbl") & !value(isfilename, "label file", s.labelFile) 50 | ); 51 | 52 | auto trainMode = ( 53 | command("train", "t", "T").set(s.selected,mode::train) 54 | .if_conflicted([]{std::cerr << "conflicting modes\n"; }), 55 | 56 | inputOptions, 57 | 58 | (option("-n") & integer("limit", s.inputLimit)) 59 | % "limit number of input images", 60 | 61 | (option("-o", "-O", "--out") & !value("model file", s.modelFile)) 62 | % "write model to specific file; default: 'out.mdl'", 63 | 64 | (option("-b", "--batch-size") & integer("batch size", s.batchSize)), 65 | 66 | (option("-p") & integer("threads", s.threads)) 67 | % "number of threads to use; default: optimum for machine" 68 | ); 69 | 70 | auto validationMode = ( 71 | command("validate", "v", "V").set(s.selected,mode::validate), 72 | !value(isfilename, "model", s.modelFile), 73 | inputOptions 74 | ); 75 | 76 | auto classificationMode = ( 77 | command("classify", "c", "C").set(s.selected,mode::classify), 78 | !value(isfilename, "model", s.modelFile), 79 | !values(isfilename, "images", s.inputFiles) 80 | ); 81 | 82 | auto cli = ( 83 | trainMode | validationMode | classificationMode, 84 | any_other(unrecognized) 85 | ); 86 | 87 | auto res = parse(argc, argv, cli); 88 | 89 | debug::print(std::cout, res); 90 | 91 | if(!res || !unrecognized.empty()) { 92 | std::string msg = "Wrong command line arguments!\n"; 93 | 94 | if(s.selected == mode::none) { 95 | msg += "Please select a mode!\n"; 96 | } 97 | else { 98 | for(const auto& m : res.missing()) { 99 | if(!m.param()->flags().empty()) { 100 | msg += "Missing option: " + m.param()->flags().front() + '\n'; 101 | } 102 | else if(!m.param()->label().empty()) { 103 | msg += "Missing value: " + m.param()->label() + '\n'; 104 | } 105 | } 106 | 107 | for(const auto& arg : unrecognized) { 108 | msg += "Argument not recognized: " + arg + '\n'; 109 | } 110 | } 111 | 112 | auto fmt = doc_formatting{}.first_column(8).doc_column(16); 113 | //.max_flags_per_param_in_usage(3).surround_alternative_flags("(", ")"); 114 | 115 | msg += "\nUsage:\n" + usage_lines(cli, argv[0], fmt).str() + '\n'; 116 | msg += "\nOptions:\n" + documentation(cli, fmt).str() + '\n'; 117 | 118 | throw std::invalid_argument{msg}; 119 | } 120 | 121 | return s; 122 | } 123 | 124 | 125 | 126 | //------------------------------------------------------------------- 127 | int main(int argc, char* argv[]) 128 | { 129 | try { 130 | auto conf = configuration(argc, argv); 131 | std::cout << "SUCCESS\n"; 132 | } 133 | catch(std::exception& e) { 134 | std::cerr << "ERROR: " << e.what() << '\n'; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /examples/naval_fate.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | * 10 | * This command line interface example was taken from http://docopt.org/. 11 | * 12 | * EXAMPLE 13 | * We want to model this command line interface: 14 | * 15 | * Naval Fate. 16 | * 17 | * Usage: 18 | * naval_fate ship new ... 19 | * naval_fate ship move [--speed=] 20 | * naval_fate ship shoot 21 | * naval_fate mine (set|remove) [--moored|--drifting] 22 | * naval_fate -h | --help 23 | * naval_fate --version 24 | * 25 | * Options: 26 | * -h --help Show this screen. 27 | * --version Show version. 28 | * --speed= Speed in knots [default: 10]. 29 | * --moored Moored (anchored) mine. 30 | * --drifting Drifting mine. 31 | * 32 | * 33 | *****************************************************************************/ 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | 43 | int main(int argc, char* argv[]) 44 | { 45 | using namespace clipp; 46 | using std::string; 47 | using std::vector; 48 | using std::cout; 49 | 50 | int x = 0, y = 0; 51 | float speed = 10.0f; 52 | bool drift = true; 53 | vector names; 54 | 55 | enum class mode { none, help, shipnew, shipmove, shipshoot, mineset, minerem}; 56 | mode selected = mode::none; 57 | 58 | auto coordinates = ( value("x", x), value("y", y) ); 59 | 60 | auto shipnew = ( command("new").set(selected,mode::shipnew), 61 | values("name", names) ); 62 | 63 | auto shipmove = ( 64 | value("name", names), 65 | command("move").set(selected,mode::shipmove), coordinates, 66 | (option("--speed=") & value("kn",speed)) % "Speed in knots [default: 10]"); 67 | 68 | auto shipshoot = ( command("shoot").set(selected,mode::shipshoot), 69 | coordinates ); 70 | 71 | auto mines = ( 72 | command("mine"), 73 | (command("set" ).set(selected,mode::mineset) | 74 | command("remove").set(selected,mode::minerem) ), 75 | coordinates, 76 | (option("--moored" ).set(drift,false) % "Moored (anchored) mine." | 77 | option("--drifting").set(drift,true) % "Drifting mine." ) 78 | ); 79 | 80 | auto navalcli = ( 81 | ( command("ship"), ( shipnew | shipmove | shipshoot ) ) 82 | | mines 83 | | command("-h", "--help").set(selected,mode::help) % "Show this screen." 84 | | command("--version")([]{ cout << "version 1.0\n"; }) % "Show version." 85 | ); 86 | 87 | auto fmt = doc_formatting{} 88 | .first_column(2) 89 | .doc_column(20) 90 | .max_flags_per_param_in_usage(8); 91 | 92 | if(parse(argc, argv, navalcli)) { 93 | switch(selected) { 94 | default: 95 | case mode::none: 96 | break; 97 | case mode::help: { 98 | cout << "Naval Fate.\n\nUsage:\n" 99 | << usage_lines(navalcli, "naval_fate", fmt) 100 | << "\n\nOptions:\n" 101 | << documentation(navalcli, fmt) << '\n'; 102 | } 103 | break; 104 | case mode::shipnew: 105 | if(names.empty()) { 106 | cout << "No new ships were made\n"; 107 | } else { 108 | cout << "Made new ship" << (names.size() > 1 ? "s " : " "); 109 | for(const auto& n : names) cout << n << ' '; 110 | cout << "\n"; 111 | } 112 | break; 113 | case mode::shipmove: 114 | if(names.empty()) { 115 | cout << "No ship was moved.\n"; 116 | } else { 117 | cout << "Moving ship " << names.front() 118 | << " to x=" << x << " y=" << y << ".\n"; 119 | } 120 | break; 121 | case mode::shipshoot: 122 | cout << "Ship fired shot aimed at x=" << x << " y=" << y << ".\n"; 123 | break; 124 | case mode::mineset: 125 | cout << "Laid " << (drift ? "drifting" : "& moored") 126 | << " mine at x=" << x << " y=" << y << ".\n"; 127 | break; 128 | case mode::minerem: 129 | cout << "Removed mine at x=" << x << " y=" << y << ".\n"; 130 | break; 131 | } 132 | } 133 | else { 134 | std::cerr << "Wrong command line arguments.\nUsage:" 135 | << usage_lines(navalcli, "naval_fate", fmt) << '\n'; 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /examples/nested_alternatives.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | 23 | bool verbose = false; 24 | bool init = true; 25 | int bsize = 1024; 26 | enum class mode {help, build, query}; 27 | bool add = false; 28 | enum class fmt {plain, json, xml}; 29 | mode selected; 30 | std::vector infiles; 31 | std::string outfile; 32 | std::string outfmt; 33 | 34 | auto cli = ( 35 | command("help") 36 | | ( command("build").set(selected,mode::help), 37 | ( command("new").set(selected,mode::build).set(add,false) 38 | | command("add").set(selected,mode::build).set(add,true) ), 39 | values("file", infiles), 40 | option("-v", "--verbose").set(verbose) % "print detailed report", 41 | option("-b", "--buffer") & opt_value( 42 | "size="+std::to_string(bsize), bsize) % "sets buffer size in KiByte", 43 | ( option("--init").set(init) 44 | | option("--no-init").set(init,false) ) % "do or don't initialize" 45 | ) 46 | | ( command("query").set(selected,mode::query), 47 | value("infile", infiles), 48 | required("-o", "--out") & value("outfile", outfile), 49 | option("-f", "--out-format") % "determine output format" 50 | & value("format",outfmt) 51 | ) 52 | ); 53 | 54 | if(parse(argc, argv, cli)) { 55 | switch(selected) { 56 | default: 57 | case mode::help: 58 | cout << make_man_page(cli, argv[0]) << '\n'; return 0; 59 | case mode::build: 60 | if(add) 61 | cout << "adding to database\n"; 62 | else 63 | cout << "building new database\n"; 64 | 65 | cout << "buffer size is " << bsize << '\n'; 66 | if(init) cout << "showing detailed information\n"; 67 | break; 68 | case mode::query: 69 | cout << "query database\n"; 70 | cout << "output to " << outfile << " in format " << outfmt << '\n'; 71 | break; 72 | } 73 | cout << "input files:"; 74 | for(const auto& f : infiles) cout << ' ' << f; 75 | cout << "\n"; 76 | if(verbose) cout << "showing detailed information\n"; 77 | } 78 | else { 79 | cout << usage_lines(cli, argv[0]) << '\n'; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /examples/numbers.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | 23 | std::vector nums; 24 | 25 | auto cli = joinable( repeatable( 26 | option(",") , opt_number("number", nums) 27 | ) ); 28 | 29 | if(parse(argc, argv, cli)) { 30 | cout << "numbers:\n"; 31 | for(auto n : nums) cout << n << '\n'; 32 | } else { 33 | cout << "Usage:\n" << usage_lines(cli, argv[0]) << '\n'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/options.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | 13 | #include 14 | 15 | 16 | int main(int argc, char* argv[]) 17 | { 18 | using namespace clipp; 19 | using std::cout; 20 | 21 | bool a = false, b = false, c = true; //target variables 22 | 23 | auto cli = ( 24 | option("-a").set(a) % "activates a", 25 | option("-b").set(b) % "activates b", 26 | option("-c", "--noc").set(c,false) % "deactivates c", 27 | option("--hi")([]{cout << "hi!\n";}) % "says hi"); 28 | 29 | if(parse(argc, argv, cli)) { 30 | cout << std::boolalpha 31 | << "a=" << a << "\nb=" << b << "\nc=" << c << '\n'; 32 | } else { 33 | cout << make_man_page(cli, argv[0]) << '\n'; 34 | } 35 | 36 | 37 | // alternative style 1: member functions instead of operators 38 | // auto cli = ( 39 | // option("-b").set(b).doc("activates b"), 40 | // option("-c", "--noc").set(c,false).doc("deactivates c"), 41 | // option("--hi").call([]{cout << "hi!\n";}).doc("says hi") ); 42 | 43 | 44 | // alternative style 2: even more operators 45 | // auto cli = ( 46 | // option("-b") % "activates b" >> b, 47 | // option("-c", "--noc") % "deactivates c" >> set(c,false), 48 | // option("--hi") % "says hi" >> []{cout << "hi!\n";} ); 49 | 50 | // auto cli = ( 51 | // option("-b") % "activates b" >> b, 52 | // option("-c", "--noc") % "deactivates c" >> set(c,false), 53 | // option("--hi") % "says hi" >> []{cout << "hi!\n";} ); 54 | 55 | // auto cli = ( 56 | // b << option("-b") % "activates b", 57 | // set(c,false) << option("-c", "--noc") % "deactivates c", 58 | // []{cout << "hi!\n";} << option("--hi") % "says hi" ); 59 | 60 | // auto cli = ( 61 | // "activates b" % option("-b") >> b, 62 | // "deactivates c" % option("-c", "--noc") >> set(c,false), 63 | // "says hi" % option("--hi") >> []{cout << "hi!\n";} ); 64 | 65 | } 66 | -------------------------------------------------------------------------------- /examples/options_values.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | int n = 0; 23 | bool domerge = false; 24 | long m = 5; 25 | auto print_ratio = [](const char* r) { cout << "using ratio of " << r << '\n'; }; 26 | 27 | auto cli = ( 28 | (option("-n", "--count") & value("count", n)) % "number of iterations", 29 | (option("-r", "--ratio") & value("ratio", print_ratio)) % "compression ratio", 30 | (option("-m") & opt_value("lines=5", m).set(domerge)) % "merge lines (default: 5)" 31 | ); 32 | 33 | if(parse(argc, argv, cli)) { 34 | cout << "performing " << n << " iterations\n"; 35 | if(domerge) cout << "merge " << m << " lines\n"; 36 | } 37 | else { 38 | cout << make_man_page(cli, argv[0]) << '\n'; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/parsing.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | 23 | auto cli = ( 24 | command("make"), 25 | value("file") % "name of file to make", 26 | option("-f", "--force") % "overwrite existing file" 27 | ); 28 | 29 | 30 | parse({"make", "out.txt"}, cli); 31 | 32 | 33 | auto args = std::vector {"make", "out.txt", "-f"}; 34 | parse(args, cli); 35 | 36 | 37 | auto result = parse(argc, argv, cli); 38 | 39 | clipp::debug::print(std::cout, result); 40 | } 41 | -------------------------------------------------------------------------------- /examples/positional_values.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | std::string ifile, ofile; 23 | bool split = false; 24 | 25 | auto cli = ( 26 | value("infile", ifile) % "input filename", 27 | value("outfile", ofile) % "output filename", 28 | option("-s", "--split").set(split) % "split files" ); 29 | 30 | if(parse(argc, argv, cli)) { 31 | cout << "input file: " << ifile << '\n' 32 | << "output file: " << ofile << '\n' 33 | << "Files will " << (split ? "" : "not") << " be split."; 34 | } 35 | else { 36 | cout << make_man_page(cli, argv[0]) << '\n'; 37 | } 38 | 39 | // alternative style: 40 | // auto cli = ( 41 | // value("infile") % "input filename" >> ifile, 42 | // value("outfile") % "output filename" >> ofile, 43 | // option("-s", "--split") % "split files" >> split ); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /examples/repeatable.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | std::vector files; 23 | std::vector lines; 24 | bool zip = false; 25 | 26 | auto cli = ( 27 | values("directory", files) % "input files", 28 | option("-c", "--compress").set(zip) % "compress results", 29 | (option("-i", "--ignore") & values("line", lines)) % "lines to be ignored" 30 | ); 31 | 32 | if(parse(argc, argv, cli)) { 33 | cout << "input files:"; 34 | for(const auto& f : files) cout << ' ' << f; 35 | cout << "\n"; 36 | cout << (zip ? "" : "don't ") << "compress results\n"; 37 | cout << "ignored lines:"; 38 | for(const auto& l : lines) cout << ' ' << l; 39 | cout << "\n"; 40 | } 41 | else { 42 | cout << make_man_page(cli, argv[0]) << '\n'; 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /examples/required_flags.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | bool recurse = false; 23 | std::string inpath, outpath; 24 | 25 | auto cli = ( 26 | option("-r", "--recursive").set(recurse) % "recurse into subdirectories", 27 | (required("-i", "--in" ) & value("input dir", inpath)) % "sets path to input directory", 28 | (required("-o", "--out") & value("output dir", outpath)) % "sets path to output directory" 29 | ); 30 | 31 | if(parse(argc, argv, cli)) { 32 | cout << "read from " << inpath 33 | << (recurse ? " (recursively)" : " (non-recursively)") 34 | << " and write to " << outpath << '\n'; 35 | } 36 | else { 37 | cout << make_man_page(cli, argv[0]) << '\n'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/sanity.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main() 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | 23 | auto cli = group( 24 | option("-a"), 25 | option("-ab") 26 | ); 27 | 28 | cout << "flags are " << (cli.flags_are_prefix_free() ? "" : "not ") 29 | << "prefix free\n"; 30 | } 31 | -------------------------------------------------------------------------------- /examples/send.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | 23 | std::vector wrong; 24 | 25 | auto istarget = match::prefix_not("-"); 26 | 27 | auto cli = ( 28 | value("file") 29 | .if_missing([]{ cout << "You need to provide a source filename!\n"; } ) 30 | .if_repeated([](int idx){ cout << "Only one source file allowed! (index " << idx << ")\n"; } ) 31 | , 32 | required("-t") & values(istarget, "target") 33 | .if_missing([]{ cout << "You need to provide at least one target filename!\n"; } ) 34 | .if_blocked([]{ cout << "Target names must not be given before the file command and the source file name!\n"; }) 35 | , 36 | option("--http") | option("--ftp") 37 | .if_conflicted([]{ cout << "You can only use one protocol at a time!\n"; } ) 38 | , 39 | any_other(wrong) 40 | ); 41 | 42 | if(parse(argc, argv, cli) && wrong.empty()) { 43 | cout << "OK\n"; 44 | } 45 | else { 46 | for(const auto& arg : wrong) { 47 | cout << "'" << arg << "' is not a valid command line argument\n"; 48 | } 49 | cout << "Usage:\n" << usage_lines(cli,argv[0]) << '\n'; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/simplify.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | 23 | 24 | std::vector files; 25 | std::vector lines; 26 | bool zip = false; 27 | 28 | auto cli = ( 29 | "input files" % 30 | values("file", files), 31 | "compress results" % 32 | option("-c", "--compress").set(zip), 33 | "lines to be ignored" % 34 | repeatable( option("-i", "--ignore") & integers("line", lines) ) 35 | ); 36 | 37 | if(parse(argc, argv, cli)) { 38 | cout << "files:\n"; 39 | for(const auto& f : files) cout << " " << f << '\n'; 40 | cout << "lines to be ignored: "; 41 | for(const auto& l : lines) cout << l << ' '; 42 | cout << "\nusing" << (zip ? "" : " no") << " compression\n"; 43 | } 44 | else { 45 | cout << make_man_page(cli, argv[0]) << '\n'; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /examples/switches.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | std::string outfile = "a.out"; 23 | bool align = false; 24 | 25 | auto cli = ( 26 | (option("-o", "--out") & value("output file", outfile)) % "output filename", 27 | with_prefix("-f", option("align") >> [&]{ align = true; } | 28 | option("noalign") >> [&]{ align = false; } ) % "control alignment" 29 | ); 30 | 31 | if(parse(argc, argv, cli)) { 32 | cout << "write to " << outfile 33 | << " with" << (align ? "" : "out") << " alignment.\n"; 34 | } 35 | else { 36 | auto fmt = doc_formatting{} 37 | .merge_alternative_flags_with_common_prefix(true); 38 | 39 | cout << make_man_page(cli, argv[0], fmt) << '\n'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/tagnames.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::cout; 22 | using std::string; 23 | 24 | auto tag_name = [] (const string& arg) { 25 | if(arg.size() < 3) return subrange{}; //too short 26 | auto i = arg.find("<"); 27 | if(i == string::npos) return subrange{}; //no tag start found 28 | auto j = arg.find(">", i+1); 29 | if(j == string::npos) return subrange{}; //didn't find end of tag 30 | return subrange{i,j-i+1}; //partial match {start, length} 31 | }; 32 | 33 | 34 | std::set tags; 35 | auto cli = joinable( 36 | values(tag_name, "string", 37 | [&](const string& arg){ if(arg[1] != '/') tags.insert(arg); }) 38 | ); 39 | 40 | if(parse(argc, argv, cli)) { 41 | cout << "tag names:\n"; 42 | for(const auto& t : tags) cout << t << '\n'; 43 | } else { 44 | cout << "Usage:\n" << usage_lines(cli, argv[0]) << '\n'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/text_formatting.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // #include 17 | #include "../include/clipp.h" 18 | 19 | 20 | int main(int argc, char* argv[]) 21 | { 22 | using namespace clipp; 23 | using std::cout; 24 | using std::string; 25 | using std::to_string; 26 | 27 | int firstCol = 0; 28 | int docCol = 30; 29 | int lastCol = 80; 30 | auto fmtcli = ( 31 | value("first column", firstCol), 32 | value("docstr column", docCol), 33 | value("last column", lastCol) 34 | ); 35 | 36 | if(!parse(argc, argv, fmtcli)) { 37 | std::cout 38 | << "This program shows how clipp handles documentation formatting.\n" 39 | << "You can use the following command line interface to re-format\n" 40 | << "the documentation text of a more complex command line interface\n" 41 | << "Usage:\n" << usage_lines(fmtcli, argv[0]) << '\n'; 42 | return 0; 43 | } 44 | if(docCol < firstCol) docCol = firstCol; 45 | if(lastCol <= docCol) lastCol = docCol+1; 46 | 47 | std::cout 48 | << "first column (>) " << firstCol << '\n' 49 | << "docstr column (|) " << docCol << '\n' 50 | << "last column (<) " << lastCol << '\n' 51 | << std::string(firstCol, ' ') << ">" 52 | << std::string(docCol-firstCol-1, ' ') << "|" 53 | << std::string(lastCol-docCol-1, ' ') << "<\n"; 54 | 55 | auto copyMode = "copy mode:" % ( 56 | command("copy") | command("move"), 57 | option("--all") % "copy all", 58 | option("--replace") % "replace existing files", 59 | option("-f", "--force") % "don't ask for confirmation" 60 | ); 61 | 62 | auto compareMode = "compare mode:" % ( 63 | command("compare"), 64 | (command("date") | command("content")), 65 | option("-b", "--binary") % "compare files byte by byte", 66 | option("-q", "--quick") % "use heuristics for faster comparison" 67 | ); 68 | 69 | auto mergeAlgo = ( 70 | command("diff") % "merge using diff" | 71 | command("patch") % "merge using patch" | 72 | ( command("content") % "merge based on content", 73 | "content based merge options:" % ( 74 | option("--git-style") % "emulate git's merge behavior", 75 | option("-m", "--marker") & value("marker") % "merge marker symbol" 76 | ) 77 | ) 78 | ); 79 | 80 | auto mergeMode = "merge mode:" % ( 81 | command("merge"), 82 | mergeAlgo, 83 | required("-o") & value("outdir") % "target directory for merge result", 84 | option("--show-conflicts") % "show merge conflicts during run" 85 | ); 86 | 87 | auto firstOpt = "user interface options:" % ( 88 | option("-v", "--verbose") % "show detailed output", 89 | option("-i", "--interactive") % "use interactive mode" 90 | ); 91 | auto lastOpt = "mode-independent options:" % ( 92 | values("files") % "input files", 93 | option("-r", "--recursive") % "descend into subdirectories", 94 | option("-h", "--help") % "show help" 95 | ); 96 | 97 | auto cli = ( 98 | firstOpt, 99 | copyMode | compareMode | mergeMode | command("list"), 100 | lastOpt 101 | ); 102 | 103 | parse(argc, argv, fmtcli); 104 | 105 | auto fmt = doc_formatting{} 106 | .line_spacing(0) 107 | .paragraph_spacing(1) 108 | .first_column(firstCol) 109 | .doc_column(docCol) 110 | .last_column(lastCol); 111 | 112 | cout << make_man_page(cli, argv[0], fmt) << '\n'; 113 | // cout << documentation(cli, fmt) << '\n'; 114 | // cout << usage_lines(cli, argv[0], fmt) << '\n'; 115 | } 116 | -------------------------------------------------------------------------------- /examples/timing.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | using namespace clipp; 21 | using std::string; 22 | using std::cout; 23 | 24 | int n = 1; 25 | bool errStop = false; 26 | string exe; 27 | std::vector args; 28 | 29 | auto cli = ( 30 | option("-n", "--repeat") & value("times", n) % "execute multiple times", 31 | option("-s", "--stop-on-error").set(errStop) % "stop on error", 32 | value("executable", exe) % "client program", 33 | option("--") & values("args", args) % "client arguments" 34 | ); 35 | 36 | if(!parse(argc, argv, cli)) { 37 | cout << make_man_page(cli, argv[0]) << '\n'; 38 | } 39 | 40 | cout << "call: " << exe; 41 | for(const auto& a : args) cout << ' ' << a; 42 | cout << '\n'; 43 | cout << n << " times\n"; 44 | if(errStop) cout << "execution will be stopped on any error\n"; 45 | } 46 | -------------------------------------------------------------------------------- /examples/transform.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * demo program - part of CLIPP (command line interfaces for modern C++) 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | using std::cout; 21 | 22 | std::string infile; 23 | bool tr = false, rot = false; 24 | double x = 0, y = 0, z = 0; 25 | double phi = 0, theta = 0; 26 | 27 | auto cli = ( 28 | value("geometry file", infile), 29 | option("-translate").set(tr) & value("x", x) & value("y", y) & value("z", z), 30 | option("-rotate").set(rot) & value("azimuth", phi) & value("polar", theta) 31 | ); 32 | 33 | if(parse(argc, argv, cli)) { 34 | if(!tr && !rot) { 35 | cout << "nothing will be done with file '" << infile << "'\n"; 36 | } 37 | else { 38 | cout << "transforming content of file '" << infile << "'\n"; 39 | if(tr) { 40 | cout << "translating objects by vector (" 41 | << x << ", " << y << ", " << z << ")\n"; 42 | } 43 | if(rot) { 44 | cout << "rotating objects about azimuth = " << phi 45 | << " and polar angle = " << theta << '\n'; 46 | } 47 | } 48 | } 49 | else { 50 | cout << "Usage:\n" << usage_lines(cli, argv[0]) << '\n'; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (NOT CMAKE_BUILD_TYPE) 2 | set(CMAKE_BUILD_TYPE Debug) 3 | endif() 4 | message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") 5 | 6 | message(STATUS "CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}") 7 | if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 8 | add_compile_options(-stdlib=libc++) 9 | else() 10 | add_compile_options(-Wlogical-op) 11 | add_compile_options(-Wnoexcept) 12 | add_compile_options(-Wstrict-null-sentinel) 13 | add_compile_options(-Wuseless-cast) 14 | endif() 15 | add_compile_options(-Wall -Wextra -Wpedantic) 16 | add_compile_options(-Wcast-align -Wcast-qual) 17 | add_compile_options(-Wctor-dtor-privacy) 18 | add_compile_options(-Wconversion -Wno-sign-conversion) 19 | add_compile_options(-Wdisabled-optimization) 20 | add_compile_options(-Wdouble-promotion) 21 | add_compile_options(-Wformat=2) 22 | add_compile_options(-Winit-self) 23 | add_compile_options(-Wmissing-include-dirs) 24 | add_compile_options(-Wold-style-cast) 25 | add_compile_options(-Woverloaded-virtual) 26 | add_compile_options(-Wredundant-decls) 27 | add_compile_options(-Wshadow) 28 | add_compile_options(-Wstrict-aliasing=1) 29 | add_compile_options(-Wstrict-overflow=5) 30 | add_compile_options(-Wswitch-default) 31 | add_compile_options(-Wundef) 32 | 33 | aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} source_files) 34 | foreach(src IN LISTS source_files) 35 | get_filename_component(name_we ${src} NAME_WE) 36 | add_executable(test-${name_we} ${src}) 37 | target_link_libraries(test-${name_we} ${PROJECT_NAME}::${PROJECT_NAME}) 38 | set_target_properties(test-${name_we} PROPERTIES 39 | CXX_STANDARD_REQUIRED ON 40 | CXX_EXTENSIONS OFF 41 | ) 42 | add_test(NAME ${name_we} COMMAND $) 43 | endforeach() 44 | -------------------------------------------------------------------------------- /test/alternative_groups_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, bool c_, bool d_, bool e_, bool f_) : 19 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_} 20 | {} 21 | bool a = false, b = false, c = false, d = false, e = false, f = false; 22 | 23 | friend bool operator == (const active& x, const active& y) noexcept { 24 | return (x.a == y.a && x.b == y.b && x.c == y.c && 25 | x.d == y.d && x.e == y.e && x.f == y.f ); 26 | } 27 | }; 28 | 29 | 30 | //------------------------------------------------------------------- 31 | void test(int lineNo, 32 | const std::initializer_list args, 33 | const active& matches, const active& missing) 34 | { 35 | using namespace clipp; 36 | 37 | active v; 38 | active m; 39 | 40 | auto cli = ( 41 | option("a").set(v.a).if_missing(set(m.a)), 42 | ( 43 | option("b").set(v.b).if_missing(set(m.b)) | 44 | required("c").set(v.c).if_missing(set(m.c)) 45 | ), 46 | ( 47 | required("d").set(v.d).if_missing(set(m.d)) | 48 | required("e").set(v.e).if_missing(set(m.e)) 49 | ), 50 | required("f").set(v.f).if_missing(set(m.f)) 51 | ); 52 | 53 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 54 | [&]{ m = active{}; v = active{}; }, 55 | [&]{ return v == matches && m == missing; }); 56 | 57 | } 58 | 59 | 60 | //------------------------------------------------------------------- 61 | int main() 62 | { 63 | try { 64 | test(__LINE__, {""}, active{0,0,0,0,0,0}, active{0,0,0,1,1,1}); 65 | 66 | test(__LINE__, {"a"}, active{1,0,0,0,0,0}, active{0,0,0,1,1,1}); 67 | test(__LINE__, {"b"}, active{0,1,0,0,0,0}, active{0,0,0,1,1,1}); 68 | test(__LINE__, {"c"}, active{0,0,1,0,0,0}, active{0,0,0,1,1,1}); 69 | test(__LINE__, {"d"}, active{0,0,0,1,0,0}, active{0,0,0,0,0,1}); 70 | test(__LINE__, {"e"}, active{0,0,0,0,1,0}, active{0,0,0,0,0,1}); 71 | test(__LINE__, {"f"}, active{0,0,0,0,0,1}, active{0,0,0,1,1,0}); 72 | 73 | test(__LINE__, {"d", "f"}, active{0,0,0,1,0,1}, active{0,0,0,0,0,0}); 74 | test(__LINE__, {"e", "f"}, active{0,0,0,0,1,1}, active{0,0,0,0,0,0}); 75 | 76 | test(__LINE__, {"b", "f"}, active{0,1,0,0,0,1}, active{0,0,0,1,1,0}); 77 | test(__LINE__, {"c", "f"}, active{0,0,1,0,0,1}, active{0,0,0,1,1,0}); 78 | 79 | test(__LINE__, {"b", "d", "f"}, active{0,1,0,1,0,1}, active{0,0,0,0,0,0}); 80 | test(__LINE__, {"c", "d", "f"}, active{0,0,1,1,0,1}, active{0,0,0,0,0,0}); 81 | 82 | test(__LINE__, {"b", "e", "f"}, active{0,1,0,0,1,1}, active{0,0,0,0,0,0}); 83 | test(__LINE__, {"c", "e", "f"}, active{0,0,1,0,1,1}, active{0,0,0,0,0,0}); 84 | } 85 | catch(std::exception& e) { 86 | std::cerr << e.what() << std::endl; 87 | return 1; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /test/alternative_options_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, bool c_, bool d_): 19 | a{a_}, b{b_}, c{c_}, d{d_} 20 | {} 21 | bool a = false, b = false, c = false, d = false; 22 | bool conflict = false; 23 | 24 | friend bool operator == (const active& x, const active& y) noexcept { 25 | return (x.a == y.a && x.b == y.b && x.c == y.c && 26 | x.d == y.d && x.conflict == y.conflict); 27 | } 28 | }; 29 | 30 | 31 | //------------------------------------------------------------------- 32 | void test(int lineNo, 33 | const std::initializer_list args, 34 | const active& matches) 35 | { 36 | using namespace clipp; 37 | 38 | { 39 | active m; 40 | 41 | auto cli = option("-a").set(m.a) | 42 | option("-b").set(m.b) | 43 | option("-c").set(m.c) | 44 | option("-d").set(m.d); 45 | 46 | auto res = parse(args, cli); 47 | m.conflict = res.any_conflict(); 48 | 49 | if(!(m == matches)) { 50 | throw std::runtime_error{"failed " + std::string( __FILE__ ) + 51 | " #1 in line " + std::to_string(lineNo)}; 52 | } 53 | } 54 | { 55 | active m; 56 | 57 | auto cli = ( 58 | option("?????"), 59 | ( 60 | option("-a").set(m.a) | 61 | option("-b").set(m.b) | 62 | option("-c").set(m.c) | 63 | option("-d").set(m.d) 64 | ) 65 | ); 66 | 67 | auto res = parse(args, cli); 68 | m.conflict = res.any_conflict(); 69 | 70 | if(!(m == matches)) { 71 | throw std::runtime_error{"failed " + std::string( __FILE__ ) + 72 | " #2 in line " + std::to_string(lineNo)}; 73 | } 74 | } 75 | } 76 | 77 | 78 | //------------------------------------------------------------------- 79 | int main() 80 | { 81 | try { 82 | test(__LINE__, {""}, active{}); 83 | 84 | test(__LINE__, {"-a"}, active{1,0,0,0}); 85 | test(__LINE__, {"-b"}, active{0,1,0,0}); 86 | test(__LINE__, {"-c"}, active{0,0,1,0}); 87 | test(__LINE__, {"-d"}, active{0,0,0,1}); 88 | 89 | { 90 | active e; e.conflict = true; 91 | test(__LINE__, {"-a","-b"}, e); 92 | test(__LINE__, {"-b","-a"}, e); 93 | test(__LINE__, {"-c","-b"}, e); 94 | test(__LINE__, {"-d","-c"}, e); 95 | test(__LINE__, {"-a","-d"}, e); 96 | 97 | test(__LINE__, {"-a","-b","-c"}, e); 98 | test(__LINE__, {"-c","-b","-a"}, e); 99 | test(__LINE__, {"-d","-a","-c"}, e); 100 | 101 | test(__LINE__, {"-a","-b","-c", "-d"}, e); 102 | test(__LINE__, {"-d","-c","-b", "-a"}, e); 103 | test(__LINE__, {"-c","-b","-a", "-d"}, e); 104 | test(__LINE__, {"-d","-a","-c", "-b"}, e); 105 | } 106 | } 107 | catch(std::exception& e) { 108 | std::cerr << e.what() << std::endl; 109 | return 1; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /test/alternative_required_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, bool c_, bool d_): 19 | a{a_}, b{b_}, c{c_}, d{d_} 20 | {} 21 | bool a = false, b = false, c = false, d = false; 22 | bool conflict = false; 23 | std::size_t missing = 0; 24 | 25 | friend bool operator == (const active& x, const active& y) noexcept { 26 | return (x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d && 27 | x.conflict == y.conflict && x.missing == y.missing); 28 | } 29 | }; 30 | 31 | 32 | //------------------------------------------------------------------- 33 | void test(int lineNo, 34 | const std::initializer_list args, 35 | const active& matches) 36 | { 37 | using namespace clipp; 38 | 39 | { 40 | active m; 41 | 42 | auto cli = required("-a").set(m.a) | 43 | required("-b").set(m.b) | 44 | required("-c").set(m.c) | 45 | required("-d").set(m.d); 46 | 47 | auto res = parse(args, cli); 48 | m.missing = res.missing().size(); 49 | m.conflict = res.any_conflict(); 50 | 51 | if(!(m == matches)) { 52 | throw std::runtime_error{"failed " + std::string( __FILE__ ) + 53 | " #1 in line " + std::to_string(lineNo)}; 54 | } 55 | } 56 | { 57 | active m; 58 | 59 | auto cli = ( 60 | option("?????"), 61 | ( 62 | required("-a").set(m.a) | 63 | required("-b").set(m.b) | 64 | required("-c").set(m.c) | 65 | required("-d").set(m.d) 66 | ) 67 | ); 68 | 69 | auto res = parse(args, cli); 70 | m.missing = res.missing().size(); 71 | m.conflict = res.any_conflict(); 72 | 73 | if(!(m == matches)) { 74 | throw std::runtime_error{"failed " + std::string( __FILE__ ) + 75 | " #2 in line " + std::to_string(lineNo)}; 76 | } 77 | } 78 | } 79 | 80 | 81 | //------------------------------------------------------------------- 82 | int main() 83 | { 84 | try { 85 | { 86 | active e; e.missing = 4; 87 | test(__LINE__, {""}, e); 88 | test(__LINE__, {"x"}, e); 89 | test(__LINE__, {"-x"}, e); 90 | test(__LINE__, {"x", "-y"}, e); 91 | } 92 | 93 | //parsing should catch all occurrences 94 | test(__LINE__, {"-a"}, active{1,0,0,0}); 95 | test(__LINE__, {"-b"}, active{0,1,0,0}); 96 | test(__LINE__, {"-c"}, active{0,0,1,0}); 97 | test(__LINE__, {"-d"}, active{0,0,0,1}); 98 | 99 | { 100 | active e; e.conflict = true; 101 | test(__LINE__, {"-a","-b"}, e); 102 | test(__LINE__, {"-b","-a"}, e); 103 | test(__LINE__, {"-b","-c"}, e); 104 | test(__LINE__, {"-c","-b"}, e); 105 | test(__LINE__, {"-a","-d"}, e); 106 | test(__LINE__, {"-d","-a"}, e); 107 | test(__LINE__, {"-d","-a","-c"}, e); 108 | test(__LINE__, {"-c","-b","-a"}, e); 109 | test(__LINE__, {"-a","-b","-c", "-d"}, e); 110 | test(__LINE__, {"-c","-a","-d", "-b"}, e); 111 | } 112 | } 113 | catch(std::exception& e) { 114 | std::cerr << e.what() << std::endl; 115 | return 1; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /test/blocking_test01.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, bool c_, bool d_, bool e_, bool f_, int i_ = 0) : 19 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_}, i{i_} 20 | {} 21 | bool a = false, b = false, c = false, d = false, e = false, f = false; 22 | int i = 0; 23 | 24 | friend bool operator == (const active& x, const active& y) noexcept { 25 | return (x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d && 26 | x.e == y.e && x.f == y.f && x.i == y.i); 27 | } 28 | }; 29 | 30 | 31 | //------------------------------------------------------------------- 32 | void test(int lineNo, 33 | const std::initializer_list args, 34 | const active& matches) 35 | { 36 | using namespace clipp; 37 | 38 | active m; 39 | 40 | auto cli = ( 41 | option("-a").set(m.a), 42 | 43 | command("-b").set(m.b), 44 | option("-c").set(m.c), 45 | option("-i") & value("i", m.i), 46 | option("-d").set(m.d), 47 | 48 | command("-e").set(m.e), 49 | option("-f").set(m.f) 50 | ); 51 | 52 | run_test({ __FILE__, lineNo }, args, cli, [&]{ return m == matches; }); 53 | } 54 | 55 | 56 | //------------------------------------------------------------------- 57 | int main() 58 | { 59 | try { 60 | test(__LINE__, {""}, active{}); 61 | 62 | test(__LINE__, {"-a"}, active{1,0,0,0,0,0, 0}); 63 | 64 | test(__LINE__, {"-a", "-c"}, active{1,0,0,0,0,0, 0}); 65 | test(__LINE__, {"-a", "-d"}, active{1,0,0,0,0,0, 0}); 66 | test(__LINE__, {"-a", "-e"}, active{1,0,0,0,0,0, 0}); 67 | test(__LINE__, {"-a", "-f"}, active{1,0,0,0,0,0, 0}); 68 | test(__LINE__, {"-a", "-i", "123"}, active{1,0,0,0,0,0, 0}); 69 | 70 | test(__LINE__, {"-b"}, active{0,1,0,0,0,0, 0}); 71 | test(__LINE__, {"-b", "-a"}, active{0,1,0,0,0,0, 0}); 72 | test(__LINE__, {"-a", "-b"}, active{1,1,0,0,0,0, 0}); 73 | 74 | test(__LINE__, {"-b", "-c"}, active{0,1,1,0,0,0, 0}); 75 | test(__LINE__, {"-a", "-b", "-c"}, active{1,1,1,0,0,0, 0}); 76 | test(__LINE__, {"-a", "-b", "-c", "-i"}, active{1,1,1,0,0,0, 0}); 77 | test(__LINE__, {"-a", "-b", "-c", "-i", "123"}, active{1,1,1,0,0,0, 123}); 78 | 79 | test(__LINE__, {"-b", "-i", "123"}, active{0,1,0,0,0,0, 123}); 80 | test(__LINE__, {"-a", "-b", "-i", "123"}, active{1,1,0,0,0,0, 123}); 81 | test(__LINE__, {"-a", "-b", "-c", "-i", "123"}, active{1,1,1,0,0,0, 123}); 82 | test(__LINE__, {"-a", "-b", "-d", "-i", "123"}, active{1,1,0,1,0,0, 123}); 83 | test(__LINE__, {"-a", "-b", "-i", "123", "-c"}, active{1,1,1,0,0,0, 123}); 84 | test(__LINE__, {"-a", "-b", "-i", "123", "-d"}, active{1,1,0,1,0,0, 123}); 85 | 86 | test(__LINE__, {"-b", "-i", "123", "-a"}, active{0,1,0,0,0,0, 123}); 87 | test(__LINE__, {"-b", "-i", "123", "-a"}, active{0,1,0,0,0,0, 123}); 88 | 89 | test(__LINE__, {"-b", "-i", "123", "-d", "-c"}, active{0,1,1,1,0,0, 123}); 90 | test(__LINE__, {"-b", "-i", "123", "-c", "-d"}, active{0,1,1,1,0,0, 123}); 91 | test(__LINE__, {"-b", "-c", "-i", "123", "-d"}, active{0,1,1,1,0,0, 123}); 92 | test(__LINE__, {"-b", "-c", "-d", "-i", "123"}, active{0,1,1,1,0,0, 123}); 93 | test(__LINE__, {"-b", "-d", "-c", "-i", "123"}, active{0,1,1,1,0,0, 123}); 94 | test(__LINE__, {"-b", "-d", "-i", "123", "-c"}, active{0,1,1,1,0,0, 123}); 95 | 96 | test(__LINE__, {"-a", "-b", "-i", "123", "-d", "-c"}, active{1,1,1,1,0,0, 123}); 97 | test(__LINE__, {"-a", "-b", "-i", "123", "-c", "-d"}, active{1,1,1,1,0,0, 123}); 98 | test(__LINE__, {"-a", "-b", "-c", "-i", "123", "-d"}, active{1,1,1,1,0,0, 123}); 99 | test(__LINE__, {"-a", "-b", "-c", "-d", "-i", "123"}, active{1,1,1,1,0,0, 123}); 100 | test(__LINE__, {"-a", "-b", "-d", "-c", "-i", "123"}, active{1,1,1,1,0,0, 123}); 101 | test(__LINE__, {"-a", "-b", "-d", "-i", "123", "-c"}, active{1,1,1,1,0,0, 123}); 102 | 103 | test(__LINE__, {"-b", "-c", "-d"}, active{0,1,1,1,0,0, 0}); 104 | test(__LINE__, {"-b", "-c", "-d", "-e"}, active{0,1,1,1,1,0, 0}); 105 | test(__LINE__, {"-b", "-c", "-d", "-e", "-f"}, active{0,1,1,1,1,1, 0}); 106 | 107 | test(__LINE__, {"-a", "-b", "-c", "-d"}, active{1,1,1,1,0,0, 0}); 108 | test(__LINE__, {"-a", "-b", "-c", "-d", "-e"}, active{1,1,1,1,1,0, 0}); 109 | test(__LINE__, {"-a", "-b", "-c", "-d", "-e", "-f"}, active{1,1,1,1,1,1, 0}); 110 | 111 | test(__LINE__, {"-b", "-f"}, active{0,1,0,0,0,0, 0}); 112 | test(__LINE__, {"-b", "-e", "-f"}, active{0,1,0,0,1,1, 0}); 113 | 114 | test(__LINE__, {"-a", "-b", "-f"}, active{1,1,0,0,0,0, 0}); 115 | test(__LINE__, {"-a", "-b", "-e", "-f"}, active{1,1,0,0,1,1, 0}); 116 | 117 | test(__LINE__, {"-b", "-e", "-c"}, active{0,1,0,0,1,0, 0}); 118 | test(__LINE__, {"-b", "-e", "-d"}, active{0,1,0,0,1,0, 0}); 119 | test(__LINE__, {"-b", "-e", "-i", "123"}, active{0,1,0,0,1,0, 0}); 120 | 121 | test(__LINE__, {"-a", "-b", "-e", "-c"}, active{1,1,0,0,1,0, 0}); 122 | test(__LINE__, {"-a", "-b", "-e", "-d"}, active{1,1,0,0,1,0, 0}); 123 | test(__LINE__, {"-a", "-b", "-e", "-i", "123"}, active{1,1,0,0,1,0, 0}); 124 | 125 | } 126 | catch(std::exception& e) { 127 | std::cerr << e.what() << std::endl; 128 | return 1; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /test/blocking_test02.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, bool c_, bool d_, bool e_, bool f_, int i_ = 0) : 19 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_}, i{i_} 20 | {} 21 | bool a = false, b = false, c = false, d = false, e = false, f = false; 22 | int i = 0; 23 | 24 | friend bool operator == (const active& x, const active& y) noexcept { 25 | return (x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d && 26 | x.e == y.e && x.f == y.f && x.i == y.i); 27 | } 28 | }; 29 | 30 | 31 | //------------------------------------------------------------------- 32 | void test(int lineNo, 33 | const std::initializer_list args, 34 | const active& matches) 35 | { 36 | using namespace clipp; 37 | 38 | active m; 39 | 40 | auto cli = ( 41 | ( command("a"), 42 | option("-x").set(m.a) 43 | ).doc("group (~a,-x)") 44 | | 45 | ( command("b"), 46 | option("-x").set(m.b), 47 | ( command("u").set(m.i,1) | 48 | command("v").set(m.i,2) | 49 | command("w").set(m.i,3) 50 | ).doc("group (u|v|w)"), 51 | option("-e").set(m.e) 52 | ).doc("group (~b,-x,(~u|~v|~w),-e)") 53 | | 54 | ( command("c"), 55 | option("-x").set(m.c), 56 | command("d").set(m.d), 57 | required("-i").set(m.e) & value("i", m.i), 58 | option("-f").set(m.f) 59 | ).doc("group (~c,-x,d,(~-i,~i),-f)") 60 | ); 61 | 62 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 63 | [&]{ m = active{}; }, 64 | [&]{ return m == matches; }); 65 | } 66 | 67 | 68 | //------------------------------------------------------------------- 69 | int main() 70 | { 71 | try { 72 | test(__LINE__, {""}, active{}); 73 | 74 | test(__LINE__, {"a"}, active{}); 75 | test(__LINE__, {"b"}, active{}); 76 | test(__LINE__, {"c"}, active{}); 77 | test(__LINE__, {"-x"}, active{}); 78 | 79 | test(__LINE__, {"a", "-x"}, active{1,0,0,0,0,0, 0}); 80 | test(__LINE__, {"b", "-x"}, active{0,1,0,0,0,0, 0}); 81 | test(__LINE__, {"c", "-x"}, active{0,0,1,0,0,0, 0}); 82 | 83 | test(__LINE__, {"b", "u"}, active{0,0,0,0,0,0, 1}); 84 | test(__LINE__, {"b", "v"}, active{0,0,0,0,0,0, 2}); 85 | test(__LINE__, {"b", "w"}, active{0,0,0,0,0,0, 3}); 86 | 87 | test(__LINE__, {"b", "-x", "u"}, active{0,1,0,0,0,0, 1}); 88 | test(__LINE__, {"b", "-x", "v"}, active{0,1,0,0,0,0, 2}); 89 | test(__LINE__, {"b", "-x", "w"}, active{0,1,0,0,0,0, 3}); 90 | 91 | test(__LINE__, {"b", "u", "-x"}, active{0,0,0,0,0,0, 1}); 92 | test(__LINE__, {"b", "v", "-x"}, active{0,0,0,0,0,0, 2}); 93 | test(__LINE__, {"b", "w", "-x"}, active{0,0,0,0,0,0, 3}); 94 | 95 | test(__LINE__, {"b", "-x", "u", "-e"}, active{0,1,0,0,1,0, 1}); 96 | test(__LINE__, {"b", "-x", "v", "-e"}, active{0,1,0,0,1,0, 2}); 97 | test(__LINE__, {"b", "-x", "w", "-e"}, active{0,1,0,0,1,0, 3}); 98 | 99 | test(__LINE__, {"b", "u", "-x", "-e"}, active{0,0,0,0,1,0, 1}); 100 | test(__LINE__, {"b", "v", "-x", "-e"}, active{0,0,0,0,1,0, 2}); 101 | test(__LINE__, {"b", "w", "-x", "-e"}, active{0,0,0,0,1,0, 3}); 102 | 103 | test(__LINE__, {"b", "-x", "u", "-e"}, active{0,1,0,0,1,0, 1}); 104 | test(__LINE__, {"b", "-x", "v", "-e"}, active{0,1,0,0,1,0, 2}); 105 | test(__LINE__, {"b", "-x", "w", "-e"}, active{0,1,0,0,1,0, 3}); 106 | 107 | test(__LINE__, {"b", "-x", "-e", "u"}, active{0,1,0,0,0,0, 1}); 108 | test(__LINE__, {"b", "-x", "-e", "v"}, active{0,1,0,0,0,0, 2}); 109 | test(__LINE__, {"b", "-x", "-e", "w"}, active{0,1,0,0,0,0, 3}); 110 | 111 | test(__LINE__, {"c", "-x", "-i"}, active{0,0,1,0,0,0, 0}); 112 | test(__LINE__, {"c", "-x", "-f"}, active{0,0,1,0,0,0, 0}); 113 | test(__LINE__, {"c", "-x", "123"}, active{0,0,1,0,0,0, 0}); 114 | 115 | test(__LINE__, {"c", "-x", "-i", "123"}, active{0,0,1,0,0,0, 0}); 116 | test(__LINE__, {"c", "-x", "-i", "-f"}, active{0,0,1,0,0,0, 0}); 117 | test(__LINE__, {"c", "-x", "123", "-i"}, active{0,0,1,0,0,0, 0}); 118 | test(__LINE__, {"c", "-x", "123", "-f"}, active{0,0,1,0,0,0, 0}); 119 | 120 | test(__LINE__, {"c", "-x", "-i", "123", "-f"}, active{0,0,1,0,0,0, 0}); 121 | 122 | test(__LINE__, {"c", "-x", "d"}, active{0,0,1,1,0,0, 0}); 123 | 124 | test(__LINE__, {"c", "-x", "d", "-i"}, active{0,0,1,1,1,0, 0}); 125 | test(__LINE__, {"c", "-x", "d", "-f"}, active{0,0,1,1,0,1, 0}); 126 | test(__LINE__, {"c", "-x", "d", "123"}, active{0,0,1,1,0,0, 0}); 127 | 128 | test(__LINE__, {"c", "-x", "d", "-i", "123"}, active{0,0,1,1,1,0, 123}); 129 | test(__LINE__, {"c", "-x", "d", "-i", "-f"}, active{0,0,1,1,1,1, 0}); 130 | test(__LINE__, {"c", "-x", "d", "123", "-i"}, active{0,0,1,1,1,0, 0}); 131 | test(__LINE__, {"c", "-x", "d", "123", "-f"}, active{0,0,1,1,0,1, 0}); 132 | 133 | test(__LINE__, {"c", "-x", "d", "-i", "123", "-f"}, active{0,0,1,1,1,1, 123}); 134 | 135 | test(__LINE__, {"c", "-x", "d", "-f", "-i"}, active{0,0,1,1,1,1, 0}); 136 | test(__LINE__, {"c", "-x", "d", "-f", "-i", "123"}, active{0,0,1,1,1,1, 123}); 137 | 138 | test(__LINE__, {"c", "d", "-f", "-i", "123"}, active{0,0,0,1,1,1, 123}); 139 | test(__LINE__, {"c", "d", "-i", "123", "-f"}, active{0,0,0,1,1,1, 123}); 140 | 141 | test(__LINE__, {"c", "d", "-x", "-i", "123", "-f"}, active{0,0,0,1,1,1, 123}); 142 | test(__LINE__, {"c", "d", "-f", "-i", "123", "-x"}, active{0,0,0,1,1,1, 123}); 143 | 144 | 145 | } 146 | catch(std::exception& e) { 147 | std::cerr << e.what() << std::endl; 148 | return 1; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /test/blocking_test03.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, bool c_, bool d_, bool e_, bool f_, int i_ = 0) : 19 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_}, i{i_} 20 | {} 21 | bool a = false, b = false, c = false, d = false, e = false, f = false; 22 | int i = 0; 23 | 24 | friend bool operator == (const active& x, const active& y) noexcept { 25 | return (x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d && 26 | x.e == y.e && x.f == y.f && x.i == y.i); 27 | } 28 | }; 29 | 30 | 31 | //------------------------------------------------------------------- 32 | void test(int lineNo, 33 | const std::initializer_list args, 34 | const active& matches) 35 | { 36 | using namespace clipp; 37 | 38 | active m1; 39 | auto cli1 = ( 40 | command("a").set(m1.a), 41 | command("b").set(m1.b), 42 | command("c").set(m1.c), 43 | command("d").set(m1.d), 44 | opt_value("i").set(m1.i), 45 | option("-e").set(m1.e), 46 | option("-f").set(m1.f) 47 | ); 48 | 49 | //equivalent interface 50 | active m2; 51 | auto cli2 = ( 52 | required("a").set(m2.a) & 53 | required("b").set(m2.b) & 54 | required("c").set(m2.c) & 55 | required("d").set(m2.d) & 56 | ( 57 | opt_value("i").set(m2.i), 58 | option("-e").set(m2.e), 59 | option("-f").set(m2.f) 60 | ) 61 | ); 62 | 63 | run_wrapped_variants({ __FILE__, lineNo }, args, cli1, 64 | [&]{ m1 = active{}; }, 65 | [&]{ return m1 == matches; }); 66 | 67 | run_wrapped_variants({ __FILE__, lineNo }, args, cli2, 68 | [&]{ m2 = active{}; }, 69 | [&]{ return m2 == matches; }); 70 | } 71 | 72 | 73 | //------------------------------------------------------------------- 74 | int main() 75 | { 76 | try { 77 | test(__LINE__, {""}, active{}); 78 | 79 | test(__LINE__, {"a"}, active{1,0,0,0,0,0, 0}); 80 | test(__LINE__, {"b"}, active{}); 81 | test(__LINE__, {"c"}, active{}); 82 | test(__LINE__, {"d"}, active{}); 83 | test(__LINE__, {"12"}, active{}); 84 | test(__LINE__, {"-e"}, active{}); 85 | test(__LINE__, {"-f"}, active{}); 86 | 87 | test(__LINE__, {"a", "b"}, active{1,1,0,0,0,0, 0}); 88 | test(__LINE__, {"a", "c"}, active{1,0,0,0,0,0, 0}); 89 | test(__LINE__, {"a", "d"}, active{1,0,0,0,0,0, 0}); 90 | test(__LINE__, {"a", "12"}, active{1,0,0,0,0,0, 0}); 91 | test(__LINE__, {"a", "-e"}, active{1,0,0,0,0,0, 0}); 92 | test(__LINE__, {"a", "-f"}, active{1,0,0,0,0,0, 0}); 93 | 94 | test(__LINE__, {"a", "b", "c"}, active{1,1,1,0,0,0, 0}); 95 | test(__LINE__, {"a", "b", "d"}, active{1,1,0,0,0,0, 0}); 96 | test(__LINE__, {"a", "b", "12"}, active{1,1,0,0,0,0, 0}); 97 | test(__LINE__, {"a", "b", "-e"}, active{1,1,0,0,0,0, 0}); 98 | test(__LINE__, {"a", "b", "-f"}, active{1,1,0,0,0,0, 0}); 99 | 100 | test(__LINE__, {"a", "b", "c", "d"}, active{1,1,1,1,0,0, 0}); 101 | test(__LINE__, {"a", "b", "c", "12"}, active{1,1,1,0,0,0, 0}); 102 | test(__LINE__, {"a", "b", "c", "-e"}, active{1,1,1,0,0,0, 0}); 103 | test(__LINE__, {"a", "b", "c", "-f"}, active{1,1,1,0,0,0, 0}); 104 | 105 | test(__LINE__, {"a", "b", "c", "d", "-e"}, active{1,1,1,1,1,0, 0}); 106 | test(__LINE__, {"a", "b", "c", "d", "-f"}, active{1,1,1,1,0,1, 0}); 107 | test(__LINE__, {"a", "b", "c", "d", "12"}, active{1,1,1,1,0,0, 12}); 108 | test(__LINE__, {"a", "b", "c", "d", "-3"}, active{1,1,1,1,0,0, -3}); 109 | 110 | test(__LINE__, {"a", "b", "c", "d", "12", "-e"}, active{1,1,1,1,1,0, 12}); 111 | test(__LINE__, {"a", "b", "c", "d", "12", "-f"}, active{1,1,1,1,0,1, 12}); 112 | 113 | test(__LINE__, {"a", "b", "c", "d", "-e", "12"}, active{1,1,1,1,1,0, 12}); 114 | test(__LINE__, {"a", "b", "c", "d", "-f", "12"}, active{1,1,1,1,0,1, 12}); 115 | 116 | test(__LINE__, {"a", "b", "c", "d", "-e", "-f"}, active{1,1,1,1,1,1, 0}); 117 | test(__LINE__, {"a", "b", "c", "d", "-f", "-e"}, active{1,1,1,1,1,1, 0}); 118 | 119 | test(__LINE__, {"a", "b", "c", "d", "12", "-e", "-f"}, active{1,1,1,1,1,1, 12}); 120 | test(__LINE__, {"a", "b", "c", "d", "-e", "12", "-f"}, active{1,1,1,1,1,1, 12}); 121 | test(__LINE__, {"a", "b", "c", "d", "-e", "-f", "12"}, active{1,1,1,1,1,1, 12}); 122 | 123 | test(__LINE__, {"a", "b", "c", "d", "12", "-f", "-e"}, active{1,1,1,1,1,1, 12}); 124 | test(__LINE__, {"a", "b", "c", "d", "-f", "12", "-e"}, active{1,1,1,1,1,1, 12}); 125 | test(__LINE__, {"a", "b", "c", "d", "-f", "-e", "12"}, active{1,1,1,1,1,1, 12}); 126 | 127 | } 128 | catch(std::exception& e) { 129 | std::cerr << e.what() << std::endl; 130 | return 1; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /test/blocking_test04.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, bool c_, bool d_, bool e_, bool f_) : 19 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_} 20 | {} 21 | bool a = false, b = false, c = false, d = false, e = false, f = false; 22 | 23 | friend bool operator == (const active& x, const active& y) noexcept { 24 | return (x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d && 25 | x.e == y.e && x.f == y.f); 26 | } 27 | }; 28 | 29 | 30 | //------------------------------------------------------------------- 31 | void test(int lineNo, 32 | const std::initializer_list args, 33 | const active& matches) 34 | { 35 | using namespace clipp; 36 | 37 | active m1; 38 | auto cli1 = ( 39 | option("a").set(m1.a), 40 | group( 41 | command("b").set(m1.b), 42 | command("c").set(m1.c), 43 | command("d").set(m1.d), 44 | command("e").set(m1.e) 45 | ), 46 | option("f").set(m1.f) 47 | ); 48 | 49 | //equivalent interface 50 | active m2; 51 | auto cli2 = ( 52 | option("a").set(m2.a), 53 | ( 54 | required("b").set(m2.b) & 55 | required("c").set(m2.c) & 56 | required("d").set(m2.d) & 57 | required("e").set(m2.e) 58 | ), 59 | option("f").set(m2.f) 60 | ); 61 | 62 | 63 | run_wrapped_variants({ __FILE__, lineNo }, args, cli1, 64 | [&]{ m1 = active{}; }, 65 | [&]{ return m1 == matches; }); 66 | 67 | run_wrapped_variants({ __FILE__, lineNo }, args, cli2, 68 | [&]{ m2 = active{}; }, 69 | [&]{ return m2 == matches; }); 70 | } 71 | 72 | 73 | //------------------------------------------------------------------- 74 | int main() 75 | { 76 | try { 77 | test(__LINE__, {""}, active{}); 78 | 79 | test(__LINE__, {"a"}, active{1,0,0,0,0,0}); 80 | test(__LINE__, {"f"}, active{0,0,0,0,0,1}); 81 | 82 | test(__LINE__, {"b"}, active{0,1,0,0,0,0}); 83 | test(__LINE__, {"c"}, active{}); 84 | test(__LINE__, {"d"}, active{}); 85 | test(__LINE__, {"e"}, active{}); 86 | 87 | test(__LINE__, {"b", "c"}, active{0,1,1,0,0,0}); 88 | test(__LINE__, {"b", "c", "d"}, active{0,1,1,1,0,0}); 89 | test(__LINE__, {"b", "c", "d", "e"}, active{0,1,1,1,1,0}); 90 | test(__LINE__, {"b", "c", "d", "e", "f"}, active{0,1,1,1,1,1}); 91 | test(__LINE__, {"b", "c", "d", "e", "a"}, active{1,1,1,1,1,0}); 92 | 93 | test(__LINE__, {"a", "b"}, active{1,1,0,0,0,0}); 94 | test(__LINE__, {"a", "b", "c"}, active{1,1,1,0,0,0}); 95 | test(__LINE__, {"a", "b", "c", "d"}, active{1,1,1,1,0,0}); 96 | test(__LINE__, {"a", "b", "c", "d", "e"}, active{1,1,1,1,1,0}); 97 | 98 | test(__LINE__, {"f", "b"}, active{0,1,0,0,0,1}); 99 | test(__LINE__, {"f", "b", "c"}, active{0,1,1,0,0,1}); 100 | test(__LINE__, {"f", "b", "c", "d"}, active{0,1,1,1,0,1}); 101 | test(__LINE__, {"f", "b", "c", "d", "e"}, active{0,1,1,1,1,1}); 102 | 103 | test(__LINE__, {"a", "b", "c", "d", "e", "f"}, active{1,1,1,1,1,1}); 104 | test(__LINE__, {"f", "b", "c", "d", "e", "a"}, active{1,1,1,1,1,1}); 105 | test(__LINE__, {"a", "f", "b", "c", "d", "e"}, active{1,1,1,1,1,1}); 106 | test(__LINE__, {"f", "a", "b", "c", "d", "e"}, active{1,1,1,1,1,1}); 107 | test(__LINE__, {"b", "c", "d", "e", "a", "f"}, active{1,1,1,1,1,1}); 108 | test(__LINE__, {"b", "c", "d", "e", "f", "a"}, active{1,1,1,1,1,1}); 109 | 110 | test(__LINE__, {"b", "c", "a"}, active{1,1,1,0,0,0}); 111 | test(__LINE__, {"b", "c", "f"}, active{0,1,1,0,0,1}); 112 | test(__LINE__, {"b", "a", "c"}, active{1,1,0,0,0,0}); 113 | test(__LINE__, {"b", "f", "c"}, active{0,1,0,0,0,1}); 114 | 115 | test(__LINE__, {"b", "c", "d", "a"}, active{1,1,1,1,0,0}); 116 | test(__LINE__, {"b", "c", "d", "f"}, active{0,1,1,1,0,1}); 117 | test(__LINE__, {"b", "c", "a", "d"}, active{1,1,1,0,0,0}); 118 | test(__LINE__, {"b", "c", "f", "d"}, active{0,1,1,0,0,1}); 119 | test(__LINE__, {"b", "a", "c", "d"}, active{1,1,0,0,0,0}); 120 | test(__LINE__, {"b", "f", "c", "d"}, active{0,1,0,0,0,1}); 121 | 122 | test(__LINE__, {"b", "a", "c", "d", "e"}, active{1,1,0,0,0,0}); 123 | test(__LINE__, {"b", "f", "c", "d", "e"}, active{0,1,0,0,0,1}); 124 | 125 | test(__LINE__, {"b", "c", "d", "f", "a", "e"}, active{1,1,1,1,0,1}); 126 | test(__LINE__, {"b", "c", "f", "d", "a", "e"}, active{1,1,1,0,0,1}); 127 | test(__LINE__, {"b", "c", "a", "d", "f", "e"}, active{1,1,1,0,0,1}); 128 | test(__LINE__, {"b", "a", "c", "f", "d", "e"}, active{1,1,0,0,0,1}); 129 | test(__LINE__, {"b", "f", "c", "a", "d", "e"}, active{1,1,0,0,0,1}); 130 | 131 | test(__LINE__, {"b", "c", "d", "a", "e"}, active{1,1,1,1,0,0}); 132 | 133 | } 134 | catch(std::exception& e) { 135 | std::cerr << e.what() << std::endl; 136 | return 1; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /test/blocking_test05.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, bool c_, bool d_, bool e_, bool f_) : 19 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_} 20 | {} 21 | bool a = false, b = false, c = false, d = false, e = false, f = false; 22 | 23 | friend bool operator == (const active& x, const active& y) noexcept { 24 | return (x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d && 25 | x.e == y.e && x.f == y.f); 26 | } 27 | }; 28 | 29 | 30 | //------------------------------------------------------------------- 31 | void test(int lineNo, 32 | const std::initializer_list args, 33 | const active& matches) 34 | { 35 | using namespace clipp; 36 | 37 | //[a] ([b] [c] [d] [e]) [f] 38 | active m1; 39 | auto cli1 = ( 40 | option("a").set(m1.a), 41 | in_sequence( 42 | option("b").set(m1.b), 43 | option("c").set(m1.c), 44 | option("d").set(m1.d), 45 | option("e").set(m1.e) 46 | ), 47 | option("f").set(m1.f) 48 | ); 49 | 50 | //equivalent interface 51 | active m2; 52 | auto cli2 = ( 53 | option("a").set(m2.a), 54 | ( 55 | option("b").set(m2.b) & 56 | option("c").set(m2.c) & 57 | option("d").set(m2.d) & 58 | option("e").set(m2.e) 59 | ), 60 | option("f").set(m2.f) 61 | ); 62 | 63 | run_wrapped_variants({ __FILE__, lineNo }, args, cli1, 64 | [&]{ m1 = active{}; }, 65 | [&]{ return m1 == matches; }); 66 | 67 | run_wrapped_variants({ __FILE__, lineNo }, args, cli2, 68 | [&]{ m2 = active{}; }, 69 | [&]{ return m2 == matches; }); 70 | } 71 | 72 | 73 | //------------------------------------------------------------------- 74 | int main() 75 | { 76 | try { 77 | test(__LINE__, {""}, active{}); 78 | 79 | test(__LINE__, {"a"}, active{1,0,0,0,0,0}); 80 | test(__LINE__, {"b"}, active{0,1,0,0,0,0}); 81 | test(__LINE__, {"c"}, active{0,0,0,0,0,0}); 82 | test(__LINE__, {"d"}, active{0,0,0,0,0,0}); 83 | test(__LINE__, {"e"}, active{0,0,0,0,0,0}); 84 | test(__LINE__, {"f"}, active{0,0,0,0,0,1}); 85 | 86 | test(__LINE__, {"a", "b"}, active{1,1,0,0,0,0}); 87 | test(__LINE__, {"a", "c"}, active{1,0,0,0,0,0}); 88 | test(__LINE__, {"a", "d"}, active{1,0,0,0,0,0}); 89 | test(__LINE__, {"a", "e"}, active{1,0,0,0,0,0}); 90 | 91 | test(__LINE__, {"b", "a"}, active{1,1,0,0,0,0}); 92 | test(__LINE__, {"c", "a"}, active{1,0,0,0,0,0}); 93 | test(__LINE__, {"d", "a"}, active{1,0,0,0,0,0}); 94 | test(__LINE__, {"e", "a"}, active{1,0,0,0,0,0}); 95 | 96 | test(__LINE__, {"f", "b"}, active{0,1,0,0,0,1}); 97 | test(__LINE__, {"f", "c"}, active{0,0,0,0,0,1}); 98 | test(__LINE__, {"f", "d"}, active{0,0,0,0,0,1}); 99 | test(__LINE__, {"f", "e"}, active{0,0,0,0,0,1}); 100 | 101 | test(__LINE__, {"b", "f"}, active{0,1,0,0,0,1}); 102 | test(__LINE__, {"c", "f"}, active{0,0,0,0,0,1}); 103 | test(__LINE__, {"d", "f"}, active{0,0,0,0,0,1}); 104 | test(__LINE__, {"e", "f"}, active{0,0,0,0,0,1}); 105 | 106 | test(__LINE__, {"a", "f", "b"}, active{1,1,0,0,0,1}); 107 | test(__LINE__, {"a", "f", "c"}, active{1,0,0,0,0,1}); 108 | test(__LINE__, {"a", "f", "d"}, active{1,0,0,0,0,1}); 109 | test(__LINE__, {"a", "f", "e"}, active{1,0,0,0,0,1}); 110 | 111 | test(__LINE__, {"a", "b", "f"}, active{1,1,0,0,0,1}); 112 | test(__LINE__, {"a", "c", "f"}, active{1,0,0,0,0,1}); 113 | test(__LINE__, {"a", "d", "f"}, active{1,0,0,0,0,1}); 114 | test(__LINE__, {"a", "e", "f"}, active{1,0,0,0,0,1}); 115 | 116 | test(__LINE__, {"f", "a", "b"}, active{1,1,0,0,0,1}); 117 | test(__LINE__, {"f", "a", "c"}, active{1,0,0,0,0,1}); 118 | test(__LINE__, {"f", "a", "d"}, active{1,0,0,0,0,1}); 119 | test(__LINE__, {"f", "a", "e"}, active{1,0,0,0,0,1}); 120 | 121 | test(__LINE__, {"a", "f", "b"}, active{1,1,0,0,0,1}); 122 | test(__LINE__, {"a", "f", "c"}, active{1,0,0,0,0,1}); 123 | test(__LINE__, {"a", "f", "d"}, active{1,0,0,0,0,1}); 124 | test(__LINE__, {"a", "f", "e"}, active{1,0,0,0,0,1}); 125 | 126 | test(__LINE__, {"b", "c"}, active{0,1,1,0,0,0}); 127 | test(__LINE__, {"b", "c", "d"}, active{0,1,1,1,0,0}); 128 | test(__LINE__, {"b", "c", "d", "e"}, active{0,1,1,1,1,0}); 129 | 130 | test(__LINE__, {"b", "c", "a"}, active{1,1,1,0,0,0}); 131 | test(__LINE__, {"b", "c", "d", "a"}, active{1,1,1,1,0,0}); 132 | test(__LINE__, {"b", "c", "d", "e", "a"}, active{1,1,1,1,1,0}); 133 | 134 | test(__LINE__, {"b", "c", "f"}, active{0,1,1,0,0,1}); 135 | test(__LINE__, {"b", "c", "d", "f"}, active{0,1,1,1,0,1}); 136 | test(__LINE__, {"b", "c", "d", "e", "f"}, active{0,1,1,1,1,1}); 137 | 138 | test(__LINE__, {"b", "c", "f", "a"}, active{1,1,1,0,0,1}); 139 | test(__LINE__, {"b", "c", "d", "f", "a"}, active{1,1,1,1,0,1}); 140 | test(__LINE__, {"b", "c", "d", "e", "f", "a"}, active{1,1,1,1,1,1}); 141 | 142 | test(__LINE__, {"b", "c", "a", "f"}, active{1,1,1,0,0,1}); 143 | test(__LINE__, {"b", "c", "d", "a", "f"}, active{1,1,1,1,0,1}); 144 | test(__LINE__, {"b", "c", "d", "e", "a", "f"}, active{1,1,1,1,1,1}); 145 | 146 | test(__LINE__, {"f", "b", "c", "a"}, active{1,1,1,0,0,1}); 147 | test(__LINE__, {"f", "b", "c", "d", "a"}, active{1,1,1,1,0,1}); 148 | test(__LINE__, {"f", "b", "c", "d", "e", "a"}, active{1,1,1,1,1,1}); 149 | 150 | test(__LINE__, {"a", "b", "c"}, active{1,1,1,0,0,0}); 151 | test(__LINE__, {"a", "b", "c", "d"}, active{1,1,1,1,0,0}); 152 | test(__LINE__, {"a", "b", "c", "d", "e"}, active{1,1,1,1,1,0}); 153 | 154 | test(__LINE__, {"b", "a", "c"}, active{1,1,0,0,0,0}); 155 | test(__LINE__, {"b", "a", "c", "d"}, active{1,1,0,0,0,0}); 156 | test(__LINE__, {"b", "a", "c", "d", "e"}, active{1,1,0,0,0,0}); 157 | 158 | test(__LINE__, {"b", "a", "c"}, active{1,1,0,0,0,0}); 159 | test(__LINE__, {"b", "c", "a", "d", "f", "e"}, active{1,1,1,0,0,1}); 160 | 161 | test(__LINE__, {"c", "b"}, active{0,1,0,0,0,0}); 162 | test(__LINE__, {"d", "b"}, active{0,1,0,0,0,0}); 163 | test(__LINE__, {"e", "b"}, active{0,1,0,0,0,0}); 164 | test(__LINE__, {"c", "d", "b"}, active{0,1,0,0,0,0}); 165 | test(__LINE__, {"b", "d", "c"}, active{0,1,1,0,0,0}); 166 | test(__LINE__, {"b", "c", "e", "d"}, active{0,1,1,1,0,0}); 167 | test(__LINE__, {"b", "d", "c", "e"}, active{0,1,1,0,0,0}); 168 | 169 | test(__LINE__, {"b", "d"}, active{0,1,0,0,0,0}); 170 | test(__LINE__, {"b", "e"}, active{0,1,0,0,0,0}); 171 | 172 | test(__LINE__, {"c", "d"}, active{}); 173 | test(__LINE__, {"c", "e"}, active{}); 174 | test(__LINE__, {"d", "c"}, active{}); 175 | test(__LINE__, {"d", "e"}, active{}); 176 | test(__LINE__, {"e", "d"}, active{}); 177 | test(__LINE__, {"e", "c"}, active{}); 178 | } 179 | catch(std::exception& e) { 180 | std::cerr << e.what() << std::endl; 181 | return 1; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /test/blocking_test06.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, bool c_, bool d_, bool e_, bool f_) : 19 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_} 20 | {} 21 | bool a = false, b = false, c = false, d = false, e = false, f = false; 22 | 23 | friend bool operator == (const active& x, const active& y) noexcept { 24 | return (x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d && 25 | x.e == y.e && x.f == y.f); 26 | } 27 | }; 28 | 29 | 30 | //------------------------------------------------------------------- 31 | void test(int lineNo, 32 | const std::initializer_list args, 33 | const active& matches) 34 | { 35 | using namespace clipp; 36 | 37 | active m; 38 | 39 | auto cli1 = ( 40 | ( 41 | option("a").set(m.a), 42 | option("b").set(m.b), 43 | option("c").set(m.c) 44 | ).doc("group abc") 45 | & ( 46 | option("d").set(m.d), 47 | option("e").set(m.e), 48 | option("f").set(m.f) 49 | ).doc("group def") 50 | ); 51 | 52 | run_wrapped_variants({ __FILE__, lineNo }, args, cli1, 53 | [&]{ m = active{}; }, 54 | [&]{ return m == matches; }); 55 | 56 | 57 | auto cli2 = ( 58 | ( 59 | option("x"), 60 | ( 61 | option("a").set(m.a), 62 | option("b").set(m.b), 63 | option("c").set(m.c) 64 | ).doc("group abc") 65 | ).doc("group x(abc)") 66 | & ( 67 | option("d").set(m.d), 68 | option("e").set(m.e), 69 | option("f").set(m.f) 70 | ).doc("group def") 71 | ); 72 | 73 | run_wrapped_variants({ __FILE__, lineNo }, args, cli2, 74 | [&]{ m = active{}; }, 75 | [&]{ return m == matches; }); 76 | 77 | 78 | auto cli3 = ( 79 | ( 80 | ( option("a").set(m.a), 81 | option("b").set(m.b) 82 | ).doc("group ab") 83 | , 84 | option("c").set(m.c) 85 | ).doc("group (ab)c") 86 | & ( 87 | ( option("d").set(m.d), 88 | option("e").set(m.e) 89 | ).doc("group de") 90 | , 91 | option("f").set(m.f) 92 | ).doc("group (de)f") 93 | ); 94 | 95 | run_wrapped_variants({ __FILE__, lineNo }, args, cli3, 96 | [&]{ m = active{}; }, 97 | [&]{ return m == matches; }); 98 | 99 | 100 | auto cli4 = ( 101 | ( 102 | ( 103 | ( option("a").set(m.a), 104 | option("b").set(m.b) 105 | ).doc("group ab") 106 | , 107 | option("c").set(m.c) 108 | ).doc("group (ab)c"), 109 | option("x") 110 | ).doc("group ((ab)c)x") 111 | & ( 112 | ( 113 | ( option("d").set(m.d), 114 | option("e").set(m.e) 115 | ).doc("group de") 116 | , 117 | option("f").set(m.f) 118 | ).doc("group (de)f"), 119 | option("y") 120 | ).doc("group ((de)f)y") 121 | ); 122 | 123 | run_wrapped_variants({ __FILE__, lineNo }, args, cli4, 124 | [&]{ m = active{}; }, 125 | [&]{ return m == matches; }); 126 | 127 | } 128 | 129 | 130 | 131 | //------------------------------------------------------------------- 132 | int main() 133 | { 134 | try { 135 | test(__LINE__, {""}, active{}); 136 | 137 | test(__LINE__, {"a"}, active{1,0,0,0,0,0}); 138 | test(__LINE__, {"b"}, active{0,1,0,0,0,0}); 139 | test(__LINE__, {"c"}, active{0,0,1,0,0,0}); 140 | 141 | test(__LINE__, {"d"}, active{0,0,0,0,0,0}); 142 | test(__LINE__, {"e"}, active{0,0,0,0,0,0}); 143 | test(__LINE__, {"f"}, active{0,0,0,0,0,0}); 144 | 145 | test(__LINE__, {"a", "d"}, active{1,0,0,1,0,0}); 146 | test(__LINE__, {"a", "e"}, active{1,0,0,0,1,0}); 147 | test(__LINE__, {"a", "f"}, active{1,0,0,0,0,1}); 148 | 149 | test(__LINE__, {"b", "d"}, active{0,1,0,1,0,0}); 150 | test(__LINE__, {"b", "e"}, active{0,1,0,0,1,0}); 151 | test(__LINE__, {"b", "f"}, active{0,1,0,0,0,1}); 152 | 153 | test(__LINE__, {"c", "d"}, active{0,0,1,1,0,0}); 154 | test(__LINE__, {"c", "e"}, active{0,0,1,0,1,0}); 155 | test(__LINE__, {"c", "f"}, active{0,0,1,0,0,1}); 156 | 157 | test(__LINE__, {"c", "b", "d"}, active{0,1,1,1,0,0}); 158 | test(__LINE__, {"b", "a", "e"}, active{1,1,0,0,1,0}); 159 | test(__LINE__, {"c", "a", "f"}, active{1,0,1,0,0,1}); 160 | 161 | test(__LINE__, {"c", "a", "b", "d"}, active{1,1,1,1,0,0}); 162 | test(__LINE__, {"b", "c", "a", "e"}, active{1,1,1,0,1,0}); 163 | test(__LINE__, {"c", "b", "a", "f"}, active{1,1,1,0,0,1}); 164 | 165 | test(__LINE__, {"c", "a", "b", "d", "e"}, active{1,1,1,1,1,0}); 166 | test(__LINE__, {"b", "c", "a", "e", "d"}, active{1,1,1,1,1,0}); 167 | test(__LINE__, {"c", "b", "a", "f", "d"}, active{1,1,1,1,0,1}); 168 | test(__LINE__, {"c", "b", "a", "d", "f"}, active{1,1,1,1,0,1}); 169 | test(__LINE__, {"c", "b", "a", "f", "e"}, active{1,1,1,0,1,1}); 170 | test(__LINE__, {"c", "b", "a", "e", "f"}, active{1,1,1,0,1,1}); 171 | 172 | test(__LINE__, {"a", "b", "c", "d", "e", "f"}, active{1,1,1,1,1,1}); 173 | test(__LINE__, {"c", "b", "a", "f", "e", "d"}, active{1,1,1,1,1,1}); 174 | test(__LINE__, {"c", "b", "a", "f", "d", "e"}, active{1,1,1,1,1,1}); 175 | test(__LINE__, {"c", "b", "a", "e", "d", "f"}, active{1,1,1,1,1,1}); 176 | } 177 | catch(std::exception& e) { 178 | std::cerr << e.what() << std::endl; 179 | return 1; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /test/blocking_test07.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | //don't include anything else before the test subject 12 | #include "testing.h" 13 | 14 | 15 | //------------------------------------------------------------------- 16 | struct active { 17 | active() = default; 18 | explicit 19 | active(bool a_, bool b_, bool c_, bool d_, bool e_, bool f_) : 20 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_} 21 | {} 22 | bool a = false, b = false, c = false, d = false, e = false, f = false; 23 | 24 | friend bool operator == (const active& x, const active& y) noexcept { 25 | return (x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d && 26 | x.e == y.e && x.f == y.f); 27 | } 28 | }; 29 | 30 | 31 | //------------------------------------------------------------------- 32 | void test(int lineNo, 33 | const std::initializer_list args, 34 | const active& matches) 35 | { 36 | using namespace clipp; 37 | 38 | active m; 39 | 40 | auto cli = ( 41 | option("a").set(m.a), 42 | ( 43 | option("b").set(m.b) | 44 | command("c").set(m.c) | 45 | command("d").set(m.d) | 46 | option("e").set(m.e) 47 | ), 48 | option("f").set(m.f) 49 | ); 50 | 51 | run_test({ __FILE__, lineNo }, args, cli, [&]{ return m == matches; }); 52 | } 53 | 54 | 55 | //------------------------------------------------------------------- 56 | int main() 57 | { 58 | try { 59 | test(__LINE__, {""}, active{}); 60 | 61 | test(__LINE__, {"a"}, active{1, 0,0,0,0, 0}); 62 | test(__LINE__, {"b"}, active{0, 1,0,0,0, 0}); 63 | test(__LINE__, {"c"}, active{0, 0,1,0,0, 0}); 64 | test(__LINE__, {"d"}, active{0, 0,0,1,0, 0}); 65 | test(__LINE__, {"e"}, active{0, 0,0,0,1, 0}); 66 | test(__LINE__, {"f"}, active{0, 0,0,0,0, 1}); 67 | 68 | test(__LINE__, {"a", "b"}, active{1, 1,0,0,0, 0}); 69 | test(__LINE__, {"a", "c"}, active{1, 0,1,0,0, 0}); 70 | test(__LINE__, {"a", "d"}, active{1, 0,0,1,0, 0}); 71 | test(__LINE__, {"a", "e"}, active{1, 0,0,0,1, 0}); 72 | test(__LINE__, {"a", "f"}, active{1, 0,0,0,0, 1}); 73 | 74 | test(__LINE__, {"a", "b", "f"}, active{1, 1,0,0,0, 1}); 75 | test(__LINE__, {"a", "c", "f"}, active{1, 0,1,0,0, 1}); 76 | test(__LINE__, {"a", "d", "f"}, active{1, 0,0,1,0, 1}); 77 | test(__LINE__, {"a", "e", "f"}, active{1, 0,0,0,1, 1}); 78 | 79 | test(__LINE__, {"f", "b"}, active{0, 1,0,0,0, 1}); 80 | test(__LINE__, {"f", "c"}, active{0, 0,1,0,0, 1}); 81 | test(__LINE__, {"f", "d"}, active{0, 0,0,1,0, 1}); 82 | test(__LINE__, {"f", "e"}, active{0, 0,0,0,1, 1}); 83 | 84 | test(__LINE__, {"b", "f"}, active{0, 1,0,0,0, 1}); 85 | test(__LINE__, {"c", "f"}, active{0, 0,1,0,0, 1}); 86 | test(__LINE__, {"d", "f"}, active{0, 0,0,1,0, 1}); 87 | test(__LINE__, {"e", "f"}, active{0, 0,0,0,1, 1}); 88 | 89 | test(__LINE__, {"b", "f", "a"}, active{1, 1,0,0,0, 1}); 90 | test(__LINE__, {"c", "f", "a"}, active{0, 0,1,0,0, 1}); 91 | test(__LINE__, {"d", "f", "a"}, active{0, 0,0,1,0, 1}); 92 | test(__LINE__, {"e", "f", "a"}, active{1, 0,0,0,1, 1}); 93 | } 94 | catch(std::exception& e) { 95 | std::cerr << e.what() << std::endl; 96 | return 1; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /test/blocking_test08.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, bool c_, bool d_, bool e_, bool f_) : 19 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_} 20 | {} 21 | bool a = false, b = false, c = false, d = false, e = false, f = false; 22 | 23 | friend bool operator == (const active& x, const active& y) noexcept { 24 | return (x.a == y.a && x.b == y.b && x.c == y.c && 25 | x.d == y.d && x.e == y.e && x.f == y.f ); 26 | } 27 | }; 28 | 29 | 30 | //------------------------------------------------------------------- 31 | void test(int lineNo, 32 | const std::initializer_list args, 33 | const active& matches) 34 | { 35 | using namespace clipp; 36 | 37 | active m; 38 | 39 | auto cli = ( 40 | option("a").set(m.a), 41 | option("b").set(m.b) & ( 42 | option("c").set(m.c) & ( 43 | option("d").set(m.d) & option("e").set(m.e) 44 | ) 45 | ), 46 | option("f").set(m.f) 47 | ); 48 | 49 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 50 | [&]{ m = active{}; }, 51 | [&]{ return m == matches; }); 52 | } 53 | 54 | 55 | //------------------------------------------------------------------- 56 | int main() 57 | { 58 | try { 59 | test(__LINE__, {""}, active{}); 60 | 61 | test(__LINE__, {"a"}, active{1, 0,0,0,0, 0}); 62 | test(__LINE__, {"f"}, active{0, 0,0,0,0, 1}); 63 | 64 | test(__LINE__, {"b"}, active{0, 1,0,0,0, 0}); 65 | test(__LINE__, {"b", "c"}, active{0, 1,1,0,0, 0}); 66 | test(__LINE__, {"b", "c", "d"}, active{0, 1,1,1,0, 0}); 67 | test(__LINE__, {"b", "c", "d", "e"}, active{0, 1,1,1,1, 0}); 68 | 69 | test(__LINE__, {"a", "b"}, active{1, 1,0,0,0, 0}); 70 | test(__LINE__, {"a", "b", "c"}, active{1, 1,1,0,0, 0}); 71 | test(__LINE__, {"a", "b", "c", "d"}, active{1, 1,1,1,0, 0}); 72 | test(__LINE__, {"a", "b", "c", "d", "e"}, active{1, 1,1,1,1, 0}); 73 | 74 | test(__LINE__, {"a", "b", "f"}, active{1, 1,0,0,0, 1}); 75 | test(__LINE__, {"a", "b", "c", "f"}, active{1, 1,1,0,0, 1}); 76 | test(__LINE__, {"a", "b", "c", "d", "f"}, active{1, 1,1,1,0, 1}); 77 | test(__LINE__, {"a", "b", "c", "d", "e", "f"}, active{1, 1,1,1,1, 1}); 78 | 79 | test(__LINE__, {"f", "b", "a"}, active{1, 1,0,0,0, 1}); 80 | test(__LINE__, {"f", "b", "c", "a"}, active{1, 1,1,0,0, 1}); 81 | test(__LINE__, {"f", "b", "c", "d", "a"}, active{1, 1,1,1,0, 1}); 82 | test(__LINE__, {"f", "b", "c", "d", "e", "a"}, active{1, 1,1,1,1, 1}); 83 | 84 | test(__LINE__, {"c"}, active{0, 0,0,0,0, 0}); 85 | test(__LINE__, {"d"}, active{0, 0,0,0,0, 0}); 86 | test(__LINE__, {"e"}, active{0, 0,0,0,0, 0}); 87 | 88 | test(__LINE__, {"b", "d"}, active{0, 1,0,0,0, 0}); 89 | test(__LINE__, {"b", "e"}, active{0, 1,0,0,0, 0}); 90 | test(__LINE__, {"b", "c", "e"}, active{0, 1,1,0,0, 0}); 91 | } 92 | catch(std::exception& e) { 93 | std::cerr << e.what() << std::endl; 94 | return 1; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /test/blocking_test09.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(const std::string f_, 19 | std::initializer_list ts, 20 | bool http_, bool ftp_, 21 | std::initializer_list ws) : 22 | http{http_}, ftp{ftp_}, f{f_}, tgts{ts}, wrong{ws} 23 | {} 24 | bool http = false, ftp = false; 25 | 26 | std::string f; 27 | std::vector tgts; 28 | std::vector wrong; 29 | 30 | friend bool operator == (const active& x, const active& y) noexcept { 31 | return x.http == y.http && x.f == y.f && 32 | std::equal(x.tgts.begin(), x.tgts.end(), y.tgts.begin()) && 33 | std::equal(x.wrong.begin(), x.wrong.end(), y.wrong.begin()); 34 | } 35 | }; 36 | 37 | 38 | //------------------------------------------------------------------- 39 | void test(int lineNo, 40 | const std::initializer_list args, 41 | const active& matches) 42 | { 43 | using namespace clipp; 44 | 45 | active m; 46 | 47 | auto cli = ( 48 | value("file", m.f), 49 | required("-t") & values(match::prefix_not("-"), "target", m.tgts), 50 | option("--http").set(m.http) | option("--ftp").set(m.ftp), 51 | any_other(m.wrong) 52 | ); 53 | 54 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 55 | [&]{ m = active{}; }, 56 | [&]{ return m == matches; }); 57 | } 58 | 59 | 60 | //------------------------------------------------------------------- 61 | int main() 62 | { 63 | try { 64 | test(__LINE__, {""}, active{}); 65 | 66 | test(__LINE__, {"abc"}, active{"abc", {}, false, false, {}}); 67 | 68 | test(__LINE__, {"abc", "--http"}, active{"abc", {}, true, false, {}}); 69 | test(__LINE__, {"abc", "--ftp"}, active{"abc", {}, false, true, {}}); 70 | test(__LINE__, {"abc", "--ftp", "--http"}, active{"abc", {}, false, true, {}}); 71 | 72 | test(__LINE__, {"abc", "-t", "--http"}, active{"abc", {}, true, false, {}}); 73 | test(__LINE__, {"abc", "-t", "--ftp"}, active{"abc", {}, false, true, {}}); 74 | 75 | test(__LINE__, {"abc", "-t", "tgt1", "--http"}, active{"abc", {"tgt1"}, true, false, {}}); 76 | test(__LINE__, {"abc", "-t", "tgt1", "--ftp"}, active{"abc", {"tgt1"}, false, true, {}}); 77 | 78 | test(__LINE__, {"abc", "-t", "tgt1", "t2", "--http"}, active{"abc", {"tgt1", "t2"}, true, false, {}}); 79 | test(__LINE__, {"abc", "-t", "tgt1", "t2", "--ftp"}, active{"abc", {"tgt1", "t2"}, false, true, {}}); 80 | 81 | 82 | test(__LINE__, {"abc", "x"}, active{"abc", {}, false, false, {"x"}}); 83 | test(__LINE__, {"abc", "-x"}, active{"abc", {}, false, false, {"-x"}}); 84 | test(__LINE__, {"abc", "-ftp"}, active{"abc", {}, false, false, {"-ftp"}}); 85 | test(__LINE__, {"abc", "--ftpx"}, active{"abc", {}, false, false, {"--ftpx"}}); 86 | 87 | test(__LINE__, {"abc", "-x", "--http"}, active{"abc", {}, true, false, {"-x"}}); 88 | test(__LINE__, {"abc", "-x", "--ftp"}, active{"abc", {}, false, true, {"-x"}}); 89 | test(__LINE__, {"abc", "-x", "--ftp", "--http"}, active{"abc", {}, false, true, {"-x"}}); 90 | 91 | test(__LINE__, {"abc", "-t", "-x", "--http"}, active{"abc", {}, true, false, {"-x"}}); 92 | test(__LINE__, {"abc", "-t", "-x", "--ftp"}, active{"abc", {}, false, true, {"-x"}}); 93 | 94 | test(__LINE__, {"abc", "-t", "tgt1", "-x", "--http"}, active{"abc", {"tgt1"}, true, false, {"-x"}}); 95 | test(__LINE__, {"abc", "-t", "tgt1", "-x", "--ftp"}, active{"abc", {"tgt1"}, false, true, {"-x"}}); 96 | 97 | test(__LINE__, {"abc", "-t", "tgt1", "t2", "-x", "--http"}, active{"abc", {"tgt1", "t2"}, true, false, {"-x"}}); 98 | test(__LINE__, {"abc", "-t", "tgt1", "t2", "-x", "--ftp"}, active{"abc", {"tgt1", "t2"}, false, true, {"-x"}}); 99 | 100 | } 101 | catch(std::exception& e) { 102 | std::cerr << e.what() << std::endl; 103 | return 1; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /test/blocking_test10.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool n_, std::initializer_list nums_, 19 | bool s_, const std::string& str_) 20 | : 21 | str{str_}, nums{nums_}, n{n_}, s{s_} 22 | {} 23 | 24 | std::string str; 25 | std::vector nums; 26 | bool n = false, s = false; 27 | 28 | friend bool operator == (const active& x, const active& y) noexcept { 29 | return x.n == y.n && x.s == y.s && x.str == y.str && 30 | std::equal(x.nums.begin(), x.nums.end(), y.nums.begin()); 31 | } 32 | }; 33 | 34 | 35 | //------------------------------------------------------------------- 36 | void test(int lineNo, 37 | const std::initializer_list args, 38 | const active& matches) 39 | { 40 | using namespace clipp; 41 | 42 | active m; 43 | 44 | auto cli = ( 45 | option("-n", "--num").set(m.n) & integers("nums", m.nums), 46 | option("-s", "--str").set(m.s) & value("str", m.str) 47 | ); 48 | 49 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 50 | [&]{ m = active{}; }, 51 | [&]{ return m == matches; }); 52 | } 53 | 54 | 55 | //------------------------------------------------------------------- 56 | int main() 57 | { 58 | try { 59 | test(__LINE__, {""}, active{}); 60 | 61 | 62 | test(__LINE__, {"-n"}, active{true, {}, false, ""}); 63 | test(__LINE__, {"-n", "1"}, active{true, {1}, false, ""}); 64 | test(__LINE__, {"-n", "1", "5"}, active{true, {1,5}, false, ""}); 65 | test(__LINE__, {"-n", "1", "-3", "4"}, active{true, {1,-3,4}, false, ""}); 66 | 67 | test(__LINE__, {"-s"}, active{false, {}, true, ""}); 68 | test(__LINE__, {"-s", "xyz"}, active{false, {}, true, "xyz"}); 69 | 70 | test(__LINE__, {"-n", "1", "ab"}, active{true, {1}, false, ""}); 71 | test(__LINE__, {"-n", "1", "2", "ab"}, active{true, {1,2}, false, ""}); 72 | test(__LINE__, {"-n", "1", "-3", "ab"}, active{true, {1,-3}, false, ""}); 73 | 74 | test(__LINE__, {"-n", "1", "-s", "ab"}, active{true, {1}, true, "ab"}); 75 | test(__LINE__, {"-n", "1", "2", "-s", "ab"}, active{true, {1,2}, true, "ab"}); 76 | test(__LINE__, {"-n", "1", "-3", "-s", "ab"}, active{true, {1,-3}, true, "ab"}); 77 | 78 | } 79 | catch(std::exception& e) { 80 | std::cerr << e.what() << std::endl; 81 | return 1; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /test/empty_args.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool o_, std::string ov_ = "_", std::string pv_ = "_"): 19 | o{o_}, ov{std::move(ov_)}, pv{std::move(pv_)} 20 | {} 21 | 22 | bool o = false; 23 | std::string ov = "_"; 24 | std::string pv = "_"; 25 | 26 | friend bool operator == (const active& x, const active& y) noexcept { 27 | return (x.o == y.o && x.ov == y.ov && x.pv == y.pv); 28 | } 29 | }; 30 | 31 | 32 | //------------------------------------------------------------------- 33 | void test_empty(int lineNo, 34 | const std::initializer_list args, 35 | const active& matches) 36 | { 37 | using namespace clipp; 38 | 39 | active m; 40 | auto cli = ( 41 | option("-o", "--opt").set(m.o) & value(match::any, "O", m.ov), 42 | value("P", m.pv) 43 | ); 44 | 45 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 46 | [&]{ m = active{}; }, 47 | [&]{ return m == matches; }); 48 | 49 | } 50 | 51 | 52 | //------------------------------------------------------------------- 53 | void test_nonempty(int lineNo, 54 | const std::initializer_list args, 55 | const active& matches) 56 | { 57 | using namespace clipp; 58 | 59 | active m; 60 | auto cli = ( 61 | option("-o", "--opt").set(m.o) & value(match::nonempty, "O", m.ov), 62 | value("P", m.pv) 63 | ); 64 | 65 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 66 | [&]{ m = active{}; }, 67 | [&]{ return m == matches; }); 68 | 69 | } 70 | 71 | 72 | //------------------------------------------------------------------- 73 | int main() 74 | { 75 | try { 76 | test_empty(__LINE__, {}, active{}); 77 | test_empty(__LINE__, {""}, active{}); 78 | test_empty(__LINE__, {"-o"}, active{true}); 79 | test_empty(__LINE__, {"-o", ""}, active{true, ""}); 80 | test_empty(__LINE__, {"-o", "X"}, active{true, "X"}); 81 | test_empty(__LINE__, {"X"}, active{false, "_", "X"}); 82 | test_empty(__LINE__, {"-o", "", "X"}, active{true, "", "X"}); 83 | 84 | 85 | test_nonempty(__LINE__, {}, active{}); 86 | test_nonempty(__LINE__, {""}, active{}); 87 | test_nonempty(__LINE__, {"-o"}, active{true}); 88 | test_nonempty(__LINE__, {"-o", ""}, active{true}); 89 | test_nonempty(__LINE__, {"-o", "X"}, active{true, "X"}); 90 | test_nonempty(__LINE__, {"X"}, active{false, "_", "X"}); 91 | 92 | //ambiguous -> cannot map to value "P", expects value "O" first 93 | test_nonempty(__LINE__, {"-o", "", "X"}, active{true}); 94 | 95 | } 96 | catch(std::exception& e) { 97 | std::cerr << e.what() << std::endl; 98 | return 1; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /test/flag_param_factories_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | /** @brief test if parameter factory call expressions compile 16 | */ 17 | void test_init_expressions_compile(int argc, char* argv[]) 18 | { 19 | using namespace clipp; 20 | 21 | arg_string a ("-a"); 22 | arg_string b ("-b"); 23 | arg_string c ("-c"); 24 | 25 | auto cli = ( 26 | option("-a", "-b", "-c"), 27 | option(a, "-b", "-c"), 28 | option("-a", b, "-c"), 29 | option("-a", "-b", c), 30 | option(a, b, "-c"), 31 | option(a, "-b", c), 32 | option("-a", b, c), 33 | option(a, b, c) 34 | , 35 | required("-a", "-b", "-c"), 36 | required(a, "-b", "-c"), 37 | required("-a", b, "-c"), 38 | required("-a", "-b", c), 39 | required(a, b, "-c"), 40 | required(a, "-b", c), 41 | required("-a", b, c), 42 | required(a, b, c) 43 | , 44 | command("-a", "-b", "-c"), 45 | command(a, "-b", "-c"), 46 | command("-a", b, "-c"), 47 | command("-a", "-b", c), 48 | command(a, b, "-c"), 49 | command(a, "-b", c), 50 | command("-a", b, c), 51 | command(a, b, c) 52 | ); 53 | 54 | parse(argc, argv, cli); 55 | } 56 | 57 | 58 | //------------------------------------------------------------------- 59 | template 60 | void test_param_init(int lineNo, 61 | std::initializer_list expexted, 62 | Strings&&... init) 63 | { 64 | using namespace clipp; 65 | 66 | auto p = parameter{std::forward(init)...}; 67 | 68 | if( !std::equal(begin(p.flags()), end(p.flags()), begin(expexted)) ) { 69 | throw std::runtime_error{"failed test " + std::string(__FILE__) + 70 | " in line " + std::to_string(lineNo)}; 71 | } 72 | } 73 | 74 | 75 | 76 | //------------------------------------------------------------------- 77 | int main(int argc, char* argv[]) 78 | { 79 | test_init_expressions_compile(argc, argv); 80 | 81 | using clipp::arg_string; 82 | using clipp::arg_list; 83 | 84 | try { 85 | //one letter flags 86 | test_param_init( __LINE__ , {"a"}, "a"); 87 | test_param_init( __LINE__ , {"a", "b"}, "a", "b"); 88 | test_param_init( __LINE__ , {"a", "b", "c"}, "a", "b", "c"); 89 | test_param_init( __LINE__ , {"a", "b", "c", "d"}, "a", "b", "c", "d"); 90 | 91 | //mixed string types 92 | test_param_init( __LINE__ , {"a"}, arg_string("a")); 93 | test_param_init( __LINE__ , {"a", "b"}, arg_string("a"), "b"); 94 | test_param_init( __LINE__ , {"a", "b"}, "a", arg_string("b")); 95 | test_param_init( __LINE__ , {"a", "b", "c"}, "a", arg_string("b"), "c"); 96 | 97 | //lists 98 | test_param_init( __LINE__ , {"a"}, arg_list{"a"}); 99 | test_param_init( __LINE__ , {"a", "b"}, arg_list{"a", "b"}); 100 | test_param_init( __LINE__ , {"a", "b", "c"}, arg_list{"a", "b", "c"}); 101 | test_param_init( __LINE__ , {"a", "b", "c", "d"}, arg_list{"a", "b", "c", "d"}); 102 | 103 | //mulit-letter flags 104 | test_param_init( __LINE__ , {"-a"}, "-a"); 105 | test_param_init( __LINE__ , {"-a", "-b"}, "-a", "-b"); 106 | test_param_init( __LINE__ , {"-a", "-b", "-c"}, "-a", "-b", "-c"); 107 | test_param_init( __LINE__ , {"-a", "-b", "-c", "-d"}, "-a", "-b", "-c", "-d"); 108 | 109 | test_param_init( __LINE__ , {"a", "-b"}, "a", "-b"); 110 | test_param_init( __LINE__ , {"a", "-b", "c"}, "a", "-b", "c"); 111 | test_param_init( __LINE__ , {"a", "-b", "c", "d"}, "a", "-b", "c", "d"); 112 | 113 | test_param_init( __LINE__ , {"--aa"}, "--aa"); 114 | test_param_init( __LINE__ , {"--aa", "--bb-ee"}, "--aa", "--bb-ee"); 115 | test_param_init( __LINE__ , {"--aa", "--bb-ee", "cee"}, "--aa", "--bb-ee", "cee"); 116 | 117 | //empty flags are not allowed 118 | test_param_init( __LINE__ , {}, ""); 119 | test_param_init( __LINE__ , {"a"}, "a", ""); 120 | test_param_init( __LINE__ , {"a"}, "", "a"); 121 | test_param_init( __LINE__ , {"a"}, "", "a", ""); 122 | 123 | test_param_init( __LINE__ , {"a", "b"}, "", "a", "b"); 124 | test_param_init( __LINE__ , {"a", "b"}, "a", "", "b"); 125 | test_param_init( __LINE__ , {"a", "b"}, "a", "b", ""); 126 | 127 | test_param_init( __LINE__ , {"a", "b", "c"}, "", "a", "b", "c"); 128 | test_param_init( __LINE__ , {"a", "b", "c"}, "a", "", "b", "c"); 129 | test_param_init( __LINE__ , {"a", "b", "c"}, "a", "b", "", "c"); 130 | test_param_init( __LINE__ , {"a", "b", "c"}, "a", "b", "c", ""); 131 | 132 | //flags with spaces are not allowed 133 | test_param_init( __LINE__ , {"a", "b"}, " ", "a", "b"); 134 | test_param_init( __LINE__ , {"a", "b"}, "a", " ", "b"); 135 | test_param_init( __LINE__ , {"a", "b"}, "a", "b", " "); 136 | 137 | test_param_init( __LINE__ , {"a", "b"}, " ", "a", "b"); 138 | test_param_init( __LINE__ , {"a", "b"}, "a", " ", "b"); 139 | test_param_init( __LINE__ , {"a", "b"}, "a", "b", " "); 140 | 141 | test_param_init( __LINE__ , {"-a"}, "- a" ); 142 | test_param_init( __LINE__ , {"-a", "-b"}, "-a", "- b"); 143 | test_param_init( __LINE__ , {"-a", "-b", "-c"}, "-a", "- b", "-c"); 144 | test_param_init( __LINE__ , {"-a", "-b", "-c", "-d"}, "-a", "-b", "- c", "-d"); 145 | 146 | test_param_init( __LINE__ , {"-a"}, " - a" ); 147 | test_param_init( __LINE__ , {"-a", "-b"}, "- a ", " - b"); 148 | test_param_init( __LINE__ , {"-a", "-b", "-c"}, "-a", "- b", " - c"); 149 | test_param_init( __LINE__ , {"-a", "-b", "-c", "-d"}, "- a ", "- b", " - c", "-d"); 150 | 151 | } 152 | catch(std::exception& e) { 153 | std::cerr << e.what() << std::endl; 154 | return 1; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /test/joined_flags_test1.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | active(bool a_, bool b_): a{a_}, b{b_} {} 18 | bool a = false, b = false; 19 | 20 | friend bool operator == (const active& x, const active& y) noexcept { 21 | return (x.a == y.a && x.b == y.b); 22 | } 23 | }; 24 | 25 | 26 | //------------------------------------------------------------------- 27 | static void 28 | test(int lineNo, 29 | const std::initializer_list args, 30 | const active& matches ) 31 | { 32 | using namespace clipp; 33 | active m; 34 | 35 | auto cli = joinable( 36 | option("a").set(m.a), 37 | option("b").set(m.b) 38 | ); 39 | 40 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 41 | [&]{ m = active{}; }, 42 | [&]{ return m == matches; }); 43 | } 44 | 45 | 46 | //------------------------------------------------------------------- 47 | int main() 48 | { 49 | using std::string; 50 | 51 | try { 52 | test(__LINE__, {""}, active{}); 53 | 54 | test(__LINE__, {"a"}, active{1,0}); 55 | test(__LINE__, {"b"}, active{0,1}); 56 | test(__LINE__, {"a","b"}, active{1,1}); 57 | test(__LINE__, {"b","a"}, active{1,1}); 58 | test(__LINE__, {"ab"}, active{1,1}); 59 | test(__LINE__, {"ba"}, active{1,1}); 60 | //fail cases 61 | test(__LINE__, {"-ab"}, active{}); 62 | test(__LINE__, {"-ba"}, active{}); 63 | test(__LINE__, {"bac"}, active{}); 64 | } 65 | catch(std::exception& e) { 66 | std::cerr << e.what() << std::endl; 67 | return 1; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /test/joined_flags_test2.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | active(bool a_, bool b_): a{a_}, b{b_} {} 18 | bool a = false, b = false; 19 | 20 | friend bool operator == (const active& x, const active& y) noexcept { 21 | return (x.a == y.a && x.b == y.b); 22 | } 23 | }; 24 | 25 | 26 | //------------------------------------------------------------------- 27 | static void 28 | test(int lineNo, 29 | const std::initializer_list args, 30 | const active& matches) 31 | { 32 | using namespace clipp; 33 | active m; 34 | 35 | auto cli = joinable( 36 | option("-a").set(m.a), 37 | option("-b").set(m.b) ); 38 | 39 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 40 | [&]{ m = active{}; }, 41 | [&]{ return m == matches; }); 42 | } 43 | 44 | 45 | //------------------------------------------------------------------- 46 | int main() 47 | { 48 | using std::string; 49 | 50 | try { 51 | test(__LINE__, {""}, active{}); 52 | 53 | test(__LINE__, {"-a"}, active{1,0}); 54 | test(__LINE__, {"-b"}, active{0,1}); 55 | test(__LINE__, {"-a","-b"}, active{1,1}); 56 | test(__LINE__, {"-b","-a"}, active{1,1}); 57 | test(__LINE__, {"-ab"}, active{1,1}); 58 | test(__LINE__, {"-ba"}, active{1,1}); 59 | test(__LINE__, {"-a-b"}, active{1,1}); 60 | test(__LINE__, {"-b-a"}, active{1,1}); 61 | //fail cases 62 | test(__LINE__, {"--ab"}, active{}); 63 | test(__LINE__, {"--ab"}, active{}); 64 | test(__LINE__, {"bca"}, active{}); 65 | test(__LINE__, {"bca-"}, active{}); 66 | test(__LINE__, {"bc-a"}, active{}); 67 | } 68 | catch(std::exception& e) { 69 | std::cerr << e.what() << std::endl; 70 | return 1; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /test/joined_flags_test3.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | active(bool a_, bool b_, bool c_, bool d_): 18 | a{a_}, b{b_}, c{c_}, d{d_} 19 | {} 20 | bool a = false, b = false, c = false, d = false; 21 | 22 | friend bool operator == (const active& x, const active& y) noexcept { 23 | return x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d; 24 | } 25 | }; 26 | 27 | 28 | //------------------------------------------------------------------- 29 | void test(int lineNo, 30 | const std::initializer_list args, 31 | const active& matches) 32 | { 33 | using namespace clipp; 34 | active m; 35 | 36 | auto cli = joinable( 37 | option("a").set(m.a), 38 | option("b").set(m.b), 39 | option("c").set(m.c), 40 | option("d").set(m.d)); 41 | 42 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 43 | [&]{ m = active{}; }, 44 | [&]{ return m == matches; }); 45 | } 46 | 47 | 48 | //------------------------------------------------------------------- 49 | int main() 50 | { 51 | using std::string; 52 | 53 | try { 54 | test(__LINE__, {""}, active{}); 55 | 56 | test(__LINE__, {"a"}, active{1,0,0,0}); 57 | test(__LINE__, {"b"}, active{0,1,0,0}); 58 | test(__LINE__, {"c"}, active{0,0,1,0}); 59 | test(__LINE__, {"d"}, active{0,0,0,1}); 60 | test(__LINE__, {"a","b"}, active{1,1,0,0}); 61 | test(__LINE__, {"c","b"}, active{0,1,1,0}); 62 | test(__LINE__, {"d","a","c"}, active{1,0,1,1}); 63 | test(__LINE__, {"ab"}, active{1,1,0,0}); 64 | test(__LINE__, {"ac"}, active{1,0,1,0}); 65 | test(__LINE__, {"ad"}, active{1,0,0,1}); 66 | test(__LINE__, {"abd"}, active{1,1,0,1}); 67 | test(__LINE__, {"cab"}, active{1,1,1,0}); 68 | test(__LINE__, {"abcd"}, active{1,1,1,1}); 69 | test(__LINE__, {"cadb"}, active{1,1,1,1}); 70 | //fail cases 71 | test(__LINE__, {"cxadb"}, active{}); 72 | test(__LINE__, {"-abc"}, active{}); 73 | test(__LINE__, {"-bca"}, active{}); 74 | test(__LINE__, {"cab-"}, active{}); 75 | test(__LINE__, {"c-ad-"}, active{}); 76 | } 77 | catch(std::exception& e) { 78 | std::cerr << e.what() << std::endl; 79 | return 1; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /test/joined_flags_test4.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | active(bool a_, bool b_, bool c_, bool d_): 18 | a{a_}, b{b_}, c{c_}, d{d_} 19 | {} 20 | bool a = false, b = false, c = false, d = false; 21 | 22 | friend bool operator == (const active& x, const active& y) noexcept { 23 | return x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d; 24 | } 25 | }; 26 | 27 | 28 | //------------------------------------------------------------------- 29 | void test(int lineNo, 30 | const std::initializer_list args, 31 | const active& matches) 32 | { 33 | using namespace clipp; 34 | active m; 35 | 36 | auto cli = joinable( 37 | option("-a").set(m.a), 38 | option("-b").set(m.b), 39 | option("-c").set(m.c), 40 | option("-d").set(m.d)); 41 | 42 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 43 | [&]{ m = active{}; }, 44 | [&]{ return m == matches; }); 45 | } 46 | 47 | 48 | //------------------------------------------------------------------- 49 | int main() 50 | { 51 | using std::string; 52 | 53 | try { 54 | test(__LINE__, {""}, active{}); 55 | 56 | test(__LINE__, {"-a"}, active{1,0,0,0}); 57 | test(__LINE__, {"-b"}, active{0,1,0,0}); 58 | test(__LINE__, {"-c"}, active{0,0,1,0}); 59 | test(__LINE__, {"-d"}, active{0,0,0,1}); 60 | test(__LINE__, {"-a","-b"}, active{1,1,0,0}); 61 | test(__LINE__, {"-c","-b"}, active{0,1,1,0}); 62 | test(__LINE__, {"-d","-a","-c"}, active{1,0,1,1}); 63 | test(__LINE__, {"-ab"}, active{1,1,0,0}); 64 | test(__LINE__, {"-ac"}, active{1,0,1,0}); 65 | test(__LINE__, {"-ad"}, active{1,0,0,1}); 66 | test(__LINE__, {"-abd"}, active{1,1,0,1}); 67 | test(__LINE__, {"-cab"}, active{1,1,1,0}); 68 | test(__LINE__, {"-abcd"}, active{1,1,1,1}); 69 | test(__LINE__, {"-cadb"}, active{1,1,1,1}); 70 | //fail cases 71 | test(__LINE__, {"cxadb"}, active{}); 72 | test(__LINE__, {"-cxadb"}, active{}); 73 | test(__LINE__, {"--abc"}, active{}); 74 | test(__LINE__, {"--bca"}, active{}); 75 | test(__LINE__, {"-cab-"}, active{}); 76 | test(__LINE__, {"-c-ad-"}, active{}); 77 | } 78 | catch(std::exception& e) { 79 | std::cerr << e.what() << std::endl; 80 | return 1; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /test/joined_flags_test5.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | active(bool a_, bool b_): a{a_}, b{b_} {} 18 | bool a = false, b = false; 19 | 20 | friend bool operator == (const active& x, const active& y) noexcept { 21 | return (x.a == y.a && x.b == y.b); 22 | } 23 | }; 24 | 25 | 26 | //------------------------------------------------------------------- 27 | void test(int lineNo, 28 | const std::initializer_list args, 29 | const active& matches) 30 | { 31 | using namespace clipp; 32 | active m; 33 | 34 | auto cli = joinable( 35 | option(">:a").set(m.a), 36 | option(">:b").set(m.b) 37 | ); 38 | 39 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 40 | [&]{ m = active{}; }, 41 | [&]{ return m == matches; }); 42 | } 43 | 44 | 45 | //------------------------------------------------------------------- 46 | int main() 47 | { 48 | using std::string; 49 | 50 | try { 51 | test(__LINE__, {""}, active{}); 52 | 53 | test(__LINE__, {">:a"}, active{1,0}); 54 | test(__LINE__, {">:b"}, active{0,1}); 55 | test(__LINE__, {">:a",">:b"}, active{1,1}); 56 | test(__LINE__, {">:b",">:a"}, active{1,1}); 57 | test(__LINE__, {">:ab"}, active{1,1}); 58 | test(__LINE__, {">:ba"}, active{1,1}); 59 | //fail cases 60 | test(__LINE__, {">:-ab"}, active{}); 61 | test(__LINE__, {"bca"}, active{}); 62 | test(__LINE__, {"-bca"}, active{}); 63 | test(__LINE__, {">:b-a"}, active{}); 64 | } 65 | catch(std::exception& e) { 66 | std::cerr << e.what() << std::endl; 67 | return 1; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /test/joined_flags_test6.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | active(bool a_, bool b_, bool c_, bool d_): 18 | a{a_}, b{b_}, c{c_}, d{d_} 19 | {} 20 | bool a = false, b = false, c = false, d = false; 21 | 22 | friend bool operator == (const active& x, const active& y) noexcept { 23 | return (x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d); 24 | } 25 | }; 26 | 27 | 28 | //------------------------------------------------------------------- 29 | void test(int lineNo, 30 | const std::initializer_list args, 31 | const active& matches) 32 | { 33 | using namespace clipp; 34 | active m; 35 | 36 | auto cli = ( 37 | joinable(option("a").set(m.a), 38 | option("b").set(m.b)), 39 | joinable(option("-a").set(m.c), 40 | option("-b").set(m.d)) ); 41 | 42 | parse(args, cli); 43 | 44 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 45 | [&]{ m = active{}; }, 46 | [&]{ return m == matches; }); 47 | } 48 | 49 | 50 | //------------------------------------------------------------------- 51 | int main() 52 | { 53 | using std::string; 54 | 55 | try { 56 | test(__LINE__, {""}, active{}); 57 | 58 | test(__LINE__, {"a"}, active{1,0,0,0}); 59 | test(__LINE__, {"b"}, active{0,1,0,0}); 60 | test(__LINE__, {"a","b"}, active{1,1,0,0}); 61 | test(__LINE__, {"b","a"}, active{1,1,0,0}); 62 | test(__LINE__, {"ab"}, active{1,1,0,0}); 63 | test(__LINE__, {"ba"}, active{1,1,0,0}); 64 | //second group 65 | test(__LINE__, {"-a"}, active{0,0,1,0}); 66 | test(__LINE__, {"-b"}, active{0,0,0,1}); 67 | test(__LINE__, {"-a","-b"}, active{0,0,1,1}); 68 | test(__LINE__, {"-b","-a"}, active{0,0,1,1}); 69 | test(__LINE__, {"-ab"}, active{0,0,1,1}); 70 | test(__LINE__, {"-ba"}, active{0,0,1,1}); 71 | test(__LINE__, {"-b-a"}, active{0,0,1,1}); 72 | test(__LINE__, {"-a-b"}, active{0,0,1,1}); 73 | //fail cases 74 | test(__LINE__, {"--ab"}, active{}); 75 | test(__LINE__, {"ab-"}, active{}); 76 | test(__LINE__, {"ba-"}, active{}); 77 | test(__LINE__, {"a-b"}, active{}); 78 | test(__LINE__, {"b-a"}, active{}); 79 | } 80 | catch(std::exception& e) { 81 | std::cerr << e.what() << std::endl; 82 | return 1; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /test/joined_params_test1.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | #include 13 | 14 | 15 | //------------------------------------------------------------------- 16 | struct active { 17 | active() = default; 18 | 19 | explicit 20 | active(std::initializer_list il): xs{il} {} 21 | 22 | std::vector xs; 23 | 24 | friend bool operator == (const active& a, const active& b) noexcept { 25 | return std::equal(begin(a.xs), end(a.xs), begin(b.xs), 26 | [](double x, double y) { 27 | return std::abs(x - y) < 1e-5; 28 | }); 29 | } 30 | }; 31 | 32 | 33 | //------------------------------------------------------------------- 34 | void test(int lineNo, 35 | const std::initializer_list args, 36 | const active& matches) 37 | { 38 | using namespace clipp; 39 | 40 | active m; 41 | auto cli = joinable( repeatable( 42 | option(",") , opt_number("number", m.xs) 43 | ) ); 44 | 45 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 46 | [&]{ m = active{}; }, 47 | [&]{ return m == matches; }); 48 | } 49 | 50 | 51 | //------------------------------------------------------------------- 52 | int main() 53 | { 54 | try { 55 | test(__LINE__, {""}, active{}); 56 | 57 | test(__LINE__, {"1" }, active{1}); 58 | test(__LINE__, {"1", "2" }, active{1,2}); 59 | test(__LINE__, {"1", "2", "3"}, active{1,2,3}); 60 | test(__LINE__, {"1.1" }, active{1.1}); 61 | test(__LINE__, {"1.1", "2.2" }, active{1.1,2.2}); 62 | test(__LINE__, {"1.1", "2.2", "3.3"}, active{1.1,2.2,3.3}); 63 | 64 | test(__LINE__, {"1" }, active{1}); 65 | test(__LINE__, {"1", ",", "2" }, active{1,2}); 66 | test(__LINE__, {"1", ",", "2", ",", "3"}, active{1,2,3}); 67 | test(__LINE__, {"1.1" }, active{1.1}); 68 | test(__LINE__, {"1.1", ",", "2.2" }, active{1.1,2.2}); 69 | test(__LINE__, {"1.1", ",", "2.2", ",", "3.3"}, active{1.1,2.2,3.3}); 70 | 71 | test(__LINE__, {"1," }, active{1}); 72 | test(__LINE__, {"1,", "2" }, active{1,2}); 73 | test(__LINE__, {"1,", "2", "3"}, active{1,2,3}); 74 | test(__LINE__, {"1.1," }, active{1.1}); 75 | test(__LINE__, {"1.1,", "2.2" }, active{1.1,2.2}); 76 | test(__LINE__, {"1.1,", "2.2", "3.3"}, active{1.1,2.2,3.3}); 77 | 78 | test(__LINE__, {"1," }, active{1}); 79 | test(__LINE__, {"1,", "2," }, active{1,2}); 80 | test(__LINE__, {"1,", "2,", "3"}, active{1,2,3}); 81 | test(__LINE__, {"1.1," }, active{1.1}); 82 | test(__LINE__, {"1.1,", "2.2," }, active{1.1,2.2}); 83 | test(__LINE__, {"1.1,", "2.2,", "3.3"}, active{1.1,2.2,3.3}); 84 | 85 | test(__LINE__, {"1," }, active{1}); 86 | test(__LINE__, {"1,", "2," }, active{1,2}); 87 | test(__LINE__, {"1,", "2,", "3,"}, active{1,2,3}); 88 | test(__LINE__, {"1.1," }, active{1.1}); 89 | test(__LINE__, {"1.1,", "2.2," }, active{1.1,2.2}); 90 | test(__LINE__, {"1.1,", "2.2,", "3.3,"}, active{1.1,2.2,3.3}); 91 | 92 | test(__LINE__, {"1" }, active{1}); 93 | test(__LINE__, {"1", ",2" }, active{1,2}); 94 | test(__LINE__, {"1", ",2", "3"}, active{1,2,3}); 95 | test(__LINE__, {"1.1" }, active{1.1}); 96 | test(__LINE__, {"1.1", ",2.2" }, active{1.1,2.2}); 97 | test(__LINE__, {"1.1", ",2.2", "3.3"}, active{1.1,2.2,3.3}); 98 | 99 | test(__LINE__, {"1" }, active{1}); 100 | test(__LINE__, {"1", ",2" }, active{1,2}); 101 | test(__LINE__, {"1", ",2", ",3"}, active{1,2,3}); 102 | test(__LINE__, {"1.1" }, active{1.1}); 103 | test(__LINE__, {"1.1", ",2.2" }, active{1.1,2.2}); 104 | test(__LINE__, {"1.1", ",2.2", ",3.3"}, active{1.1,2.2,3.3}); 105 | 106 | test(__LINE__, {"1" }, active{1}); 107 | test(__LINE__, {"1,2", "3"}, active{1,2,3}); 108 | test(__LINE__, {"1.1,2.2" }, active{1.1,2.2}); 109 | test(__LINE__, {"1.1", "2.2", "3.3"}, active{1.1,2.2,3.3}); 110 | 111 | test(__LINE__, {"1", "2,3"}, active{1,2,3}); 112 | 113 | test(__LINE__, {"1.1" }, active{1.1}); 114 | test(__LINE__, {"1.1", "2.2" }, active{1.1,2.2}); 115 | test(__LINE__, {"1.1", "2.2,3.3"}, active{1.1,2.2,3.3}); 116 | 117 | test(__LINE__, {"1" }, active{1}); 118 | test(__LINE__, {"1,2" }, active{1,2}); 119 | test(__LINE__, {"1,2,3"}, active{1,2,3}); 120 | test(__LINE__, {"1.1" }, active{1.1}); 121 | test(__LINE__, {"1.1,2.2" }, active{1.1,2.2}); 122 | test(__LINE__, {"1.1,2.2,3.3"}, active{1.1,2.2,3.3}); 123 | 124 | test(__LINE__, {"1", "2,3", "4", ",", "5", "6,7,8"}, active{1,2,3,4,5,6,7,8}); 125 | test(__LINE__, {"1", "2.2,3", "4.4", ",", "5.5", "6,7,8"}, active{1,2.2,3,4.4,5.5,6,7,8}); 126 | 127 | test(__LINE__, {","}, active{}); 128 | test(__LINE__, {"1", ","}, active{1}); 129 | test(__LINE__, {"1", ",", "2", ","}, active{1,2}); 130 | 131 | } 132 | catch(std::exception& e) { 133 | std::cerr << e.what() << std::endl; 134 | return 1; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /test/joined_params_test2.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct counters { 16 | counters() = default; 17 | 18 | explicit 19 | counters(int a_, int b_): a{a_}, b{b_} {} 20 | 21 | int a = 0, b = 0; 22 | 23 | friend bool operator == (const counters& x, const counters& y) noexcept { 24 | return (x.a == y.a && x.b == y.b); 25 | } 26 | }; 27 | 28 | 29 | //------------------------------------------------------------------- 30 | void test(int lineNo, 31 | const std::initializer_list args, 32 | const counters& matches) 33 | { 34 | using namespace clipp; 35 | 36 | counters m; 37 | auto cli1 = joinable( 38 | repeatable( 39 | option("a").call([&]{++m.a;}), 40 | option("b").call([&]{++m.b;}) 41 | ) 42 | ); 43 | 44 | run_wrapped_variants({ __FILE__, lineNo }, args, cli1, 45 | [&]{ m = counters{}; }, 46 | [&]{ return m == matches; }); 47 | 48 | 49 | auto cli2 = joinable( 50 | repeatable( option("a").call([&]{++m.a;}) ), 51 | repeatable( option("b").call([&]{++m.b;}) ) 52 | ); 53 | 54 | run_wrapped_variants({ __FILE__, lineNo }, args, cli2, 55 | [&]{ m = counters{}; }, 56 | [&]{ return m == matches; }); 57 | } 58 | 59 | 60 | 61 | //------------------------------------------------------------------- 62 | int main() 63 | { 64 | try { 65 | test(__LINE__, {}, counters{}); 66 | 67 | test(__LINE__, {"a"}, counters{1,0}); 68 | test(__LINE__, {"b"}, counters{0,1}); 69 | 70 | test(__LINE__, {"a","a"}, counters{2,0}); 71 | test(__LINE__, {"b","b"}, counters{0,2}); 72 | test(__LINE__, {"a","b"}, counters{1,1}); 73 | 74 | test(__LINE__, {"a","a","a"}, counters{3,0}); 75 | test(__LINE__, {"b","b","b"}, counters{0,3}); 76 | test(__LINE__, {"a","b","a"}, counters{2,1}); 77 | test(__LINE__, {"b","a","b"}, counters{1,2}); 78 | 79 | test(__LINE__, {"b","a","a","b"}, counters{2,2}); 80 | test(__LINE__, {"a","b","b","a"}, counters{2,2}); 81 | 82 | 83 | test(__LINE__, {"aa"}, counters{2,0}); 84 | test(__LINE__, {"bb"}, counters{0,2}); 85 | 86 | test(__LINE__, {"aaa"}, counters{3,0}); 87 | test(__LINE__, {"bbb"}, counters{0,3}); 88 | 89 | test(__LINE__, {"abbb"}, counters{1,3}); 90 | test(__LINE__, {"abba"}, counters{2,2}); 91 | test(__LINE__, {"baba"}, counters{2,2}); 92 | test(__LINE__, {"abab"}, counters{2,2}); 93 | 94 | test(__LINE__, {"abaabbabbbbaaabaabababab"}, counters{12,12}); 95 | 96 | test(__LINE__, {"a", "bba", "b", "aba", "bb", "aaaa"}, counters{8,6}); 97 | } 98 | catch(std::exception& e) { 99 | std::cerr << e.what() << std::endl; 100 | return 1; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /test/joined_sequence_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | 18 | explicit 19 | active(int i_, char a_, char b_, char c_) : i{i_}, a{a_}, b{b_}, c{c_} {} 20 | 21 | active(int i_, const std::string& s_) : i{i_}, s{s_} {} 22 | 23 | int i = 0; 24 | char a = ' ', b = ' ', c = ' '; 25 | std::string s = ""; 26 | 27 | friend bool operator == (const active& x, const active& y) noexcept { 28 | return (x.i == y.i && 29 | x.a == y.a && x.b == y.b && x.c == y.c && 30 | x.s == y.s); 31 | } 32 | }; 33 | 34 | 35 | //------------------------------------------------------------------- 36 | void test(int lineNo, 37 | const std::initializer_list args, 38 | const active& matches) 39 | { 40 | using namespace clipp; 41 | 42 | auto one_char = [](const std::string& arg) { 43 | if(arg.empty() || !std::isalpha(arg[0])) return subrange{}; 44 | return subrange{0,1}; 45 | }; 46 | 47 | active m; 48 | auto cli = group( 49 | option("-i").set(m.i,1) & value(one_char, "A", m.a), 50 | option("-j").set(m.i,2) & value(one_char, "A", m.a) & value(one_char, "B", m.b), 51 | option("-k").set(m.i,3) & value(one_char, "A", m.a) & value(one_char, "B", m.b) & value(one_char, "C", m.c) 52 | , 53 | option("-m").set(m.i,4) & values(one_char, "char", [&](const std::string& a){m.s += a;}) 54 | , 55 | option("-o").set(m.i,9) & value("str", m.s) 56 | ); 57 | 58 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 59 | [&]{ m = active{}; }, 60 | [&]{ return m == matches; }); 61 | } 62 | 63 | 64 | //------------------------------------------------------------------- 65 | int main() 66 | { 67 | try { 68 | 69 | test(__LINE__, {""}, active{}); 70 | 71 | test(__LINE__, {"-i" }, active{1, ' ', ' ', ' '}); 72 | test(__LINE__, {"-i", "x" }, active{1, 'x', ' ', ' '}); 73 | test(__LINE__, {"-i", "x", "y" }, active{1, 'x', ' ', ' '}); 74 | test(__LINE__, {"-i", "x", "y", "z"}, active{1, 'x', ' ', ' '}); 75 | 76 | test(__LINE__, {"-j" }, active{2, ' ', ' ', ' '}); 77 | test(__LINE__, {"-j", "x" }, active{2, 'x', ' ', ' '}); 78 | test(__LINE__, {"-j", "x", "y" }, active{2, 'x', 'y', ' '}); 79 | test(__LINE__, {"-j", "x", "y", "z"}, active{2, 'x', 'y', ' '}); 80 | 81 | test(__LINE__, {"-k" }, active{3, ' ', ' ', ' '}); 82 | test(__LINE__, {"-k", "x" }, active{3, 'x', ' ', ' '}); 83 | test(__LINE__, {"-k", "x", "y" }, active{3, 'x', 'y', ' '}); 84 | test(__LINE__, {"-k", "x", "y", "z"}, active{3, 'x', 'y', 'z'}); 85 | 86 | test(__LINE__, {"-m" }, active{4, ""}); 87 | test(__LINE__, {"-m", "x" }, active{4, "x"}); 88 | test(__LINE__, {"-m", "x", "y" }, active{4, "xy"}); 89 | test(__LINE__, {"-m", "x", "y", "z"}, active{4, "xyz"}); 90 | 91 | test(__LINE__, {"-o" }, active{9, ""}); 92 | test(__LINE__, {"-o", "x" }, active{9, "x"}); 93 | test(__LINE__, {"-o", "x", "y" }, active{9, "x"}); 94 | test(__LINE__, {"-o", "x", "y", "z"}, active{9, "x"}); 95 | 96 | 97 | //joined sequence 98 | test(__LINE__, {"-i" }, active{1, ' ', ' ', ' '}); 99 | test(__LINE__, {"-ix" }, active{1, 'x', ' ', ' '}); 100 | test(__LINE__, {"-ixy" }, active{0, ' ', ' ', ' '}); 101 | test(__LINE__, {"-ixyz"}, active{0, ' ', ' ', ' '}); 102 | 103 | test(__LINE__, {"-j" }, active{2, ' ', ' ', ' '}); 104 | test(__LINE__, {"-jx" }, active{2, 'x', ' ', ' '}); 105 | test(__LINE__, {"-jxy" }, active{2, 'x', 'y', ' '}); 106 | test(__LINE__, {"-jxyz"}, active{0, ' ', ' ', ' '}); 107 | 108 | test(__LINE__, {"-k" }, active{3, ' ', ' ', ' '}); 109 | test(__LINE__, {"-kx" }, active{3, 'x', ' ', ' '}); 110 | test(__LINE__, {"-kxy" }, active{3, 'x', 'y', ' '}); 111 | test(__LINE__, {"-kxyz" }, active{3, 'x', 'y', 'z'}); 112 | test(__LINE__, {"-kxyza"}, active{0, ' ', ' ', ' '}); 113 | 114 | test(__LINE__, {"-m" }, active{4, ""}); 115 | test(__LINE__, {"-mx" }, active{4, "x"}); 116 | test(__LINE__, {"-mxy" }, active{4, "xy"}); 117 | test(__LINE__, {"-mxyz" }, active{4, "xyz"}); 118 | test(__LINE__, {"-mxyza"}, active{4, "xyza"}); 119 | 120 | test(__LINE__, {"-o" }, active{9, ""}); 121 | test(__LINE__, {"-ox" }, active{9, "x"}); 122 | test(__LINE__, {"-oxy" }, active{9, "xy"}); 123 | test(__LINE__, {"-oxyz" }, active{9, "xyz"}); 124 | test(__LINE__, {"-oxyza"}, active{9, "xyza"}); 125 | 126 | 127 | } 128 | catch(std::exception& e) { 129 | std::cerr << e.what() << std::endl; 130 | return 1; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /test/mixed_params_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | #include 13 | 14 | 15 | //------------------------------------------------------------------- 16 | struct active { 17 | int av = 0; 18 | int bv = 1; 19 | float cv = 0.0f, dv = 1.0f; 20 | double ev = 0.0, fv = 1.0; 21 | std::string gv; 22 | bool a = false, b = false, c = false, d = false, e = false, f = false, 23 | g = false, h = false, i = false; 24 | 25 | friend bool operator == (const active& x, const active& y) noexcept { 26 | if(x.a != y.a || x.b != y.b || x.c != y.c || 27 | x.d != y.d || x.e != y.e || x.f != y.f || 28 | x.g != y.g || x.h != y.h || x.i != y.i || 29 | x.av != y.av || x.bv != y.bv || x.gv != y.gv) return false; 30 | 31 | using std::abs; 32 | if(abs(x.cv - y.cv) > 1e-4f || abs(x.dv - y.dv) > 1e-4f || 33 | abs(x.ev - y.ev) > 1e-4 || abs(x.fv - y.fv) > 1e-4) return false; 34 | 35 | return true; 36 | } 37 | }; 38 | 39 | 40 | //------------------------------------------------------------------- 41 | void test(int lineNo, 42 | const std::initializer_list args, 43 | const active& matches) 44 | { 45 | using namespace clipp; 46 | 47 | active m; 48 | 49 | auto cli = ( 50 | required("-a").set(m.a) & value("A",m.av), 51 | required("-b", "--bb").set(m.b) & value("B",m.bv), 52 | option("-c", "--cc").set(m.c) & value("C",m.cv) & opt_value("D",m.dv), 53 | option("-d", "--dd").set(m.d) & opt_value("D",m.dv), 54 | required("-e", "--ee").set(m.e) & value("E",m.ev), 55 | option("-f", "--ff").set(m.f) & opt_value("F",m.fv), 56 | value("G", m.gv).set(m.g), 57 | option("-h", "--hh", "---hhh").set(m.h), 58 | required("-i", "--ii").set(m.i) 59 | ); 60 | 61 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 62 | [&]{ m = active{}; }, 63 | [&]{ return m == matches; }); 64 | } 65 | 66 | 67 | //------------------------------------------------------------------- 68 | int main() 69 | { 70 | 71 | try { 72 | active m; 73 | test(__LINE__, {""}, m); 74 | 75 | m = active{}; m.a = true; 76 | test(__LINE__, {"-a"}, m); 77 | m = active{}; m.a = true; m.av = 65; 78 | test(__LINE__, {"-a", "65"}, m); 79 | test(__LINE__, {"-a65"}, m); 80 | 81 | m = active{}; m.b = true; 82 | test(__LINE__, {"-b"}, m); 83 | m = active{}; m.b = true; m.bv = 12; 84 | test(__LINE__, {"-b", "12"}, m); 85 | test(__LINE__, {"-b12"}, m); 86 | 87 | m = active{}; m.c = true; 88 | test(__LINE__, {"-c"}, m); 89 | m = active{}; m.c = true; m.cv = 2.3f; 90 | test(__LINE__, {"-c", "2.3"}, m); 91 | test(__LINE__, {"-c2.3"}, m); 92 | test(__LINE__, {"-c2", ".3"}, m); 93 | test(__LINE__, {"-c", "+2.3"}, m); 94 | test(__LINE__, {"-c+2.3"}, m); 95 | test(__LINE__, {"-c+2", ".3"}, m); 96 | m = active{}; m.c = true; m.cv = -2.3f; 97 | test(__LINE__, {"-c", "-2.3"}, m); 98 | test(__LINE__, {"-c-2.3"}, m); 99 | test(__LINE__, {"-c-2", ".3"}, m); 100 | 101 | m = active{}; m.c = true; m.cv = 1; m.dv = 2; 102 | test(__LINE__, {"-c", "1", "2"}, m); 103 | test(__LINE__, {"-c1", "2"}, m); 104 | test(__LINE__, {"-c1", "2"}, m); 105 | 106 | m = active{}; m.d = true; m.c = true; m.cv = 2; 107 | test(__LINE__, {"-c", "2", "-d"}, m); 108 | m = active{}; m.a = true; m.av = 1; m.c = true; m.cv = 2; 109 | test(__LINE__, {"-c", "2", "-a", "1"}, m); 110 | 111 | m = active{}; m.d = true; 112 | test(__LINE__, {"-d"}, m); 113 | m = active{}; m.d = true; m.dv = 2.3f; 114 | test(__LINE__, {"-d", "2.3"}, m); 115 | test(__LINE__, {"-d2.3"}, m); 116 | test(__LINE__, {"-d2", ".3"}, m); 117 | 118 | m = active{}; m.e = true; 119 | test(__LINE__, {"-e"}, m); 120 | m = active{}; m.e = true; m.ev = 2.3; 121 | test(__LINE__, {"-e", "2.3"}, m); 122 | test(__LINE__, {"-e2.3"}, m); 123 | test(__LINE__, {"-e2", ".3"}, m); 124 | 125 | m = active{}; m.f = true; 126 | test(__LINE__, {"-f"}, m); 127 | test(__LINE__, {"--ff"}, m); 128 | m = active{}; m.f = true; m.fv = 2.3; 129 | test(__LINE__, {"-f", "2.3"}, m); 130 | test(__LINE__, {"--ff", "2.3"}, m); 131 | test(__LINE__, {"-f2.3"}, m); 132 | test(__LINE__, {"--ff2.3"}, m); 133 | test(__LINE__, {"-f2", ".3"}, m); 134 | test(__LINE__, {"--ff2", ".3"}, m); 135 | 136 | m = active{}; m.g = true; m.gv = "xyz"; 137 | test(__LINE__, {"xyz"}, m); 138 | 139 | m = active{}; m.g = true; m.gv = "-h"; 140 | test(__LINE__, {"-h"}, m); 141 | m = active{}; m.g = true; m.gv = "--hh"; 142 | test(__LINE__, {"--hh"}, m); 143 | m = active{}; m.g = true; m.gv = "---hhh"; 144 | test(__LINE__, {"---hhh"}, m); 145 | 146 | m = active{}; m.g = true; m.gv = "--h"; 147 | test(__LINE__, {"--h"}, m); 148 | m = active{}; m.g = true; m.gv = "--hh"; 149 | test(__LINE__, {"--hh"}, m); 150 | m = active{}; m.g = true; m.gv = "-hh"; 151 | test(__LINE__, {"-hh"}, m); 152 | m = active{}; m.g = true; m.gv = "-hhh"; 153 | test(__LINE__, {"-hhh"}, m); 154 | 155 | m = active{}; m.h = true; m.g = true; m.gv = "x-y.z"; 156 | test(__LINE__, {"x-y.z", "-h"}, m); 157 | test(__LINE__, {"x-y.z", "--hh"}, m); 158 | test(__LINE__, {"x-y.z", "---hhh"}, m); 159 | 160 | m = active{}; m.i = true; m.g = true; m.gv = "xYz"; 161 | test(__LINE__, {"xYz", "-i"}, m); 162 | test(__LINE__, {"xYz", "--ii"}, m); 163 | 164 | m = active{}; m.g = true; m.gv = "-ii"; 165 | test(__LINE__, {"-ii"}, m); 166 | m = active{}; m.g = true; m.gv = "--i"; 167 | test(__LINE__, {"--i"}, m); 168 | 169 | m = active{}; 170 | m.a = true; m.av = 65; 171 | m.b = true; m.bv = 12; 172 | m.c = true; m.cv = -0.12f; 173 | m.d = true; m.dv = 2.3f; 174 | m.e = true; m.ev = 3.4; 175 | m.f = true; m.fv = 5.6; 176 | m.g = true; m.gv = "x-y.z"; 177 | m.h = true; 178 | m.i = true; 179 | 180 | test(__LINE__, {"-a", "65", "-b12", "-c", "-0.12f", "-d2.3", 181 | "-e3", ".4", "--ff", "5.6", "x-y.z", "-h", "--ii"}, m); 182 | 183 | test(__LINE__, {"-b12", "-c", "-0.12f", "-d2.3", "-e3", ".4", "-a", "65", 184 | "--ff", "5.6", "x-y.z", "-h", "--ii"}, m); 185 | 186 | test(__LINE__, {"-d2.3", "-e3", ".4", "-b12", "-c", "-0.12f", "-a", "65", 187 | "--ff", "5.6", "x-y.z", "-h", "--ii"}, m); 188 | 189 | } 190 | catch(std::exception& e) { 191 | std::cerr << e.what() << std::endl; 192 | return 1; 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /test/options_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, bool c_, bool d_, bool e_, bool f_): 19 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_} 20 | {} 21 | bool a = false, b = false, c = false, d = false, e = false, f = false; 22 | 23 | friend bool operator == (const active& x, const active& y) noexcept { 24 | return (x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d && 25 | x.e == y.e && x.f == y.f); 26 | } 27 | }; 28 | 29 | 30 | //------------------------------------------------------------------- 31 | void test(int lineNo, 32 | const std::initializer_list args, 33 | const active& matches) 34 | { 35 | using namespace clipp; 36 | 37 | active m; 38 | auto cli = ( 39 | option("-a", "--aaa").set(m.a), 40 | option("-b", "--bee").set(m.b), 41 | option("-c", "--cee").set(m.c), 42 | option("-d", "--dee").set(m.d), 43 | option("-e", "--eee").set(m.e), 44 | option("-f", "--eff").set(m.f) ); 45 | 46 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 47 | [&]{ m = active{}; }, 48 | [&]{ return m == matches; }); 49 | } 50 | 51 | 52 | //------------------------------------------------------------------- 53 | int main() 54 | { 55 | try { 56 | test(__LINE__, {""}, active{}); 57 | //single option presence - primary flags 58 | test(__LINE__, {"-a"}, active{1,0,0,0,0,0}); 59 | test(__LINE__, {"-b"}, active{0,1,0,0,0,0}); 60 | test(__LINE__, {"-c"}, active{0,0,1,0,0,0}); 61 | test(__LINE__, {"-d"}, active{0,0,0,1,0,0}); 62 | test(__LINE__, {"-e"}, active{0,0,0,0,1,0}); 63 | test(__LINE__, {"-f"}, active{0,0,0,0,0,1}); 64 | 65 | //single option presence - secondary flags 66 | test(__LINE__, {"--aaa"}, active{1,0,0,0,0,0}); 67 | test(__LINE__, {"--bee"}, active{0,1,0,0,0,0}); 68 | test(__LINE__, {"--cee"}, active{0,0,1,0,0,0}); 69 | test(__LINE__, {"--dee"}, active{0,0,0,1,0,0}); 70 | test(__LINE__, {"--eee"}, active{0,0,0,0,1,0}); 71 | test(__LINE__, {"--eff"}, active{0,0,0,0,0,1}); 72 | 73 | //all (varying sequence) 74 | test(__LINE__, {"-a", "-b", "-c", "-d", "-e", "-f"}, active{1,1,1,1,1,1}); 75 | test(__LINE__, {"-c", "-d", "-a", "-f", "-e", "-b"}, active{1,1,1,1,1,1}); 76 | 77 | test(__LINE__, {"--aaa", "--bee", "--cee", "--dee", "--eee", "--eff"}, 78 | active{1,1,1,1,1,1}); 79 | 80 | test(__LINE__, {"--eee", "--bee", "--eff", "--dee", "--aaa", "--cee"}, 81 | active{1,1,1,1,1,1}); 82 | 83 | //several options 84 | test(__LINE__, {"-b", "--aaa", "-f", "--dee"}, active{1,1,0,1,0,1}); 85 | test(__LINE__, {"-f", "-a", "-b", "--dee"}, active{1,1,0,1,0,1}); 86 | 87 | //option repeat is ignored 88 | test(__LINE__, {"-b", "-a", "--bee", "--aaa"}, active{1,1,0,0,0,0}); 89 | 90 | } 91 | catch(std::exception& e) { 92 | std::cerr << e.what() << std::endl; 93 | return 1; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /test/prefix_free_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | void test(int lineNo, bool expected, const clipp::group& cli) 16 | { 17 | if(cli.flags_are_prefix_free() != expected) { 18 | 19 | std::cout << "prefix '" << cli.common_flag_prefix() << "'" << std::endl; 20 | 21 | throw std::runtime_error{"failed test " + std::string(__FILE__) + 22 | " in line " + std::to_string(lineNo)}; 23 | } 24 | } 25 | 26 | 27 | //------------------------------------------------------------------- 28 | clipp::group 29 | make_cli_1() 30 | { 31 | using namespace clipp; 32 | 33 | auto copyMode = "copy mode:" % ( 34 | command("copy") | command("move"), 35 | option("--all") % "copy all", 36 | option("--replace") % "replace existing files", 37 | option("-f", "--force") % "don't ask for confirmation" 38 | ); 39 | 40 | auto compareMode = "compare mode:" % ( 41 | command("compare"), 42 | (command("date") | command("content")), 43 | option("-b", "--binary") % "compare files byte by byte", 44 | option("-q", "--quick") % "use heuristics for faster comparison" 45 | ); 46 | 47 | auto mergeAlgo = ( 48 | command("diff") % "merge using diff" | 49 | command("patch") % "merge using patch" | 50 | ( command("inside") % "merge based on content", 51 | "content based merge options:" % ( 52 | option("--git-style") % "emulate git's merge behavior", 53 | option("-m", "--marker") & value("marker") % "merge marker symbol" 54 | ) 55 | ) 56 | ); 57 | 58 | auto mergeMode = "merge mode:" % ( 59 | command("merge"), 60 | mergeAlgo, 61 | required("-o") & value("outdir") % "target directory for merge result", 62 | option("--show-conflicts") % "show merge conflicts during run" 63 | ); 64 | 65 | auto firstOpt = "user interface options:" % ( 66 | option("-v", "--verbose") % "show detailed output", 67 | option("-i", "--interactive") % "use interactive mode" 68 | ); 69 | auto lastOpt = "mode-independent options:" % ( 70 | values("files") % "input files", 71 | option("-r", "--recursive") % "descend into subdirectories", 72 | option("-h", "--help") % "show help" 73 | ); 74 | 75 | return ( 76 | firstOpt, 77 | copyMode | compareMode | mergeMode | command("list"), 78 | lastOpt); 79 | } 80 | 81 | //------------------------------------------------------------------- 82 | int main() 83 | { 84 | using namespace clipp; 85 | 86 | try { 87 | test( __LINE__ , true, group{} ); 88 | 89 | test( __LINE__ , true, ( option("-a"), option("-b") )); 90 | 91 | test( __LINE__ , true, ( option(""), option("-b") )); 92 | test( __LINE__ , true, ( option("-a"), option("") )); 93 | 94 | test( __LINE__ , true, ( option("-a"), option("-b"), option("--a") )); 95 | test( __LINE__ , true, ( option(""), option("-b"), option("--a") )); 96 | test( __LINE__ , true, ( option("-a"), option(""), option("--a") )); 97 | test( __LINE__ , true, ( option("-a"), option("-b"), option("") )); 98 | 99 | test( __LINE__ , true, ( 100 | option("-a"), option("--a"), option("-b"), option("--b") 101 | )); 102 | 103 | test( __LINE__ , true, ( 104 | option("-a"), option("--a-a"), option("-b"), option("--b-b") 105 | )); 106 | 107 | test( __LINE__ , true, ( 108 | (option("-a"), option("--a-a")) % "a", 109 | (option("-b"), option("--b-b")) % "b" 110 | )); 111 | 112 | test( __LINE__ , true, ( value("-a"), option("-a"), option("-b") )); 113 | test( __LINE__ , true, ( option("-a"), value("-a"), option("-b") )); 114 | test( __LINE__ , true, ( option("-a"), option("-b"), value("-b") )); 115 | 116 | test( __LINE__ , true, ( option("-a"), option("-b"), value("") )); 117 | 118 | test( __LINE__ , true, ( 119 | option("-a"), option("--a"), option("-b"), value("-b"), option("--b") 120 | )); 121 | 122 | test( __LINE__ , true, ( 123 | option("-a"), option("--a-a"), option("-b"), option("--b-b") 124 | )); 125 | 126 | test( __LINE__ , true, ( 127 | (option("-a"), option("--a-a")) % "a", 128 | (option("-b"), option("--b-b")) % "b" 129 | )); 130 | 131 | //same flags are not an error - TODO is this OK? 132 | test( __LINE__ , true, ( 133 | (option("-a"), option("-a")) % "a", 134 | (option("-b"), option("-b")) % "b" 135 | )); 136 | 137 | test( __LINE__ , true, ( 138 | (option("-a") & value("-a"), option("--a-a")) % "a", 139 | (option("-b"), option("--b-b") & values("-a")) % "b" 140 | )); 141 | 142 | 143 | test( __LINE__ , false, ( option("-a"), option("-ab") )); 144 | 145 | test( __LINE__ , false, ( option("-ab"), option("-a") )); 146 | 147 | test( __LINE__ , false, ( 148 | option("-a"), option("-aa"), option("-b"), option("--b-b") 149 | )); 150 | 151 | test( __LINE__ , false, ( 152 | (option("-a"), option("--a")) % "a", 153 | (option("-b"), option("-abba")) % "b" 154 | )); 155 | 156 | test( __LINE__ , false, ( 157 | (option("-a") & value("a"), option("--a")) % "a", 158 | (option("-b"), option("-abba") & values("-b")) % "b" 159 | )); 160 | 161 | test( __LINE__, true, make_cli_1() ); 162 | 163 | } 164 | catch(std::exception& e) { 165 | std::cerr << e.what() << std::endl; 166 | return 1; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /test/prefix_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2019 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | active(bool a_, int i_): a{a_}, i{i_} {} 18 | bool a = false; 19 | int i = 0; 20 | 21 | friend bool operator == (const active& x, const active& y) noexcept { 22 | return (x.a == y.a && x.i == y.i); 23 | } 24 | }; 25 | 26 | 27 | //------------------------------------------------------------------- 28 | static void 29 | test(int lineNo, 30 | const std::initializer_list args, 31 | const active& matches ) 32 | { 33 | using namespace clipp; 34 | active m; 35 | 36 | auto cli = ( 37 | option("-a").set(m.a), 38 | option("-ab", "-a-b", "-a-b=") & value("i", m.i) 39 | ); 40 | 41 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 42 | [&]{ m = active{}; }, 43 | [&]{ return m == matches; }); 44 | } 45 | 46 | 47 | //------------------------------------------------------------------- 48 | int main() 49 | { 50 | using std::string; 51 | 52 | try { 53 | test(__LINE__, {""}, active{0,0}); 54 | test(__LINE__, {"-a"}, active{1,0}); 55 | 56 | test(__LINE__, {"-ab"}, active{0,0}); 57 | test(__LINE__, {"-a-b"}, active{0,0}); 58 | test(__LINE__, {"-a-b="}, active{0,0}); 59 | 60 | test(__LINE__, {"-ab", "2"}, active{0,2}); 61 | test(__LINE__, {"-a-b", "3"}, active{0,3}); 62 | test(__LINE__, {"-a-b=", "4"}, active{0,4}); 63 | 64 | test(__LINE__, {"-ab2" }, active{0,2}); 65 | test(__LINE__, {"-a-b3" }, active{0,3}); 66 | test(__LINE__, {"-a-b=4"}, active{0,4}); 67 | 68 | test(__LINE__, {"-a", "-ab", "2"}, active{1,2}); 69 | test(__LINE__, {"-a", "-a-b", "3"}, active{1,3}); 70 | test(__LINE__, {"-a", "-a-b=", "4"}, active{1,4}); 71 | 72 | test(__LINE__, {"-a", "-ab2" }, active{1,2}); 73 | test(__LINE__, {"-a", "-a-b3" }, active{1,3}); 74 | test(__LINE__, {"-a", "-a-b=4"}, active{1,4}); 75 | 76 | test(__LINE__, {"-ab", "2", "-a"}, active{1,2}); 77 | test(__LINE__, {"-a-b", "3", "-a"}, active{1,3}); 78 | test(__LINE__, {"-a-b=", "4", "-a"}, active{1,4}); 79 | 80 | test(__LINE__, {"-a", "-ab" }, active{1,0}); 81 | test(__LINE__, {"-a", "-a-b" }, active{1,0}); 82 | test(__LINE__, {"-a", "-a-b="}, active{1,0}); 83 | 84 | test(__LINE__, {"-ab", "-a"}, active{1,0}); 85 | test(__LINE__, {"-a-b", "-a"}, active{1,0}); 86 | test(__LINE__, {"-a-b=", "-a"}, active{1,0}); 87 | } 88 | catch(std::exception& e) { 89 | std::cerr << e.what() << std::endl; 90 | return 1; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /test/repeatability_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | 18 | explicit 19 | active(bool a_, bool b_, bool c_, bool d_, bool e_, bool f_, 20 | std::initializer_list i_) : 21 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_}, i{i_} 22 | {} 23 | 24 | bool a = false, b = false, c = false, d = false, e = false, f = false; 25 | std::vector i; 26 | 27 | friend bool operator == (const active& x, const active& y) noexcept { 28 | return (x.a == y.a && x.b == y.b && x.c == y.c && 29 | x.d == y.d && x.e == y.e && x.f == y.f && 30 | std::equal(begin(x.i), end(x.i), begin(y.i))); 31 | } 32 | }; 33 | 34 | struct repeats { 35 | repeats() = default; 36 | 37 | explicit 38 | repeats(int a_, int b_, int c_, int d_, int e_, int f_, int i_) : 39 | a{a_}, b{b_}, c{c_}, d{d_}, e{e_}, f{f_}, i{i_} 40 | {} 41 | 42 | int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, i = 0; 43 | 44 | friend bool operator == (const repeats& x, const repeats& y) noexcept { 45 | return (x.a == y.a && x.b == y.b && x.c == y.c && 46 | x.d == y.d && x.e == y.e && x.f == y.f && x.i == y.i); 47 | } 48 | }; 49 | 50 | 51 | //------------------------------------------------------------------- 52 | void test(int lineNo, 53 | const std::initializer_list args, 54 | const active& matches, 55 | const repeats& repeated) 56 | { 57 | using namespace clipp; 58 | 59 | active m; 60 | repeats r; 61 | auto cli = group( 62 | //repeatable option 63 | option("a").repeatable(true).set(m.a).if_repeated(increment(r.a)) 64 | , 65 | //repeatable option + exactly one optional value 66 | option("b").repeatable(true).set(m.b).if_repeated(increment(r.b)) & 67 | opt_value("B", m.i).if_repeated(increment(r.i)) 68 | , 69 | //option + values... 70 | option("c").set(m.c).if_repeated(increment(r.c)) & 71 | values("C", m.i).if_repeated(increment(r.i)) 72 | , 73 | //repeatable group of (option + value) 74 | repeatable( 75 | option("d").set(m.d).if_repeated(increment(r.d)) & 76 | value("D", m.i).if_repeated(increment(r.i)) 77 | ) 78 | , 79 | //non-repeatable option 80 | option("e").set(m.e).if_repeated(increment(r.e)) 81 | , 82 | //repeatable group of (option + values...) 83 | //Note that we have to make sure, that args {"f", "3", "f", "4"} 84 | //won't be interpreted as "f" followed by 3 values. 85 | //This is achieved with the prefix_not predicate which excludes "f" 86 | //itself from beeing matched as a value. 87 | repeatable( 88 | option("f").set(m.f).if_repeated(increment(r.f)) & 89 | values(match::prefix_not("f"), "F", m.i).if_repeated(increment(r.i)) 90 | ) 91 | ); 92 | 93 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 94 | [&]{ m = active{}; r = repeats{}; }, 95 | [&]{ return m == matches && r == repeated; }); 96 | } 97 | 98 | 99 | //------------------------------------------------------------------- 100 | int main() 101 | { 102 | try { 103 | test(__LINE__, {""}, active{}, repeats{}); 104 | // a b c d e f i a b c d e f i 105 | test(__LINE__, {"a"}, active{1,0,0,0,0,0,{}}, repeats{0,0,0,0,0,0,0}); 106 | test(__LINE__, {"a", "a"}, active{1,0,0,0,0,0,{}}, repeats{1,0,0,0,0,0,0}); 107 | test(__LINE__, {"a", "a", "a"}, active{1,0,0,0,0,0,{}}, repeats{2,0,0,0,0,0,0}); 108 | test(__LINE__, {"a", "a", "a", "a"}, active{1,0,0,0,0,0,{}}, repeats{3,0,0,0,0,0,0}); 109 | test(__LINE__, {"a", "a", "a", "a", "a" }, active{1,0,0,0,0,0,{}}, repeats{4,0,0,0,0,0,0}); 110 | test(__LINE__, {"a", "a", "e", "a", "a", "a"}, active{1,0,0,0,1,0,{}}, repeats{4,0,0,0,0,0,0}); 111 | 112 | test(__LINE__, {"b"}, active{0,1,0,0,0,0,{}}, repeats{0,0,0,0,0,0,0}); 113 | test(__LINE__, {"b", "b", "2"}, active{0,1,0,0,0,0,{2}}, repeats{0,1,0,0,0,0,0}); 114 | test(__LINE__, {"b", "2", "b"}, active{0,1,0,0,0,0,{2}}, repeats{0,1,0,0,0,0,0}); 115 | test(__LINE__, {"b", "a", "b"}, active{1,1,0,0,0,0,{}}, repeats{0,1,0,0,0,0,0}); 116 | test(__LINE__, {"b", "b", "2", "3"}, active{0,1,0,0,0,0,{2}}, repeats{0,1,0,0,0,0,1}); 117 | test(__LINE__, {"b", "2", "b", "b", "3"}, active{0,1,0,0,0,0,{2}}, repeats{0,2,0,0,0,0,1}); 118 | 119 | test(__LINE__, {"c"}, active{0,0,1,0,0,0,{}}, repeats{0,0,0,0,0,0,0}); 120 | test(__LINE__, {"c", "c"}, active{0,0,1,0,0,0,{}}, repeats{0,0,1,0,0,0,0}); 121 | test(__LINE__, {"c", "2"}, active{0,0,1,0,0,0,{2}}, repeats{0,0,0,0,0,0,0}); 122 | test(__LINE__, {"c", "2", "3"}, active{0,0,1,0,0,0,{2,3}}, repeats{0,0,0,0,0,0,1}); 123 | test(__LINE__, {"c", "c", "2", "3"}, active{0,0,1,0,0,0,{2,3}}, repeats{0,0,1,0,0,0,1}); 124 | test(__LINE__, {"c", "2", "3", "c"}, active{0,0,1,0,0,0,{2,3}}, repeats{0,0,1,0,0,0,1}); 125 | 126 | test(__LINE__, {"d"}, active{0,0,0,1,0,0,{}}, repeats{0,0,0,0,0,0,0}); 127 | test(__LINE__, {"d", "d"}, active{0,0,0,1,0,0,{}}, repeats{0,0,0,1,0,0,0}); 128 | test(__LINE__, {"d", "2"}, active{0,0,0,1,0,0,{2}}, repeats{0,0,0,0,0,0,0}); 129 | test(__LINE__, {"d", "2", "d", "3"}, active{0,0,0,1,0,0,{2,3}}, repeats{0,0,0,1,0,0,1}); 130 | test(__LINE__, {"d", "2", "3"}, active{0,0,0,1,0,0,{2}}, repeats{0,0,0,0,0,0,0}); 131 | 132 | test(__LINE__, {"e"}, active{0,0,0,0,1,0,{}}, repeats{0,0,0,0,0,0,0}); 133 | test(__LINE__, {"e", "a"}, active{1,0,0,0,1,0,{}}, repeats{0,0,0,0,0,0,0}); 134 | test(__LINE__, {"e", "e"}, active{0,0,0,0,1,0,{}}, repeats{0,0,0,0,1,0,0}); 135 | test(__LINE__, {"e", "e", "e"}, active{0,0,0,0,1,0,{}}, repeats{0,0,0,0,2,0,0}); 136 | test(__LINE__, {"e", "a", "e", "e"}, active{1,0,0,0,1,0,{}}, repeats{0,0,0,0,2,0,0}); 137 | test(__LINE__, {"e", "b", "e", "a", "e" }, active{1,1,0,0,1,0,{}}, repeats{0,0,0,0,2,0,0}); 138 | test(__LINE__, {"e", "a", "a", "e", "e", "a"}, active{1,0,0,0,1,0,{}}, repeats{2,0,0,0,2,0,0}); 139 | 140 | test(__LINE__, {"f"}, active{0,0,0,0,0,1,{}}, repeats{0,0,0,0,0,0,0}); 141 | test(__LINE__, {"f", "2"}, active{0,0,0,0,0,1,{2}}, repeats{0,0,0,0,0,0,0}); 142 | test(__LINE__, {"f", "2", "3"}, active{0,0,0,0,0,1,{2,3}}, repeats{0,0,0,0,0,0,1}); 143 | test(__LINE__, {"f", "2", "f", "3"}, active{0,0,0,0,0,1,{2,3}}, repeats{0,0,0,0,0,1,1}); 144 | test(__LINE__, {"f", "2", "3", "4"}, active{0,0,0,0,0,1,{2,3,4}}, repeats{0,0,0,0,0,0,2}); 145 | test(__LINE__, {"f", "2", "f", "3", "4"}, active{0,0,0,0,0,1,{2,3,4}}, repeats{0,0,0,0,0,1,2}); 146 | test(__LINE__, {"f", "2", "3", "f", "4"}, active{0,0,0,0,0,1,{2,3,4}}, repeats{0,0,0,0,0,1,2}); 147 | test(__LINE__, {"f", "2", "f", "3", "f", "4"}, active{0,0,0,0,0,1,{2,3,4}}, repeats{0,0,0,0,0,2,2}); 148 | 149 | test(__LINE__, {"f", "f"}, active{0,0,0,0,0,1,{}}, repeats{0,0,0,0,0,1,0}); 150 | test(__LINE__, {"f", "2", "3", "f"}, active{0,0,0,0,0,1,{2,3}}, repeats{0,0,0,0,0,1,1}); 151 | 152 | } 153 | catch(std::exception& e) { 154 | std::cerr << e.what() << std::endl; 155 | return 1; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /test/repeatable_alternatives_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include "testing.h" 12 | 13 | 14 | //------------------------------------------------------------------- 15 | struct active { 16 | active() = default; 17 | explicit 18 | active(bool a_, bool b_, 19 | std::initializer_list i_, std::initializer_list j_) 20 | : 21 | a{a_}, b{b_}, i{i_}, j{j_} 22 | {} 23 | bool a = false, b = false; 24 | std::vector i, j; 25 | 26 | friend bool operator == (const active& x, const active& y) noexcept { 27 | return x.a == y.a && x.b == y.b && 28 | std::equal(begin(x.i), end(x.i), begin(y.i)) && 29 | std::equal(begin(x.j), end(x.j), begin(y.j)); 30 | } 31 | }; 32 | 33 | 34 | //------------------------------------------------------------------- 35 | void test(int lineNo, 36 | const std::initializer_list args, 37 | const active& matches) 38 | { 39 | using namespace clipp; 40 | 41 | active m; 42 | 43 | auto cli = repeatable( 44 | ( option("a").set(m.a) & value("i",m.i) ) | 45 | ( option("b").set(m.b) & value("j",m.j) ) 46 | ); 47 | 48 | run_wrapped_variants({ __FILE__, lineNo }, args, cli, 49 | [&]{ m = active{}; }, 50 | [&]{ return m == matches; }); 51 | } 52 | 53 | 54 | //------------------------------------------------------------------- 55 | int main() 56 | { 57 | try { 58 | 59 | test(__LINE__, {""}, active{}); 60 | 61 | test(__LINE__, {"a"}, active{1,0, {}, {} }); 62 | test(__LINE__, {"b"}, active{0,1, {}, {} }); 63 | 64 | test(__LINE__, {"a", "12"}, active{1,0, {12}, {} }); 65 | test(__LINE__, {"b", "34"}, active{0,1, {}, {34} }); 66 | 67 | test(__LINE__, {"a", "12", "b", "34"}, active{1,1, {12}, {34} }); 68 | 69 | test(__LINE__, {"a", "12", "a", "34"}, active{1,0, {12,34}, {} }); 70 | 71 | test(__LINE__, {"b", "12", "b", "34"}, active{0,1, {}, {12,34} }); 72 | 73 | test(__LINE__, {"a", "1", "b", "2", "a", "3"}, active{1,1, {1,3}, {2} }); 74 | 75 | test(__LINE__, {"a", "1", "b", "2", "b", "4", "a", "3"}, active{1,1, {1,3}, {2,4} }); 76 | 77 | test(__LINE__, {"a", "b", "2", "b", "a", "3"}, active{1,1, {3}, {2} }); 78 | 79 | } 80 | catch(std::exception& e) { 81 | std::cerr << e.what() << std::endl; 82 | return 1; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /test/testing.h: -------------------------------------------------------------------------------- 1 | #ifndef CLIPP_TESTING_H_ 2 | #define CLIPP_TESTING_H_ 3 | 4 | //don't include anything else before the test subject 5 | #include "../include/clipp.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | /*************************************************************************//** 19 | * 20 | * @brief stores the location of a test definition 21 | * 22 | *****************************************************************************/ 23 | struct test_location 24 | { 25 | test_location(std::string file_, int line_): 26 | file{std::move(file_)}, line{line_} 27 | {} 28 | 29 | std::string file; 30 | int line; 31 | }; 32 | 33 | 34 | 35 | /*************************************************************************//** 36 | * 37 | * @brief returns wrapped/nested variants of the input command line interface 38 | * 39 | *****************************************************************************/ 40 | template 41 | std::vector 42 | wrapped_variants(const CLI& cli) 43 | { 44 | using namespace clipp; 45 | return { 46 | /* 1*/ cli 47 | , 48 | /* 2*/ group{cli} 49 | , 50 | /* 3*/ group{group{cli}} 51 | , 52 | /* 4*/ group{option("?a?"), cli} 53 | , 54 | /* 5*/ group{cli, option("?a?")} 55 | , 56 | /* 6*/ group{option("?b?"), cli, option("?a?")} 57 | , 58 | /* 7*/ group{group{option("?a?")}, cli} 59 | , 60 | /* 8*/ group{cli, group{option("?a?")}} 61 | , 62 | /* 9*/ group{option("?a?"), group{cli}} 63 | , 64 | /*10*/ group{group{cli}, option("?a?")} 65 | , 66 | /*11*/ group{option("?b?"), group{cli}, option("?a?")} 67 | }; 68 | } 69 | 70 | 71 | 72 | /*************************************************************************//** 73 | * 74 | * @brief runs CLI validity tests based on differently wrapped variants of 75 | * the original input CLI 76 | * 77 | *****************************************************************************/ 78 | template 79 | void run_wrapped_variants( 80 | const test_location& info, 81 | const std::initializer_list& args, 82 | const CLI& cli, 83 | std::function initialize, 84 | std::function valid) 85 | { 86 | using std::cout; 87 | using std::to_string; 88 | 89 | int variant = 0; 90 | for(const auto& wrappedCli : wrapped_variants(cli)) { 91 | ++variant; 92 | 93 | initialize(); 94 | 95 | parse(args, wrappedCli); 96 | 97 | // cout << "==============================================\n" 98 | // << " in file " << info.file << " in line " << info.line 99 | // << " with variant " << variant << '\n' 100 | // << "==============================================\n"; 101 | // clipp::debug::print(cout, wrappedCli); 102 | // cout << "args = { "; 103 | // for(const auto& a : args) cout << '"' << a << "\" "; 104 | // cout << "}\n"; 105 | // auto res = clipp::parse(args, wrappedCli); 106 | // cout << "----------------------------------------------\n"; 107 | // clipp::debug::print(cout, res); 108 | 109 | if(!valid()) { 110 | throw std::runtime_error{"failed test " + info.file + 111 | " in line " + to_string(info.line) + 112 | " with variant " + to_string(variant) }; 113 | } 114 | } 115 | } 116 | 117 | 118 | 119 | /*************************************************************************//** 120 | * 121 | * @brief runs CLI validity test 122 | * 123 | *****************************************************************************/ 124 | template 125 | void run_test( 126 | const test_location& info, 127 | const std::initializer_list& args, 128 | const CLI& cli, 129 | std::function valid) 130 | { 131 | using std::cout; 132 | using std::to_string; 133 | 134 | parse(args, cli); 135 | 136 | // cout << "==============================================\n" 137 | // << " in file " << info.file << " in line " << info.line << '\n' 138 | // << "==============================================\n"; 139 | // clipp::debug::print(cout, cli); 140 | // cout << "args = { "; 141 | // for(const auto& a : args) cout << '"' << a << "\" "; 142 | // cout << "}\n"; 143 | // auto res = clipp::parse(args, cli); 144 | // cout << "----------------------------------------------\n"; 145 | // clipp::debug::print(cout, res); 146 | 147 | if(!valid()) { 148 | throw std::runtime_error{"failed test " + info.file + 149 | " in line " + to_string(info.line) }; 150 | } 151 | } 152 | 153 | 154 | #endif 155 | -------------------------------------------------------------------------------- /test/values_conversion_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * CLIPP - command line interfaces for modern C++ 4 | * 5 | * released under MIT license 6 | * 7 | * (c) 2017-2018 André Müller; foss@andremueller-online.de 8 | * 9 | *****************************************************************************/ 10 | 11 | #include 12 | 13 | #include "testing.h" 14 | 15 | //------------------------------------------------------------------- 16 | #if defined(_MSC_VER) 17 | #if _MSC_VER < 1800 18 | namespace std { 19 | template 20 | bool isinf(const T &x) { return !_finite(x); } 21 | } 22 | #endif 23 | #endif 24 | 25 | //------------------------------------------------------------------- 26 | template::value, 27 | bool = std::is_floating_point::value> 28 | struct equals { 29 | static bool result(const T& a, const T&b) { 30 | return a == b; 31 | } 32 | }; 33 | 34 | template 35 | struct equals { 36 | static bool result(const T& a, const T&b) { 37 | #if defined(_MSC_VER) 38 | bool ainf = a == std::numeric_limits::infinity(); 39 | bool binf = b == std::numeric_limits::infinity(); 40 | if(ainf && binf) return true; 41 | if(ainf || binf) return false; 42 | #else 43 | if(std::isinf(a) && std::isinf(b)) return true; 44 | if(std::isinf(a) || std::isinf(b)) return false; 45 | #endif 46 | return a == b; 47 | } 48 | }; 49 | 50 | template 51 | struct equals { 52 | static bool result(const T& a, const T&b) { 53 | if(std::isinf(a) && std::isinf(b)) return true; 54 | if(std::isinf(a) || std::isinf(b)) return false; 55 | return std::abs(a-b) < T(1e-4); 56 | } 57 | }; 58 | 59 | 60 | //------------------------------------------------------------------- 61 | template 62 | void test(int lineNo, T x, const std::string& arg, T expected) 63 | { 64 | using namespace clipp; 65 | 66 | auto cli = group( value("", x) ); 67 | 68 | // std::cout << lineNo << " " << x << " '" << arg << "' " << expected; 69 | 70 | run_test({ __FILE__, lineNo }, {arg.c_str()}, cli, [&]{ 71 | // std::cout << " -> " << x << std::endl; 72 | return equals::result(x,expected); } ); 73 | } 74 | 75 | 76 | //------------------------------------------------------------------- 77 | template 78 | void test_conv(int lineNo) 79 | { 80 | test(lineNo, T(0), "0", T(0) ); 81 | test(lineNo, T(0), "1", T(1) ); 82 | test(lineNo, T(0), "2", T(2) ); 83 | test(lineNo, T(0), "66", T(66) ); 84 | 85 | test(lineNo, T(0), " 0 ", T(0) ); 86 | test(lineNo, T(0), " 1 ", T(1) ); 87 | test(lineNo, T(0), " 2 ", T(2) ); 88 | test(lineNo, T(0), " 66 ", T(66) ); 89 | 90 | constexpr auto maxv = std::numeric_limits::max(); 91 | test(lineNo, T(0), std::to_string(maxv), maxv); 92 | test(lineNo, T(0), " " + std::to_string(maxv) + " ", maxv); 93 | 94 | if(std::is_signed::value) { 95 | constexpr auto minv = std::numeric_limits::lowest(); 96 | test(lineNo, T(0), std::to_string(minv), minv); 97 | test(lineNo, T(0), " " + std::to_string(minv) + " ", minv); 98 | } 99 | else { 100 | test(lineNo, T(0), "-1", T(0) ); 101 | test(lineNo, T(0), " -1 ", T(0) ); 102 | } 103 | } 104 | 105 | 106 | //------------------------------------------------------------------- 107 | template sizeof(T))> 108 | struct test_clamp { 109 | static void in(int lineNo) { 110 | constexpr auto maxv = std::numeric_limits::max(); 111 | test(lineNo, T(0), std::to_string(maxv), maxv); 112 | test(lineNo, T(0), " " + std::to_string(maxv) + " ", maxv); 113 | 114 | test(lineNo, T(0), std::to_string(Wide(maxv)+1), maxv); 115 | test(lineNo, T(0), " " + std::to_string(Wide(maxv)+1) + " ", maxv); 116 | 117 | if(std::is_signed::value) { 118 | constexpr auto minv = std::numeric_limits::lowest(); 119 | test(lineNo, T(0), std::to_string(Wide(minv)-1), minv); 120 | test(lineNo, T(0), " " + std::to_string(Wide(minv)-1) + " ", minv); 121 | } 122 | } 123 | }; 124 | 125 | template 126 | struct test_clamp { 127 | static void in(int) {} 128 | }; 129 | 130 | 131 | //------------------------------------------------------------------- 132 | int main() 133 | { 134 | try { 135 | 136 | test(__LINE__, false, "", false); 137 | test(__LINE__, false, " ", true); 138 | test(__LINE__, false, "0", true); 139 | test(__LINE__, false, "1", true); 140 | test(__LINE__, false, "a", true); 141 | 142 | test_conv( __LINE__ ); 143 | test_conv( __LINE__ ); 144 | test_conv( __LINE__ ); 145 | test_conv( __LINE__ ); 146 | test_conv( __LINE__ ); 147 | 148 | test_conv( __LINE__ ); 149 | test_conv( __LINE__ ); 150 | test_conv( __LINE__ ); 151 | test_conv( __LINE__ ); 152 | 153 | test_conv( __LINE__ ); 154 | test_conv( __LINE__ ); 155 | test_conv( __LINE__ ); 156 | 157 | test(__LINE__, 0, "", 0); 158 | test(__LINE__, 0, " ", ' '); 159 | test(__LINE__, 0, "0", '0'); 160 | test(__LINE__, 0, "1", '1'); 161 | test(__LINE__, 0, "a", 'a'); 162 | test(__LINE__, 0, "11", 11); 163 | test(__LINE__, 0, "65", 65); 164 | test(__LINE__, 0, "127", 127); 165 | test(__LINE__, 0, "128", 127); 166 | test(__LINE__, 0, "-1", -1); 167 | test(__LINE__, 0, "-128", -128); 168 | test(__LINE__, 0, "-129", -128); 169 | 170 | test(__LINE__, "", "", ""); 171 | test(__LINE__, "", " ", " "); 172 | test(__LINE__, "", "0", "0"); 173 | test(__LINE__, "", "1", "1"); 174 | test(__LINE__, "", "a", "a"); 175 | test(__LINE__, "", "ab", "ab"); 176 | test(__LINE__, "", "abc", "abc"); 177 | 178 | using wide_ui_t = unsigned long long int; 179 | test_clamp::in( __LINE__ ); 180 | test_clamp::in( __LINE__ ); 181 | test_clamp::in( __LINE__ ); 182 | test_clamp::in( __LINE__ ); 183 | test_clamp::in( __LINE__ ); 184 | 185 | using wide_i_t = long long int; 186 | test_clamp::in(__LINE__); 187 | test_clamp::in( __LINE__ ); 188 | test_clamp::in( __LINE__ ); 189 | test_clamp::in( __LINE__ ); 190 | test_clamp::in( __LINE__ ); 191 | 192 | } 193 | catch(std::exception& e) { 194 | std::cerr << e.what() << std::endl; 195 | return 1; 196 | } 197 | } 198 | --------------------------------------------------------------------------------