first
This commit is contained in:
@@ -0,0 +1,317 @@
|
||||
function(add_cli_exe T)
|
||||
add_executable(${T} ${ARGN})
|
||||
target_link_libraries(${T} PUBLIC CLI11)
|
||||
set_property(TARGET ${T} PROPERTY FOLDER "Examples")
|
||||
if(CLI11_FORCE_LIBCXX)
|
||||
set_property(
|
||||
TARGET ${T}
|
||||
APPEND_STRING
|
||||
PROPERTY LINK_FLAGS -stdlib=libc++)
|
||||
target_link_libraries(${T} PUBLIC c++abi)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if(CLI11_BUILD_EXAMPLES_JSON AND CMAKE_VERSION VERSION_GREATER "3.14.7")
|
||||
message(STATUS "Using nlohmann/json")
|
||||
FetchContent_Declare(
|
||||
json
|
||||
URL https://github.com/nlohmann/json/releases/download/v3.7.3/include.zip
|
||||
URL_HASH "SHA256=87b5884741427220d3a33df1363ae0e8b898099fbc59f1c451113f6732891014")
|
||||
|
||||
FetchContent_MakeAvailable(json)
|
||||
|
||||
add_cli_exe(json json.cpp)
|
||||
target_include_directories(json PUBLIC SYSTEM "${json_SOURCE_DIR}/single_include")
|
||||
|
||||
add_test(NAME json_config_out COMMAND json --item 2)
|
||||
set_property(TEST json_config_out PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[\{.*"item": "2".*"simple": false.*\}]=])
|
||||
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/input.json" [=[{"item":3,"simple":false}]=])
|
||||
add_test(NAME json_config_in COMMAND json --config "${CMAKE_CURRENT_BINARY_DIR}/input.json")
|
||||
set_property(TEST json_config_in PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[\{.*"item": "3".*"simple": false.*\}]=])
|
||||
endif()
|
||||
|
||||
add_cli_exe(simple simple.cpp)
|
||||
add_test(NAME simple_basic COMMAND simple)
|
||||
add_test(NAME simple_all COMMAND simple -f filename.txt -c 12 --flag --flag -d 1.2)
|
||||
set_property(
|
||||
TEST simple_all
|
||||
PROPERTY
|
||||
PASS_REGULAR_EXPRESSION
|
||||
[=[Working on file: filename.txt, direct count: 1, opt count: 1.*Working on count: 12, direct count: 1, opt count: 1.*Received flag: 2 \(2\) times.*Some value: 1\.2]=]
|
||||
)
|
||||
|
||||
add_test(NAME simple_version COMMAND simple --version)
|
||||
set_property(TEST simple_version PROPERTY PASS_REGULAR_EXPRESSION "${CLI11_VERSION}")
|
||||
|
||||
add_cli_exe(subcommands subcommands.cpp)
|
||||
add_test(NAME subcommands_none COMMAND subcommands)
|
||||
set_property(TEST subcommands_none PROPERTY PASS_REGULAR_EXPRESSION "A subcommand is required")
|
||||
add_test(
|
||||
NAME subcommands_all
|
||||
COMMAND subcommands --random start --file
|
||||
name stop --count)
|
||||
set_property(
|
||||
TEST subcommands_all
|
||||
PROPERTY
|
||||
PASS_REGULAR_EXPRESSION
|
||||
[=[Working on --file from start: name.*Working on --count from stop: 1, direct count: 1.*Count of --random flag: 1.*Subcommand: start.*Subcommand: stop]=]
|
||||
)
|
||||
|
||||
add_cli_exe(subcom_partitioned subcom_partitioned.cpp)
|
||||
add_test(NAME subcom_partitioned_none COMMAND subcom_partitioned)
|
||||
set_property(
|
||||
TEST subcom_partitioned_none
|
||||
PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[--file is required.*Run with --help for more information\..*This is a timer:]=])
|
||||
|
||||
add_test(NAME subcom_partitioned_all COMMAND subcom_partitioned --file this --count --count -d 1.2)
|
||||
set_property(
|
||||
TEST subcom_partitioned_all
|
||||
PROPERTY
|
||||
PASS_REGULAR_EXPRESSION
|
||||
[=[Working on file: this, direct count: 1, opt count: 1.*Working on count: 2, direct count: 2, opt count: 2.*Some value: 1\.2.*This is a timer:]=]
|
||||
)
|
||||
# test shows that the help prints out for unnamed subcommands
|
||||
add_test(NAME subcom_partitioned_help COMMAND subcom_partitioned --help)
|
||||
set_property(
|
||||
TEST subcom_partitioned_help
|
||||
PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[-f,[ \t]*--file TEXT REQUIRED(.|[\r\n])*-d,[ \t]*--double FLOAT]=])
|
||||
|
||||
####################################################
|
||||
add_cli_exe(config_app config_app.cpp)
|
||||
add_test(NAME config_app1 COMMAND config_app -p)
|
||||
set_property(TEST config_app1 PROPERTY PASS_REGULAR_EXPRESSION "file=")
|
||||
|
||||
add_test(NAME config_app2 COMMAND config_app -p -f /)
|
||||
set_property(TEST config_app2 PROPERTY PASS_REGULAR_EXPRESSION "file=\"/\"")
|
||||
|
||||
add_test(NAME config_app3 COMMAND config_app -f "" -p)
|
||||
set_property(TEST config_app3 PROPERTY PASS_REGULAR_EXPRESSION "file=\"\"")
|
||||
|
||||
add_test(NAME config_app4 COMMAND config_app -f "/" -p)
|
||||
set_property(TEST config_app4 PROPERTY PASS_REGULAR_EXPRESSION "file=\"/\"")
|
||||
|
||||
####################################################
|
||||
|
||||
add_cli_exe(option_groups option_groups.cpp)
|
||||
add_test(NAME option_groups_missing COMMAND option_groups)
|
||||
set_property(TEST option_groups_missing PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[Exactly 1 option from(.|[\r\n])*is required]=])
|
||||
add_test(NAME option_groups_extra COMMAND option_groups --csv --binary)
|
||||
set_property(TEST option_groups_extra PROPERTY PASS_REGULAR_EXPRESSION "but 2 were given")
|
||||
add_test(NAME option_groups_extra2 COMMAND option_groups --csv --address "192.168.1.1" -o
|
||||
"test.out")
|
||||
set_property(TEST option_groups_extra2 PROPERTY PASS_REGULAR_EXPRESSION "at most 1")
|
||||
|
||||
add_cli_exe(positional_arity positional_arity.cpp)
|
||||
add_test(NAME positional_arity1 COMMAND positional_arity one)
|
||||
set_property(TEST positional_arity1 PROPERTY PASS_REGULAR_EXPRESSION "File 1 = one")
|
||||
add_test(NAME positional_arity2 COMMAND positional_arity one two)
|
||||
set_property(TEST positional_arity2 PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[File 1 = one.*File 2 = two]=])
|
||||
add_test(NAME positional_arity3 COMMAND positional_arity 1 2 one)
|
||||
set_property(TEST positional_arity3 PROPERTY PASS_REGULAR_EXPRESSION "File 1 = one")
|
||||
add_test(NAME positional_arity_fail COMMAND positional_arity 1 one two)
|
||||
set_property(TEST positional_arity_fail PROPERTY PASS_REGULAR_EXPRESSION "Could not convert")
|
||||
|
||||
add_cli_exe(positional_validation positional_validation.cpp)
|
||||
add_test(NAME positional_validation1 COMMAND positional_validation one)
|
||||
set_property(TEST positional_validation1 PROPERTY PASS_REGULAR_EXPRESSION "File 1 = one")
|
||||
add_test(NAME positional_validation2 COMMAND positional_validation one 1 2 two)
|
||||
set_property(TEST positional_validation2 PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[File 1 = one.*File 2 = two]=])
|
||||
add_test(NAME positional_validation3 COMMAND positional_validation 1 2 one)
|
||||
set_property(TEST positional_validation3 PROPERTY PASS_REGULAR_EXPRESSION "File 1 = one")
|
||||
add_test(NAME positional_validation4 COMMAND positional_validation 1 one two 2)
|
||||
set_property(TEST positional_validation4 PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[File 1 = one.*File 2 = two]=])
|
||||
if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
|
||||
OR NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
#this test doesn't work without get_time which isn't available until GCC 5.0
|
||||
add_cli_exe(date_validator date_validator.cpp)
|
||||
add_test(NAME date_validator1 COMMAND date_validator --time 2025-08-14T14:30:00)
|
||||
set_property(TEST date_validator1 PROPERTY PASS_REGULAR_EXPRESSION "date given")
|
||||
add_test(NAME date_validator2 COMMAND date_validator --time 8/17/2025T14:30:00)
|
||||
set_property(TEST date_validator2 PROPERTY PASS_REGULAR_EXPRESSION "Failed to parse time string")
|
||||
endif()
|
||||
|
||||
add_cli_exe(custom_validator custom_validator.cpp)
|
||||
add_test(NAME custom_validator1 COMMAND custom_validator --number 12)
|
||||
set_property(TEST custom_validator1 PROPERTY PASS_REGULAR_EXPRESSION "value not within range")
|
||||
add_test(NAME custom_validator2 COMMAND custom_validator --number 12 --center 10 --range 3)
|
||||
set_property(TEST custom_validator2 PROPERTY PASS_REGULAR_EXPRESSION "number 12 in range")
|
||||
|
||||
add_cli_exe(shapes shapes.cpp)
|
||||
add_test(NAME shapes_all COMMAND shapes circle 4.4 circle 10.7 rectangle 4 4 circle 2.3 triangle
|
||||
4.5 ++ rectangle 2.1 ++ circle 234.675)
|
||||
set_property(
|
||||
TEST shapes_all
|
||||
PROPERTY
|
||||
PASS_REGULAR_EXPRESSION
|
||||
[=[circle2 with radius 10\.7(.|[\r\n])*triangle1 with sides \[4\.5\](.|[\r\n])*rectangle2 with edges \[2\.1,2\.1\](.|[\r\n])*circle4 with radius 234\.675]=]
|
||||
)
|
||||
|
||||
add_cli_exe(ranges ranges.cpp)
|
||||
add_test(NAME ranges_range COMMAND ranges --range 1 2 3)
|
||||
set_property(TEST ranges_range PROPERTY PASS_REGULAR_EXPRESSION "[2:1:3]")
|
||||
add_test(NAME ranges_minmax COMMAND ranges --min 2 --max 3)
|
||||
set_property(TEST ranges_minmax PROPERTY PASS_REGULAR_EXPRESSION "[2:1:3]")
|
||||
add_test(NAME ranges_error COMMAND ranges --min 2 --max 3 --step 1 --range 1 2 3)
|
||||
set_property(TEST ranges_error PROPERTY PASS_REGULAR_EXPRESSION "Exactly 1 option from")
|
||||
|
||||
add_cli_exe(validators validators.cpp)
|
||||
add_test(NAME validators_help COMMAND validators --help)
|
||||
set_property(
|
||||
TEST validators_help
|
||||
PROPERTY
|
||||
PASS_REGULAR_EXPRESSION
|
||||
[=[ -f,[ \t]*--file TEXT:FILE.*File name.* -v,[ \t]*--value INT:INT in \[3 - 6\].*Value in range]=]
|
||||
)
|
||||
add_test(NAME validators_file COMMAND validators --file nonex.xxx)
|
||||
set_property(
|
||||
TEST validators_file
|
||||
PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[--file: File does not exist: nonex\.xxx.*Run with --help for more information\.]=])
|
||||
add_test(NAME validators_plain COMMAND validators --value 9)
|
||||
set_property(
|
||||
TEST validators_plain
|
||||
PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[--value: Value 9 not in range \[3 - 6\].*Run with --help for more information\.]=])
|
||||
|
||||
add_cli_exe(groups groups.cpp)
|
||||
add_test(NAME groups_none COMMAND groups)
|
||||
set_property(
|
||||
TEST groups_none
|
||||
PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[--file is required.*Run with --help for more information\..*This is a timer:]=])
|
||||
add_test(NAME groups_all COMMAND groups --file this --count --count -d 1.2)
|
||||
set_property(
|
||||
TEST groups_all
|
||||
PROPERTY
|
||||
PASS_REGULAR_EXPRESSION
|
||||
[=[Working on file: this, direct count: 1, opt count: 1.*Working on count: 2, direct count: 2, opt count: 2.*Some value: 1\.2.*This is a timer:]=]
|
||||
)
|
||||
|
||||
add_cli_exe(inter_argument_order inter_argument_order.cpp)
|
||||
add_test(NAME inter_argument_order COMMAND inter_argument_order --foo 1 2 3 --x --bar 4 5 6 --z
|
||||
--foo 7 8)
|
||||
set_property(
|
||||
TEST inter_argument_order
|
||||
PROPERTY
|
||||
PASS_REGULAR_EXPRESSION
|
||||
[=[foo : 1
|
||||
foo : 2
|
||||
foo : 3
|
||||
bar : 4
|
||||
bar : 5
|
||||
bar : 6
|
||||
foo : 7
|
||||
foo : 8]=])
|
||||
|
||||
add_cli_exe(prefix_command prefix_command.cpp)
|
||||
add_test(NAME prefix_command COMMAND prefix_command -v 3 2 1 -- other one two 3)
|
||||
set_property(
|
||||
TEST prefix_command PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[Prefix: 3 : 2 : 1.*Remaining commands: other one two 3]=])
|
||||
|
||||
#just test a minimal build
|
||||
add_cli_exe(minimal minimal.cpp)
|
||||
add_test(NAME minimal COMMAND minimal)
|
||||
|
||||
add_cli_exe(arg_capture arg_capture.cpp)
|
||||
add_test(NAME arg_capture COMMAND arg_capture -v 27 --sub -v 13 --val prefix)
|
||||
set_property(TEST arg_capture PROPERTY PASS_REGULAR_EXPRESSION "value=27")
|
||||
add_test(NAME arg_capture2 COMMAND arg_capture -v 27 --sub -v 13 --val prefix)
|
||||
set_property(TEST arg_capture2 PROPERTY PASS_REGULAR_EXPRESSION "after Args:-v 13 --val prefix")
|
||||
|
||||
add_cli_exe(callback_passthrough callback_passthrough.cpp)
|
||||
add_test(NAME callback_passthrough1 COMMAND callback_passthrough --argname t2 --t2 test)
|
||||
set_property(TEST callback_passthrough1 PROPERTY PASS_REGULAR_EXPRESSION "the value is now test")
|
||||
add_test(NAME callback_passthrough2 COMMAND callback_passthrough --arg EEEK --argname arg)
|
||||
set_property(TEST callback_passthrough2 PROPERTY PASS_REGULAR_EXPRESSION "the value is now EEEK")
|
||||
|
||||
add_cli_exe(enum enum.cpp)
|
||||
add_test(NAME enum_pass COMMAND enum -l 1)
|
||||
add_test(NAME enum_fail COMMAND enum -l 4)
|
||||
set_property(
|
||||
TEST enum_fail
|
||||
PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[--level: Check 4 value in \{.*FAILED.*Run with --help for more information\.]=])
|
||||
|
||||
add_cli_exe(enum_ostream enum_ostream.cpp)
|
||||
add_test(NAME enum_ostream_pass COMMAND enum_ostream --level medium)
|
||||
set_property(TEST enum_ostream_pass PROPERTY PASS_REGULAR_EXPRESSION "Enum received: Medium")
|
||||
|
||||
add_cli_exe(digit_args digit_args.cpp)
|
||||
add_test(NAME digit_args COMMAND digit_args -h)
|
||||
set_property(TEST digit_args PROPERTY PASS_REGULAR_EXPRESSION "-3{3}")
|
||||
|
||||
add_cli_exe(modhelp modhelp.cpp)
|
||||
add_test(NAME modhelp COMMAND modhelp -a test -h)
|
||||
set_property(TEST modhelp PROPERTY PASS_REGULAR_EXPRESSION "Option -a string in help: test")
|
||||
|
||||
add_cli_exe(array_option array_option.cpp)
|
||||
add_test(NAME array_option COMMAND array_option --a 1 2)
|
||||
set_property(TEST array_option PROPERTY PASS_REGULAR_EXPRESSION "pass")
|
||||
|
||||
add_subdirectory(subcom_in_files)
|
||||
add_test(NAME subcom_in_files COMMAND subcommand_main subcommand_a -f this.txt --with-foo)
|
||||
set_property(TEST subcom_in_files PROPERTY PASS_REGULAR_EXPRESSION
|
||||
[=[Working on file: this\.txt.*Using foo!]=])
|
||||
|
||||
add_cli_exe(formatter formatter.cpp)
|
||||
|
||||
add_cli_exe(nested nested.cpp)
|
||||
|
||||
add_cli_exe(subcom_help subcom_help.cpp)
|
||||
add_test(NAME subcom_help_normal COMMAND subcom_help sub --help)
|
||||
add_test(NAME subcom_help_reversed COMMAND subcom_help --help sub)
|
||||
|
||||
add_cli_exe(retired retired.cpp)
|
||||
add_test(NAME retired_retired_test COMMAND retired --retired_option)
|
||||
add_test(NAME retired_retired_test2 COMMAND retired --retired_option 567)
|
||||
add_test(NAME retired_retired_test3 COMMAND retired --retired_option2 567 689 789)
|
||||
add_test(NAME retired_deprecated COMMAND retired --deprecate 19 20)
|
||||
|
||||
set_property(TEST retired_retired_test PROPERTY PASS_REGULAR_EXPRESSION "WARNING.*retired")
|
||||
|
||||
set_property(TEST retired_retired_test2 PROPERTY PASS_REGULAR_EXPRESSION "WARNING.*retired")
|
||||
|
||||
set_property(TEST retired_retired_test3 PROPERTY PASS_REGULAR_EXPRESSION "WARNING.*retired")
|
||||
|
||||
set_property(TEST retired_deprecated PROPERTY PASS_REGULAR_EXPRESSION "deprecated.*not_deprecated")
|
||||
|
||||
if(CMAKE_CXX_STANDARD GREATER 13)
|
||||
add_cli_exe(close_match close_match.cpp)
|
||||
|
||||
add_test(NAME close_match_test COMMAND close_match i)
|
||||
add_test(NAME close_match_test2 COMMAND close_match upg)
|
||||
add_test(NAME close_match_test3 COMMAND close_match rem)
|
||||
add_test(NAME close_match_test4 COMMAND close_match upgrde)
|
||||
|
||||
set_property(TEST close_match_test PROPERTY PASS_REGULAR_EXPRESSION "install")
|
||||
|
||||
set_property(TEST close_match_test2 PROPERTY PASS_REGULAR_EXPRESSION "upgrade")
|
||||
|
||||
set_property(TEST close_match_test3 PROPERTY PASS_REGULAR_EXPRESSION "remove")
|
||||
|
||||
set_property(TEST close_match_test4 PROPERTY PASS_REGULAR_EXPRESSION "closest match is upgrade")
|
||||
endif()
|
||||
#--------------------------------------------
|
||||
add_cli_exe(custom_parse custom_parse.cpp)
|
||||
add_test(NAME cp_test COMMAND custom_parse --dv 1.7)
|
||||
set_property(TEST cp_test PROPERTY PASS_REGULAR_EXPRESSION "called correct")
|
||||
|
||||
#-----------------------------------------------------
|
||||
add_cli_exe(help_usage help_usage.cpp)
|
||||
add_test(NAME help_use COMMAND help_usage --help)
|
||||
set_property(TEST help_use PROPERTY PASS_REGULAR_EXPRESSION "[1..9]")
|
||||
|
||||
#------------------------------------------------
|
||||
# This executable is for manual testing and is expected to change regularly
|
||||
|
||||
add_cli_exe(tester testEXE.cpp)
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Code modified from https://github.com/CLIUtils/CLI11/issues/559
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
/** This example demonstrates the use of `prefix_command` on a subcommand
|
||||
to capture all subsequent arguments along with an alias to make it appear as a regular options.
|
||||
|
||||
All the values after the "sub" or "--sub" are available in the remaining() method.
|
||||
*/
|
||||
int main(int argc, const char *argv[]) {
|
||||
|
||||
int value{0};
|
||||
CLI::App app{"Test App"};
|
||||
app.add_option("-v", value, "value");
|
||||
|
||||
auto *subcom = app.add_subcommand("sub", "")->prefix_command();
|
||||
subcom->alias("--sub");
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::cout << "value=" << value << '\n';
|
||||
std::cout << "after Args:";
|
||||
for(const auto &aarg : subcom->remaining()) {
|
||||
std::cout << aarg << " ";
|
||||
}
|
||||
std::cout << '\n';
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Code modified from Loic Gouarin(https://github.com/gouarin) https://github.com/CLIUtils/CLI11/issues/1135
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::array<int, 2> a{0, 1};
|
||||
CLI::App app{"My app"};
|
||||
app.add_option("--a", a, "an array")->capture_default_str();
|
||||
app.parse(argc, argv);
|
||||
|
||||
std::cout << "pass\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("callback_passthrough");
|
||||
app.allow_extras();
|
||||
std::string argName;
|
||||
std::string val;
|
||||
app.add_option("--argname", argName, "the name of the custom command line argument");
|
||||
app.callback([&app, &val, &argName]() {
|
||||
if(!argName.empty()) {
|
||||
CLI::App subApp;
|
||||
subApp.add_option("--" + argName, val, "custom argument option");
|
||||
subApp.parse(app.remaining_for_passthrough());
|
||||
}
|
||||
});
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
std::cout << "the value is now " << val << '\n';
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Code inspired by discussion from https://github.com/CLIUtils/CLI11/issues/1149
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
|
||||
// only works with C++14 or higher
|
||||
|
||||
// Levenshtein distance function code generated by chatgpt/copilot
|
||||
std::size_t levenshteinDistance(const std::string &s1, const std::string &s2) {
|
||||
std::size_t len1 = s1.size(), len2 = s2.size();
|
||||
if(len1 == 0 || len2 == 0) {
|
||||
return (std::max)(len1, len2);
|
||||
}
|
||||
std::vector<std::size_t> prev(len2 + 1), curr(len2 + 1);
|
||||
std::iota(prev.begin(), prev.end(), 0); // Fill prev with {0, 1, ..., len2}
|
||||
|
||||
for(std::size_t ii = 1; ii <= len1; ++ii) {
|
||||
curr[0] = ii;
|
||||
for(std::size_t jj = 1; jj <= len2; ++jj) {
|
||||
// If characters match, no substitution cost; otherwise, cost is 1.
|
||||
std::size_t cost = (s1[ii - 1] == s2[jj - 1]) ? 0 : 1;
|
||||
|
||||
// Compute the minimum cost between:
|
||||
// - Deleting a character from `s1` (prev[jj] + 1)
|
||||
// - Inserting a character into `s1` (curr[jj - 1] + 1)
|
||||
// - Substituting a character (prev[jj - 1] + cost)
|
||||
|
||||
curr[jj] = (std::min)({prev[jj] + 1, curr[jj - 1] + 1, prev[jj - 1] + cost});
|
||||
}
|
||||
prev = std::exchange(curr, prev); // Swap vectors efficiently
|
||||
}
|
||||
return prev[len2];
|
||||
}
|
||||
|
||||
// Finds the closest string from a list (modified from chat gpt code)
|
||||
std::pair<std::string, std::size_t> findClosestMatch(const std::string &input,
|
||||
const std::vector<std::string> &candidates) {
|
||||
std::string closest;
|
||||
std::size_t minDistance{std::string::npos};
|
||||
for(const auto &candidate : candidates) {
|
||||
std::size_t distance = levenshteinDistance(input, candidate);
|
||||
if(distance < minDistance) {
|
||||
minDistance = distance;
|
||||
closest = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return {closest, minDistance};
|
||||
}
|
||||
|
||||
void addSubcommandCloseMatchDetection(CLI::App *app, std::size_t minDistance = 3) {
|
||||
// if extras are not allowed then there will be no remaining
|
||||
app->allow_extras(true);
|
||||
// generate a list of subcommand names
|
||||
auto subs = app->get_subcommands(nullptr);
|
||||
CLI::results_t list;
|
||||
for(const auto *sub : subs) {
|
||||
if(!sub->get_name().empty()) {
|
||||
list.emplace_back(sub->get_name());
|
||||
}
|
||||
const auto &aliases = sub->get_aliases();
|
||||
if(!aliases.empty()) {
|
||||
list.insert(list.end(), aliases.begin(), aliases.end());
|
||||
}
|
||||
}
|
||||
// add a callback that runs before a final callback and loops over the remaining arguments for subcommands
|
||||
app->parse_complete_callback([app, minDistance, list = std::move(list)]() {
|
||||
for(auto &extra : app->remaining()) {
|
||||
if(!extra.empty() && extra.front() != '-') {
|
||||
auto closest = findClosestMatch(extra, list);
|
||||
if(closest.second <= minDistance) {
|
||||
std::cout << "unmatched command \"" << extra << "\", closest match is " << closest.first << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** This example demonstrates the use of close match detection to detect invalid commands that are close matches to
|
||||
* existing ones
|
||||
*/
|
||||
int main(int argc, const char *argv[]) {
|
||||
|
||||
int value{0};
|
||||
CLI::App app{"App for testing prefix matching and close string matching"};
|
||||
// turn on prefix matching
|
||||
app.allow_subcommand_prefix_matching();
|
||||
app.add_option("-v", value, "value");
|
||||
|
||||
app.add_subcommand("install", "");
|
||||
app.add_subcommand("upgrade", "");
|
||||
app.add_subcommand("remove", "");
|
||||
app.add_subcommand("test", "");
|
||||
// enable close matching for subcommands
|
||||
addSubcommandCloseMatchDetection(&app, 5);
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
auto subs = app.get_subcommands();
|
||||
for(const auto &sub : subs) {
|
||||
std::cout << sub->get_name() << "\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("configuration print example");
|
||||
|
||||
app.add_flag("-p,--print", "Print configuration and exit")->configurable(false); // NEW: print flag
|
||||
|
||||
std::string file;
|
||||
CLI::Option *opt = app.add_option("-f,--file,file", file, "File name")
|
||||
->capture_default_str()
|
||||
->run_callback_for_default(); // NEW: capture_default_str()
|
||||
|
||||
int count{0};
|
||||
CLI::Option *copt =
|
||||
app.add_option("-c,--count", count, "Counter")->capture_default_str(); // NEW: capture_default_str()
|
||||
|
||||
int v{0};
|
||||
CLI::Option *flag = app.add_flag("--flag", v, "Some flag that can be passed multiple times")
|
||||
->capture_default_str(); // NEW: capture_default_str()
|
||||
|
||||
double value{0.0}; // = 3.14;
|
||||
app.add_option("-d,--double", value, "Some Value")->capture_default_str(); // NEW: capture_default_str()
|
||||
|
||||
app.get_config_formatter_base()->quoteCharacter('"', '"');
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
if(app.get_option("--print")->as<bool>()) { // NEW: print configuration and exit
|
||||
std::cout << app.config_to_str(true, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::cout << "Working on file: " << file << ", direct count: " << app.count("--file")
|
||||
<< ", opt count: " << opt->count() << '\n';
|
||||
std::cout << "Working on count: " << count << ", direct count: " << app.count("--count")
|
||||
<< ", opt count: " << copt->count() << '\n';
|
||||
std::cout << "Received flag: " << v << " (" << flag->count() << ") times\n";
|
||||
std::cout << "Some value: " << value << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// from Issue #566 on github https://github.com/CLIUtils/CLI11/issues/566
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
// example file to demonstrate a custom lexical cast function
|
||||
|
||||
template <class T = int> struct Values {
|
||||
T a;
|
||||
T b;
|
||||
T c;
|
||||
};
|
||||
|
||||
// in C++20 this is constructible from a double due to the new aggregate initialization in C++20.
|
||||
using DoubleValues = Values<double>;
|
||||
|
||||
// the lexical cast operator should be in the same namespace as the type for ADL to work properly
|
||||
bool lexical_cast(const std::string &input, Values<double> & /*v*/) {
|
||||
std::cout << "called correct lexical_cast function ! val: " << input << '\n';
|
||||
return true;
|
||||
}
|
||||
|
||||
DoubleValues doubles;
|
||||
void argparse(CLI::Option_group *group) { group->add_option("--dv", doubles)->default_str("0"); }
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::App app;
|
||||
|
||||
argparse(app.add_option_group("param"));
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
template <typename T> class DeltaRange : public CLI::Validator {
|
||||
public:
|
||||
T center_point;
|
||||
T delta;
|
||||
DeltaRange(const T ¢er, const T &range)
|
||||
: CLI::Validator(
|
||||
[this](const std::string &value) -> std::string {
|
||||
T newValue;
|
||||
auto result = CLI::detail::lexical_cast(value, newValue);
|
||||
if(!(result && this->check(newValue))) {
|
||||
return std::string("value not within range");
|
||||
}
|
||||
return std::string{};
|
||||
},
|
||||
"RANGE"),
|
||||
center_point(center), delta(range) {}
|
||||
|
||||
CLI11_NODISCARD bool check(const T &test) const {
|
||||
return (test >= (center_point - delta)) && (test <= (center_point + delta));
|
||||
}
|
||||
CLI11_NODISCARD T center() const { return center_point; }
|
||||
CLI11_NODISCARD T range() const { return delta; }
|
||||
void center(const T &value) { center_point = value; }
|
||||
void range(const T &value) { delta = value; }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
/* this application creates custom validator which is a range center+/- range The center and range can be defined by
|
||||
* other command line options and are updated dynamically
|
||||
*/
|
||||
CLI::App app("custom range validator");
|
||||
|
||||
std::string value;
|
||||
auto dr = std::make_shared<DeltaRange<int>>(7, 3);
|
||||
app.add_option("--number", value, "enter value in the related range")->check(dr)->required();
|
||||
|
||||
app.add_option_function<int>("--center", [&dr](int new_center) { dr->center(new_center); })->trigger_on_parse();
|
||||
app.add_option_function<int>("--range", [&dr](int new_range) { dr->range(new_range); })->trigger_on_parse();
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::cout << "number " << value << " in range = " << dr->center() << " +/- " << dr->range() << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
// Custom validator is an alias of Validator, the constructor takes a function that takes as input and returns a string
|
||||
const CLI::CustomValidator ISO8601(
|
||||
[](std::string &input) {
|
||||
std::tm tm = {};
|
||||
std::istringstream ss(input);
|
||||
|
||||
ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S");
|
||||
if(ss.fail()) {
|
||||
return std::string("Failed to parse time string");
|
||||
}
|
||||
return std::string{};
|
||||
},
|
||||
"datetime[%Y-%m-%dT%H:%M:%S]");
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("custom validator testing");
|
||||
|
||||
std::string value;
|
||||
app.add_option("--time", value, "enter a date in iso8601 format")->check(ISO8601)->required();
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::cout << "date given = " << value << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::App app;
|
||||
|
||||
int val{0};
|
||||
// add a set of flags with default values associate with them
|
||||
app.add_flag("-1{1},-2{2},-3{3},-4{4},-5{5},-6{6}, -7{7}, -8{8}, -9{9}", val, "compression level");
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::cout << "value = " << val << '\n';
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#define CLI11_ENABLE_EXTRA_VALIDATORS 1
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
enum class Level : int { High, Medium, Low };
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::App app;
|
||||
|
||||
Level level{Level::Low};
|
||||
// specify string->value mappings
|
||||
std::map<std::string, Level> map{{"high", Level::High}, {"medium", Level::Medium}, {"low", Level::Low}};
|
||||
// CheckedTransformer translates and checks whether the results are either in one of the strings or in one of the
|
||||
// translations already
|
||||
app.add_option("-l,--level", level, "Level settings")
|
||||
->required()
|
||||
->transform(CLI::CheckedTransformer(map, CLI::ignore_case));
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
// CLI11's built in enum streaming can be used outside CLI11 like this:
|
||||
using CLI::enums::operator<<;
|
||||
std::cout << "Enum received: " << level << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#define CLI11_ENABLE_EXTRA_VALIDATORS 1
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
enum class Level : int { High, Medium, Low };
|
||||
|
||||
// Defining operator<<() for your enum class (in this case for 'Level') overrides CLI11's enum streaming
|
||||
inline std::ostream &operator<<(std::ostream &os, const Level &level) {
|
||||
switch(level) {
|
||||
case Level::High:
|
||||
os << "High";
|
||||
break;
|
||||
case Level::Medium:
|
||||
os << "Medium";
|
||||
break;
|
||||
case Level::Low:
|
||||
os << "Low";
|
||||
break;
|
||||
}
|
||||
os << " (ft rom custom ostream)";
|
||||
return os;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::App app;
|
||||
|
||||
Level level{Level::Low};
|
||||
// specify string->value mappings
|
||||
std::map<std::string, Level> map{{"high", Level::High}, {"medium", Level::Medium}, {"low", Level::Low}};
|
||||
// CheckedTransformer translates and checks whether the results are either in one of the strings or in one of the
|
||||
// translations already
|
||||
app.add_option("-l,--level", level, "Level settings")
|
||||
->required()
|
||||
->transform(CLI::CheckedTransformer(map, CLI::ignore_case));
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
// CLI11's built in enum streaming can be used outside CLI11 like this:
|
||||
using CLI::enums::operator<<;
|
||||
std::cout << "Enum received: " << level << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class MyFormatter : public CLI::Formatter {
|
||||
public:
|
||||
MyFormatter() : Formatter() {}
|
||||
std::string make_option_opts(const CLI::Option *) const override { return " OPTION"; }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::App app;
|
||||
app.set_help_all_flag("--help-all", "Show all help");
|
||||
|
||||
auto fmt = std::make_shared<MyFormatter>();
|
||||
fmt->column_width(15);
|
||||
app.formatter(fmt);
|
||||
|
||||
app.add_flag("--flag", "This is a flag");
|
||||
|
||||
auto *sub1 = app.add_subcommand("one", "Description One");
|
||||
sub1->add_flag("--oneflag", "Some flag");
|
||||
auto *sub2 = app.add_subcommand("two", "Description Two");
|
||||
sub2->add_flag("--twoflag", "Some other flag");
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::cout << "This app was meant to show off the formatter, run with -h" << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <CLI/Timer.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::AutoTimer give_me_a_name("This is a timer");
|
||||
|
||||
CLI::App app("K3Pi goofit fitter");
|
||||
|
||||
std::string file;
|
||||
CLI::Option *opt = app.add_option("-f,--file,file", file, "File name")->required()->group("Important");
|
||||
|
||||
int count{0};
|
||||
CLI::Option *copt = app.add_flag("-c,--count", count, "Counter")->required()->group("Important");
|
||||
|
||||
double value{0.0}; // = 3.14;
|
||||
app.add_option("-d,--double", value, "Some Value")->group("Other");
|
||||
|
||||
try {
|
||||
app.parse(argc, argv);
|
||||
} catch(const CLI::ParseError &e) {
|
||||
return app.exit(e);
|
||||
}
|
||||
|
||||
std::cout << "Working on file: " << file << ", direct count: " << app.count("--file")
|
||||
<< ", opt count: " << opt->count() << '\n';
|
||||
std::cout << "Working on count: " << count << ", direct count: " << app.count("--count")
|
||||
<< ", opt count: " << copt->count() << '\n';
|
||||
std::cout << "Some value: " << value << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::string input_file_name, output_file_name;
|
||||
int level{5}, subopt{0};
|
||||
|
||||
// app caption
|
||||
CLI::App app{"CLI11 help"};
|
||||
// this tests out some of the wide character support, mainly for compilation checking
|
||||
argv = app.ensure_utf8(argv);
|
||||
app.require_subcommand(1);
|
||||
// subcommands options and flags
|
||||
CLI::App *const encode = app.add_subcommand("e", "encode")->ignore_case(); // ignore case
|
||||
encode->add_option("input", input_file_name, "input file")
|
||||
->option_text(" ")
|
||||
->required()
|
||||
->check(CLI::ExistingFile); // file must exist
|
||||
encode->add_option("output", output_file_name, "output file")->option_text(" ")->required(); // required option
|
||||
encode->add_option("-l, --level", level, "encoding level")
|
||||
->option_text("[1..9]")
|
||||
->check(CLI::Range(1, 9))
|
||||
->default_val(5); // limit parameter range
|
||||
encode->add_flag("-R, --remove", "remove input file"); // no parameter option
|
||||
encode->add_flag("-s, --suboption", subopt, "suboption")->option_text(" ");
|
||||
|
||||
CLI::App *const decode = app.add_subcommand("d", "decode")->ignore_case();
|
||||
decode->add_option("input", input_file_name, "input file")->option_text(" ")->required()->check(CLI::ExistingFile);
|
||||
decode->add_option("output", output_file_name, "output file")->option_text(" ")->required();
|
||||
|
||||
// Usage message modification
|
||||
std::string usage_msg = "Usage: " + std::string(argv[0]) + " <command> [options] <input-file> <output-file>";
|
||||
app.usage(usage_msg);
|
||||
// flag to display full help at once
|
||||
app.set_help_flag("");
|
||||
app.set_help_all_flag("-h, --help");
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
$ ./help_usage -h
|
||||
CLI11 help
|
||||
|
||||
OPTIONS:
|
||||
-h, --help
|
||||
|
||||
SUBCOMMANDS:
|
||||
e
|
||||
encode
|
||||
|
||||
POSITIONALS:
|
||||
input input file
|
||||
output output file
|
||||
|
||||
OPTIONS:
|
||||
-l, --level [1..9] encoding level
|
||||
-R, --remove remove input file
|
||||
-s, --suboption suboption
|
||||
|
||||
|
||||
d
|
||||
decode
|
||||
|
||||
POSITIONALS:
|
||||
input input file
|
||||
output output file
|
||||
*/
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::App app{"An app to practice mixing unlimited arguments, but still recover the original order."};
|
||||
|
||||
std::vector<int> foos;
|
||||
auto *foo = app.add_option("--foo,-f", foos, "Some unlimited argument");
|
||||
|
||||
std::vector<int> bars;
|
||||
auto *bar = app.add_option("--bar", bars, "Some unlimited argument");
|
||||
|
||||
app.add_flag("--z,--x", "Random other flags");
|
||||
|
||||
// Standard parsing lines (copy and paste in, or use CLI11_PARSE)
|
||||
try {
|
||||
app.parse(argc, argv);
|
||||
} catch(const CLI::ParseError &e) {
|
||||
return app.exit(e);
|
||||
}
|
||||
|
||||
// I prefer using the back and popping
|
||||
std::reverse(std::begin(foos), std::end(foos));
|
||||
std::reverse(std::begin(bars), std::end(bars));
|
||||
|
||||
std::vector<std::pair<std::string, int>> keyval;
|
||||
for(auto *option : app.parse_order()) {
|
||||
if(option == foo) {
|
||||
keyval.emplace_back("foo", foos.back());
|
||||
foos.pop_back();
|
||||
}
|
||||
if(option == bar) {
|
||||
keyval.emplace_back("bar", bars.back());
|
||||
bars.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
// Prove the vector is correct
|
||||
for(auto &pair : keyval) {
|
||||
std::cout << pair.first << " : " << pair.second << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// This example is only built on GCC 7 on Travis due to mismatch in stdlib
|
||||
// for clang (CLI11 is forgiving about mismatches, json.hpp is not)
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
class ConfigJSON : public CLI::Config {
|
||||
public:
|
||||
std::string to_config(const CLI::App *app, bool default_also, bool, std::string) const override {
|
||||
|
||||
json j;
|
||||
|
||||
for(const CLI::Option *opt : app->get_options({})) {
|
||||
|
||||
// Only process option with a long-name and configurable
|
||||
if(!opt->get_lnames().empty() && opt->get_configurable()) {
|
||||
std::string name = opt->get_lnames()[0];
|
||||
|
||||
// Non-flags
|
||||
if(opt->get_type_size() != 0) {
|
||||
|
||||
// If the option was found on command line
|
||||
if(opt->count() == 1)
|
||||
j[name] = opt->results().at(0);
|
||||
else if(opt->count() > 1)
|
||||
j[name] = opt->results();
|
||||
|
||||
// If the option has a default and is requested by optional argument
|
||||
else if(default_also && !opt->get_default_str().empty())
|
||||
j[name] = opt->get_default_str();
|
||||
|
||||
// Flag, one passed
|
||||
} else if(opt->count() == 1) {
|
||||
j[name] = true;
|
||||
|
||||
// Flag, multiple passed
|
||||
} else if(opt->count() > 1) {
|
||||
j[name] = opt->count();
|
||||
|
||||
// Flag, not present
|
||||
} else if(opt->count() == 0 && default_also) {
|
||||
j[name] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(const CLI::App *subcom : app->get_subcommands({}))
|
||||
j[subcom->get_name()] = json(to_config(subcom, default_also, false, ""));
|
||||
|
||||
return j.dump(4);
|
||||
}
|
||||
|
||||
std::vector<CLI::ConfigItem> from_config(std::istream &input) const override {
|
||||
json j;
|
||||
input >> j;
|
||||
return _from_config(j);
|
||||
}
|
||||
|
||||
std::vector<CLI::ConfigItem>
|
||||
_from_config(json j, std::string name = "", std::vector<std::string> prefix = {}) const {
|
||||
std::vector<CLI::ConfigItem> results;
|
||||
|
||||
if(j.is_object()) {
|
||||
for(json::iterator item = j.begin(); item != j.end(); ++item) {
|
||||
auto copy_prefix = prefix;
|
||||
if(!name.empty())
|
||||
copy_prefix.push_back(name);
|
||||
auto sub_results = _from_config(*item, item.key(), copy_prefix);
|
||||
results.insert(results.end(), sub_results.begin(), sub_results.end());
|
||||
}
|
||||
} else if(!name.empty()) {
|
||||
results.emplace_back();
|
||||
CLI::ConfigItem &res = results.back();
|
||||
res.name = name;
|
||||
res.parents = prefix;
|
||||
if(j.is_boolean()) {
|
||||
res.inputs = {j.get<bool>() ? "true" : "false"};
|
||||
} else if(j.is_number()) {
|
||||
std::stringstream ss;
|
||||
ss << j.get<double>();
|
||||
res.inputs = {ss.str()};
|
||||
} else if(j.is_string()) {
|
||||
res.inputs = {j.get<std::string>()};
|
||||
} else if(j.is_array()) {
|
||||
for(std::string ival : j)
|
||||
res.inputs.push_back(ival);
|
||||
} else {
|
||||
throw CLI::ConversionError("Failed to convert " + name);
|
||||
}
|
||||
} else {
|
||||
throw CLI::ConversionError("You must make all top level values objects in json!");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::App app;
|
||||
app.config_formatter(std::make_shared<ConfigJSON>());
|
||||
|
||||
int item;
|
||||
|
||||
app.add_flag("--simple");
|
||||
app.add_option("--item", item);
|
||||
app.set_config("--config");
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::cout << app.config_to_str(true, true) << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Code modified from https://github.com/CLIUtils/CLI11/issues/1334
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
|
||||
/** This example is a minimal example of using CLI11. It does not do anything, but it compiles and runs, and can be used
|
||||
* as a starting point for new projects.
|
||||
*/
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app{"App description"};
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::App test{R"raw(Modify the help print so that argument values are accessible.
|
||||
Note that this will not shortcut `->required` and other similar options.)raw"};
|
||||
|
||||
// Remove help flag because it shortcuts all processing
|
||||
test.set_help_flag();
|
||||
|
||||
// Add custom flag that activates help
|
||||
auto *help = test.add_flag("-h,--help", "Request help");
|
||||
|
||||
std::string some_option;
|
||||
test.add_option("-a", some_option, "Some description");
|
||||
|
||||
try {
|
||||
test.parse(argc, argv);
|
||||
if(*help)
|
||||
throw CLI::CallForHelp();
|
||||
} catch(const CLI::Error &e) {
|
||||
std::cout << "Option -a string in help: " << some_option << '\n';
|
||||
return test.exit(e);
|
||||
}
|
||||
|
||||
std::cout << "Option -a string: " << some_option << '\n';
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#define CLI11_ENABLE_EXTRA_VALIDATORS 1
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("Vision Application");
|
||||
app.set_help_all_flag("--help-all", "Expand all help");
|
||||
app.add_flag("--version", "Get version");
|
||||
|
||||
CLI::App *cameraApp = app.add_subcommand("camera", "Configure the app camera");
|
||||
cameraApp->require_subcommand(0, 1); // 0 (default) or 1 camera
|
||||
|
||||
std::string mvcamera_config_file = "mvcamera_config.json";
|
||||
CLI::App *mvcameraApp = cameraApp->add_subcommand("mvcamera", "MatrixVision Camera Configuration");
|
||||
mvcameraApp->add_option("-c,--config", mvcamera_config_file, "Config filename")
|
||||
->capture_default_str()
|
||||
->check(CLI::ExistingFile);
|
||||
|
||||
std::string mock_camera_path;
|
||||
CLI::App *mockcameraApp = cameraApp->add_subcommand("mock", "Mock Camera Configuration");
|
||||
mockcameraApp->add_option("-p,--path", mock_camera_path, "Path")->required()->check(CLI::ExistingPath);
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("data output specification");
|
||||
app.set_help_all_flag("--help-all", "Expand all help");
|
||||
|
||||
auto *format = app.add_option_group("output_format", "formatting type for output");
|
||||
auto *target = app.add_option_group("output target", "target location for the output");
|
||||
bool csv{false};
|
||||
bool human{false};
|
||||
bool binary{false};
|
||||
format->add_flag("--csv", csv, "specify the output in csv format");
|
||||
format->add_flag("--human", human, "specify the output in human readable text format");
|
||||
format->add_flag("--binary", binary, "specify the output in binary format");
|
||||
// require one of the options to be selected
|
||||
format->require_option(1);
|
||||
std::string fileLoc;
|
||||
std::string networkAddress;
|
||||
target->add_option("-o,--file", fileLoc, "specify the file location of the output");
|
||||
target->add_option("--address", networkAddress, "specify a network address to send the file");
|
||||
|
||||
// require at most one of the target options
|
||||
target->require_option(0, 1);
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::string format_type = (csv) ? std::string("CSV") : ((human) ? "human readable" : "binary");
|
||||
std::cout << "Selected " << format_type << " format\n";
|
||||
if(!fileLoc.empty()) {
|
||||
std::cout << " sent to file " << fileLoc << '\n';
|
||||
} else if(!networkAddress.empty()) {
|
||||
std::cout << " sent over network to " << networkAddress << '\n';
|
||||
} else {
|
||||
std::cout << " sent to std::cout\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("test for positional arity");
|
||||
|
||||
auto *numbers = app.add_option_group("numbers", "specify key numbers");
|
||||
auto *files = app.add_option_group("files", "specify files");
|
||||
int num1{-1}, num2{-1};
|
||||
numbers->add_option("num1", num1, "first number");
|
||||
numbers->add_option("num2", num2, "second number");
|
||||
std::string file1, file2;
|
||||
files->add_option("file1", file1, "first file")->required();
|
||||
files->add_option("file2", file2, "second file");
|
||||
// set a pre parse callback that turns the numbers group on or off depending on the number of arguments
|
||||
app.preparse_callback([numbers](std::size_t arity) {
|
||||
if(arity <= 2) {
|
||||
numbers->disabled();
|
||||
} else {
|
||||
numbers->disabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
if(num1 != -1)
|
||||
std::cout << "Num1 = " << num1 << '\n';
|
||||
|
||||
if(num2 != -1)
|
||||
std::cout << "Num2 = " << num2 << '\n';
|
||||
|
||||
std::cout << "File 1 = " << file1 << '\n';
|
||||
if(!file2.empty()) {
|
||||
std::cout << "File 2 = " << file2 << '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#define CLI11_ENABLE_EXTRA_VALIDATORS 1
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("test for positional validation");
|
||||
|
||||
int num1{-1}, num2{-1};
|
||||
app.add_option("num1", num1, "first number")->check(CLI::Number);
|
||||
app.add_option("num2", num2, "second number")->check(CLI::Number);
|
||||
std::string file1, file2;
|
||||
app.add_option("file1", file1, "first file")->required();
|
||||
app.add_option("file2", file2, "second file");
|
||||
app.validate_positionals();
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
if(num1 != -1)
|
||||
std::cout << "Num1 = " << num1 << '\n';
|
||||
|
||||
if(num2 != -1)
|
||||
std::cout << "Num2 = " << num2 << '\n';
|
||||
|
||||
std::cout << "File 1 = " << file1 << '\n';
|
||||
if(!file2.empty()) {
|
||||
std::cout << "File 2 = " << file2 << '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("Prefix command app");
|
||||
app.prefix_command(CLI::PrefixCommandMode::On);
|
||||
|
||||
std::vector<int> vals;
|
||||
app.add_option("--vals,-v", vals)->expected(-1);
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::vector<std::string> more_comms = app.remaining();
|
||||
|
||||
std::cout << "Prefix";
|
||||
for(int v : vals)
|
||||
std::cout << ": " << v << " ";
|
||||
|
||||
std::cout << '\n' << "Remaining commands: ";
|
||||
|
||||
for(const auto &com : more_comms)
|
||||
std::cout << com << " ";
|
||||
std::cout << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app{"App to demonstrate exclusionary option groups."};
|
||||
|
||||
std::vector<int> range;
|
||||
app.add_option("--range,-R", range, "A range")->expected(-2);
|
||||
|
||||
auto *ogroup = app.add_option_group("min_max_step", "set the min max and step");
|
||||
int min{0}, max{0}, step{1};
|
||||
ogroup->add_option("--min,-m", min, "The minimum")->required();
|
||||
ogroup->add_option("--max,-M", max, "The maximum")->required();
|
||||
ogroup->add_option("--step,-s", step, "The step")->capture_default_str();
|
||||
|
||||
app.require_option(1);
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
if(!range.empty()) {
|
||||
if(range.size() == 2) {
|
||||
min = range[0];
|
||||
max = range[1];
|
||||
}
|
||||
if(range.size() >= 3) {
|
||||
step = range[0];
|
||||
min = range[1];
|
||||
max = range[2];
|
||||
}
|
||||
}
|
||||
std::cout << "range is [" << min << ':' << step << ':' << max << "]\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// This example shows the usage of the retired and deprecated option helper methods
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("example for retired/deprecated options");
|
||||
std::vector<int> x;
|
||||
auto *opt1 = app.add_option("--retired_option2", x);
|
||||
|
||||
std::pair<int, int> y;
|
||||
auto *opt2 = app.add_option("--deprecate", y);
|
||||
|
||||
app.add_option("--not_deprecated", x);
|
||||
|
||||
// specify that a non-existing option is retired
|
||||
CLI::retire_option(app, "--retired_option");
|
||||
|
||||
// specify that an existing option is retired and non-functional: this will replace the option with another that
|
||||
// behaves the same but does nothing
|
||||
CLI::retire_option(app, opt1);
|
||||
|
||||
// deprecate an existing option and specify the recommended replacement
|
||||
CLI::deprecate_option(opt2, "--not_deprecated");
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
if(!x.empty()) {
|
||||
std::cout << "Retired option example: got --not_deprecated values:";
|
||||
for(auto &xval : x) {
|
||||
std::cout << xval << " ";
|
||||
}
|
||||
std::cout << '\n';
|
||||
} else if(app.count_all() == 1) {
|
||||
std::cout << "Retired option example: no arguments received\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("load shapes");
|
||||
|
||||
app.set_help_all_flag("--help-all");
|
||||
auto *circle = app.add_subcommand("circle", "draw a circle")->immediate_callback();
|
||||
double radius{0.0};
|
||||
int circle_counter{0};
|
||||
circle->callback([&radius, &circle_counter] {
|
||||
++circle_counter;
|
||||
std::cout << "circle" << circle_counter << " with radius " << radius << '\n';
|
||||
});
|
||||
|
||||
circle->add_option("radius", radius, "the radius of the circle")->required();
|
||||
|
||||
auto *rect = app.add_subcommand("rectangle", "draw a rectangle")->immediate_callback();
|
||||
double edge1{0.0};
|
||||
double edge2{0.0};
|
||||
int rect_counter{0};
|
||||
rect->callback([&edge1, &edge2, &rect_counter] {
|
||||
++rect_counter;
|
||||
if(edge2 == 0) {
|
||||
edge2 = edge1;
|
||||
}
|
||||
std::cout << "rectangle" << rect_counter << " with edges [" << edge1 << ',' << edge2 << "]\n";
|
||||
edge2 = 0;
|
||||
});
|
||||
|
||||
rect->add_option("edge1", edge1, "the first edge length of the rectangle")->required();
|
||||
rect->add_option("edge2", edge2, "the second edge length of the rectangle");
|
||||
|
||||
auto *tri = app.add_subcommand("triangle", "draw a rectangle")->immediate_callback();
|
||||
std::vector<double> sides;
|
||||
int tri_counter = 0;
|
||||
tri->callback([&sides, &tri_counter] {
|
||||
++tri_counter;
|
||||
|
||||
std::cout << "triangle" << tri_counter << " with sides [" << CLI::detail::join(sides) << "]\n";
|
||||
});
|
||||
|
||||
tri->add_option("sides", sides, "the side lengths of the triangle");
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("K3Pi goofit fitter");
|
||||
// add version output
|
||||
app.set_version_flag("--version", std::string(CLI11_VERSION));
|
||||
std::string file;
|
||||
CLI::Option *opt = app.add_option("-f,--file,file", file, "File name");
|
||||
|
||||
int count{0};
|
||||
CLI::Option *copt = app.add_option("-c,--count", count, "Counter");
|
||||
|
||||
int v{0};
|
||||
CLI::Option *flag = app.add_flag("--flag", v, "Some flag that can be passed multiple times");
|
||||
|
||||
double value{0.0}; // = 3.14;
|
||||
app.add_option("-d,--double", value, "Some Value");
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::cout << "Working on file: " << file << ", direct count: " << app.count("--file")
|
||||
<< ", opt count: " << opt->count() << '\n';
|
||||
std::cout << "Working on count: " << count << ", direct count: " << app.count("--count")
|
||||
<< ", opt count: " << copt->count() << '\n';
|
||||
std::cout << "Received flag: " << v << " (" << flag->count() << ") times\n";
|
||||
std::cout << "Some value: " << value << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
CLI::App cli_global{"Demo app"};
|
||||
auto &cli_sub = *cli_global.add_subcommand("sub", "Some subcommand");
|
||||
std::string sub_arg;
|
||||
cli_sub.add_option("sub_arg", sub_arg, "Argument for subcommand")->required();
|
||||
CLI11_PARSE(cli_global, argc, argv);
|
||||
if(cli_sub) {
|
||||
std::cout << "Got: " << sub_arg << '\n';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
add_cli_exe(subcommand_main subcommand_main.cpp subcommand_a.cpp subcommand_a.hpp)
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "subcommand_a.hpp"
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
/// Set up a subcommand and capture a shared_ptr to a struct that holds all its options.
|
||||
/// The variables of the struct are bound to the CLI options.
|
||||
/// We use a shared ptr so that the addresses of the variables remain for binding,
|
||||
/// You could return the shared pointer if you wanted to access the values in main.
|
||||
void setup_subcommand_a(CLI::App &app) {
|
||||
// Create the option and subcommand objects.
|
||||
auto opt = std::make_shared<SubcommandAOptions>();
|
||||
auto *sub = app.add_subcommand("subcommand_a", "performs subcommand a");
|
||||
|
||||
// Add options to sub, binding them to opt.
|
||||
sub->add_option("-f,--file", opt->file, "File name")->required();
|
||||
sub->add_flag("--with-foo", opt->with_foo, "Counter");
|
||||
|
||||
// Set the run function as callback to be called when this subcommand is issued.
|
||||
sub->callback([opt]() { run_subcommand_a(*opt); });
|
||||
}
|
||||
|
||||
/// The function that runs our code.
|
||||
/// This could also simply be in the callback lambda itself,
|
||||
/// but having a separate function is cleaner.
|
||||
void run_subcommand_a(SubcommandAOptions const &opt) {
|
||||
// Do stuff...
|
||||
std::cout << "Working on file: " << opt.file << '\n';
|
||||
if(opt.with_foo) {
|
||||
std::cout << "Using foo!" << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <string>
|
||||
|
||||
/// Collection of all options of Subcommand A.
|
||||
struct SubcommandAOptions {
|
||||
std::string file;
|
||||
bool with_foo;
|
||||
};
|
||||
|
||||
// We could manually make a few variables and use shared pointers for each; this
|
||||
// is just done this way to be nicely organized
|
||||
|
||||
// Function declarations.
|
||||
void setup_subcommand_a(CLI::App &app);
|
||||
void run_subcommand_a(SubcommandAOptions const &opt);
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "subcommand_a.hpp"
|
||||
#include <CLI/CLI.hpp>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::App app{"..."};
|
||||
|
||||
// Call the setup functions for the subcommands.
|
||||
// They are kept alive by a shared pointer in the
|
||||
// lambda function held by CLI11
|
||||
setup_subcommand_a(app);
|
||||
|
||||
// Make sure we get at least one subcommand
|
||||
app.require_subcommand();
|
||||
|
||||
// More setup if needed, i.e., other subcommands etc.
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <CLI/Timer.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::AutoTimer give_me_a_name("This is a timer");
|
||||
|
||||
CLI::App app("K3Pi goofit fitter");
|
||||
|
||||
CLI::App_p impOpt = std::make_shared<CLI::App>("Important");
|
||||
std::string file;
|
||||
CLI::Option *opt = impOpt->add_option("-f,--file,file", file, "File name")->required();
|
||||
|
||||
int count{0};
|
||||
CLI::Option *copt = impOpt->add_flag("-c,--count", count, "Counter")->required();
|
||||
|
||||
CLI::App_p otherOpt = std::make_shared<CLI::App>("Other");
|
||||
double value{0.0}; // = 3.14;
|
||||
otherOpt->add_option("-d,--double", value, "Some Value");
|
||||
|
||||
// add the subapps to the main one
|
||||
app.add_subcommand(impOpt);
|
||||
app.add_subcommand(otherOpt);
|
||||
|
||||
try {
|
||||
app.parse(argc, argv);
|
||||
} catch(const CLI::ParseError &e) {
|
||||
return app.exit(e);
|
||||
}
|
||||
|
||||
std::cout << "Working on file: " << file << ", direct count: " << impOpt->count("--file")
|
||||
<< ", opt count: " << opt->count() << '\n';
|
||||
std::cout << "Working on count: " << count << ", direct count: " << impOpt->count("--count")
|
||||
<< ", opt count: " << copt->count() << '\n';
|
||||
std::cout << "Some value: " << value << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("K3Pi goofit fitter");
|
||||
app.set_help_all_flag("--help-all", "Expand all help");
|
||||
app.add_flag("--random", "Some random flag");
|
||||
CLI::App *start = app.add_subcommand("start", "A great subcommand");
|
||||
CLI::App *stop = app.add_subcommand("stop", "Do you really want to stop?");
|
||||
app.require_subcommand(); // 1 or more
|
||||
|
||||
std::string file;
|
||||
start->add_option("-f,--file", file, "File name");
|
||||
|
||||
CLI::Option *s = stop->add_flag("-c,--count", "Counter");
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::cout << "Working on --file from start: " << file << '\n';
|
||||
std::cout << "Working on --count from stop: " << s->count() << ", direct count: " << stop->count("--count") << '\n';
|
||||
std::cout << "Count of --random flag: " << app.count("--random") << '\n';
|
||||
for(auto *subcom : app.get_subcommands())
|
||||
std::cout << "Subcommand: " << subcom->get_name() << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Code modified from https://github.com/CLIUtils/CLI11/issues/559
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
|
||||
int value{0};
|
||||
CLI::App app{"Test App"};
|
||||
app.add_option("-v", value, "value");
|
||||
|
||||
auto *subcom = app.add_subcommand("sub", "")->prefix_command();
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::cout << "value =" << value << '\n';
|
||||
std::cout << "after Args:";
|
||||
for(const auto &aarg : subcom->remaining()) {
|
||||
std::cout << aarg << " ";
|
||||
}
|
||||
std::cout << '\n';
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
CLI::App app("Validator checker");
|
||||
|
||||
std::string file;
|
||||
app.add_option("-f,--file,file", file, "File name")->check(CLI::ExistingFile);
|
||||
|
||||
int count{0};
|
||||
app.add_option("-v,--value", count, "Value in range")->check(CLI::Range(3, 6));
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::cout << "Try printing help or failing the validator" << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user