mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-05-05 14:43:52 +00:00
add some reduction methods to the options on the fuzz tests (#930)
This adds a round trip test for config file generation to the fuzzer. (the next step after this PR will be a fuzzer that verifies that the round trip actually matches the results. This change ended up requiring quite a few minor changes to fix the ambiguities between the config file generation and config file reader. 1). There was a number of potential conflicts between positional names and regular option names that could be triggered in config files, this required a number of additional checks on the positional naming to ensure no conflicts. 2). flag options with disable flag override can produce output results that are not valid by themselves, resolving this required flag input to be able to handle an array and output the original value set of results. 3). strings with non-printable characters could cause all sorts of chaos in the config files. This was resolved by generating a binary string conversion format and handling multiline comments and characters, and handling escaped characters. Note; I think a better solution is to move to fully supporting string formatting and escaping along with the binary strings from TOML now that TOML 1.0 is finalized. That will not be this PR though, maybe the next one. 4). Lot of ambiguities and edge cases in the string splitter, this was reworked 5). handling of comments was not done well, especially comment characters in the name of the option which is allowed. 6). non printable characters in the option naming. This would be weird in practice but it also cause some big holes in the config file generation, so the restricted character set for option naming was expanded. (don't allow spaces or control characters). --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
3bc2739c11
commit
0f5bf21e91
18
.codacy.yml
Normal file
18
.codacy.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
engines:
|
||||||
|
rubocop:
|
||||||
|
enabled: true
|
||||||
|
duplication:
|
||||||
|
enabled: true
|
||||||
|
metrics:
|
||||||
|
enabled: true
|
||||||
|
coverage:
|
||||||
|
enabled: false
|
||||||
|
languages:
|
||||||
|
|
||||||
|
exclude_paths:
|
||||||
|
- "fuzz/**/*"
|
||||||
|
- "fuzz/*"
|
||||||
|
- "scripts/**/*"
|
||||||
|
- "scripts/*"
|
||||||
|
- "**.md"
|
@ -9,6 +9,7 @@ filter=-readability/nolint # Conflicts with clang-tidy
|
|||||||
filter=-readability/check # Catch uses CHECK(a == b) (Tests only)
|
filter=-readability/check # Catch uses CHECK(a == b) (Tests only)
|
||||||
filter=-build/namespaces # Currently using it for one test (Tests only)
|
filter=-build/namespaces # Currently using it for one test (Tests only)
|
||||||
filter=-runtime/references # Requires fundamental change of API, don't see need for this
|
filter=-runtime/references # Requires fundamental change of API, don't see need for this
|
||||||
|
filter=-runtime/string # Requires not using static const strings which makes thing really annoying
|
||||||
filter=-whitespace/blank_line # Unnecessarily strict with blank lines that otherwise help with readability
|
filter=-whitespace/blank_line # Unnecessarily strict with blank lines that otherwise help with readability
|
||||||
filter=-whitespace/indent # Requires strange 3-space indent of private/protected/public markers
|
filter=-whitespace/indent # Requires strange 3-space indent of private/protected/public markers
|
||||||
filter=-whitespace/parens,-whitespace/braces # Conflict with clang-format
|
filter=-whitespace/parens,-whitespace/braces # Conflict with clang-format
|
||||||
|
@ -206,6 +206,16 @@ str3 = """\
|
|||||||
The key is that the closing of the multiline string must be at the end of a line
|
The key is that the closing of the multiline string must be at the end of a line
|
||||||
and match the starting 3 quote sequence.
|
and match the starting 3 quote sequence.
|
||||||
|
|
||||||
|
### Binary Strings
|
||||||
|
|
||||||
|
Config files have a binary conversion capability, this is mainly to support
|
||||||
|
writing config files but can be used by user generated files as well. Strings
|
||||||
|
with the form `B"(XXXXX)"` will convert any characters inside the parenthesis
|
||||||
|
with the form \xHH to the equivalent binary value. The HH are hexadecimal
|
||||||
|
characters. Characters not in this form will be translated as given. If argument
|
||||||
|
values with unprintable characters are used to generate a config file this
|
||||||
|
binary form will be used in the output string.
|
||||||
|
|
||||||
## Multiple configuration files
|
## Multiple configuration files
|
||||||
|
|
||||||
If it is desired that multiple configuration be allowed. Use
|
If it is desired that multiple configuration be allowed. Use
|
||||||
|
@ -40,10 +40,16 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
app->parse(parseString);
|
app->parse(parseString);
|
||||||
|
|
||||||
} catch(const CLI::ParseError &e) {
|
} catch(const CLI::ParseError &e) {
|
||||||
//(app)->exit(e);
|
//(app)->exit(e);
|
||||||
// this just indicates we caught an error known by CLI
|
// this just indicates we caught an error known by CLI
|
||||||
}
|
|
||||||
|
|
||||||
return 0; // Non-zero return values are reserved for future use.
|
return 0; // Non-zero return values are reserved for future use.
|
||||||
}
|
}
|
||||||
|
// should be able to write the config to a file and read from it again
|
||||||
|
std::string configOut = app->config_to_str();
|
||||||
|
app->clear();
|
||||||
|
std::stringstream out(configOut);
|
||||||
|
app->parse_from_stream(out);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -22,6 +22,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
|||||||
auto app = fuzzdata.generateApp();
|
auto app = fuzzdata.generateApp();
|
||||||
try {
|
try {
|
||||||
app->parse_from_stream(out);
|
app->parse_from_stream(out);
|
||||||
|
// should be able to write the config to a file and read from it again
|
||||||
|
std::string configOut = app->config_to_str();
|
||||||
|
|
||||||
|
app->clear();
|
||||||
|
std::stringstream out(configOut);
|
||||||
|
app->parse_from_stream(out);
|
||||||
|
|
||||||
} catch(const CLI::ParseError &e) {
|
} catch(const CLI::ParseError &e) {
|
||||||
// (app)->exit(e);
|
// (app)->exit(e);
|
||||||
// this just indicates we caught an error known by CLI
|
// this just indicates we caught an error known by CLI
|
||||||
|
@ -68,9 +68,9 @@ std::shared_ptr<CLI::App> FuzzApp::generateApp() {
|
|||||||
auto *vgroup = fApp->add_option_group("vectors");
|
auto *vgroup = fApp->add_option_group("vectors");
|
||||||
|
|
||||||
vgroup->add_option("--vopt1", vv1);
|
vgroup->add_option("--vopt1", vv1);
|
||||||
vgroup->add_option("--vopt2", vvs);
|
vgroup->add_option("--vopt2", vvs)->inject_separator();
|
||||||
vgroup->add_option("--vopt3", vstr);
|
vgroup->add_option("--vopt3", vstr);
|
||||||
vgroup->add_option("--vopt4", vecvecd);
|
vgroup->add_option("--vopt4", vecvecd)->inject_separator();
|
||||||
|
|
||||||
fApp->add_option("--oopt1", od1);
|
fApp->add_option("--oopt1", od1);
|
||||||
fApp->add_option("--oopt2", ods);
|
fApp->add_option("--oopt2", ods);
|
||||||
@ -121,6 +121,30 @@ std::shared_ptr<CLI::App> FuzzApp::generateApp() {
|
|||||||
sub->add_option("--sdwrap", dwrap);
|
sub->add_option("--sdwrap", dwrap);
|
||||||
sub->add_option("--siwrap", iwrap);
|
sub->add_option("--siwrap", iwrap);
|
||||||
|
|
||||||
|
auto *resgroup = fApp->add_option_group("outputOrder");
|
||||||
|
|
||||||
|
resgroup->add_option("--vA", vstrA)->expected(0, 2)->multi_option_policy(CLI::MultiOptionPolicy::TakeAll);
|
||||||
|
resgroup->add_option("--vB", vstrB)->expected(0, 2)->multi_option_policy(CLI::MultiOptionPolicy::TakeLast);
|
||||||
|
resgroup->add_option("--vC", vstrC)->expected(0, 2)->multi_option_policy(CLI::MultiOptionPolicy::TakeFirst);
|
||||||
|
resgroup->add_option("--vD", vstrD)->expected(0, 2)->multi_option_policy(CLI::MultiOptionPolicy::Reverse);
|
||||||
|
resgroup->add_option("--vS", val32)->expected(0, 2)->multi_option_policy(CLI::MultiOptionPolicy::Sum);
|
||||||
|
resgroup->add_option("--vM", mergeBuffer)->expected(0, 2)->multi_option_policy(CLI::MultiOptionPolicy::Join);
|
||||||
|
resgroup->add_option("--vE", vstrE)->expected(2, 4)->delimiter(',');
|
||||||
|
|
||||||
|
auto *vldtr = fApp->add_option_group("validators");
|
||||||
|
|
||||||
|
validator_strings.resize(10);
|
||||||
|
vldtr->add_option("--vdtr1", validator_strings[0])->join()->check(CLI::PositiveNumber);
|
||||||
|
vldtr->add_option("--vdtr2", validator_strings[1])->join()->check(CLI::NonNegativeNumber);
|
||||||
|
vldtr->add_option("--vdtr3", validator_strings[2])->join()->check(CLI::NonexistentPath);
|
||||||
|
vldtr->add_option("--vdtr4", validator_strings[3])->join()->check(CLI::Range(7, 3456));
|
||||||
|
vldtr->add_option("--vdtr5", validator_strings[4])
|
||||||
|
->join()
|
||||||
|
->check(CLI::Range(std::string("aa"), std::string("zz"), "string range"));
|
||||||
|
vldtr->add_option("--vdtr6", validator_strings[5])->join()->check(CLI::TypeValidator<double>());
|
||||||
|
vldtr->add_option("--vdtr7", validator_strings[6])->join()->check(CLI::TypeValidator<bool>());
|
||||||
|
vldtr->add_option("--vdtr8", validator_strings[7])->join()->check(CLI::ValidIPV4);
|
||||||
|
vldtr->add_option("--vdtr9", validator_strings[8])->join()->transform(CLI::Bound(2, 255));
|
||||||
return fApp;
|
return fApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ class FuzzApp {
|
|||||||
|
|
||||||
std::vector<double> vv1{};
|
std::vector<double> vv1{};
|
||||||
std::vector<std::string> vstr{};
|
std::vector<std::string> vstr{};
|
||||||
|
|
||||||
std::vector<std::vector<double>> vecvecd{};
|
std::vector<std::vector<double>> vecvecd{};
|
||||||
std::vector<std::vector<std::string>> vvs{};
|
std::vector<std::vector<std::string>> vvs{};
|
||||||
std::optional<double> od1{};
|
std::optional<double> od1{};
|
||||||
@ -103,5 +104,15 @@ class FuzzApp {
|
|||||||
std::string buffer{};
|
std::string buffer{};
|
||||||
int intbuffer{0};
|
int intbuffer{0};
|
||||||
std::atomic<double> doubleAtomic{0.0};
|
std::atomic<double> doubleAtomic{0.0};
|
||||||
|
|
||||||
|
// for testing restrictions and reduction methods
|
||||||
|
std::vector<std::string> vstrA{};
|
||||||
|
std::vector<std::string> vstrB{};
|
||||||
|
std::vector<std::string> vstrC{};
|
||||||
|
std::vector<std::string> vstrD{};
|
||||||
|
std::vector<std::string> vstrE{};
|
||||||
|
std::vector<std::string> vstrF{};
|
||||||
|
std::string mergeBuffer{};
|
||||||
|
std::vector<std::string> validator_strings{};
|
||||||
};
|
};
|
||||||
} // namespace CLI
|
} // namespace CLI
|
||||||
|
@ -20,5 +20,6 @@ int main(int argc, char **argv) {
|
|||||||
(app)->exit(e);
|
(app)->exit(e);
|
||||||
// this just indicates we caught an error known by CLI
|
// this just indicates we caught an error known by CLI
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,14 @@
|
|||||||
"--siwrap"
|
"--siwrap"
|
||||||
"--svtup"
|
"--svtup"
|
||||||
"--satd"
|
"--satd"
|
||||||
|
"--vA"
|
||||||
|
"--vB"
|
||||||
|
"--vC"
|
||||||
|
"--vD"
|
||||||
|
"--vS"
|
||||||
|
"--vM"
|
||||||
|
"--vE"
|
||||||
|
"--vdtr"
|
||||||
"nflag2"
|
"nflag2"
|
||||||
"stup1"
|
"stup1"
|
||||||
"svtup"
|
"svtup"
|
||||||
@ -143,6 +151,7 @@
|
|||||||
"stup4"
|
"stup4"
|
||||||
"sdwrap"
|
"sdwrap"
|
||||||
"siwrap"
|
"siwrap"
|
||||||
|
"vdtr"
|
||||||
"svtup"
|
"svtup"
|
||||||
"satd"
|
"satd"
|
||||||
"%%"
|
"%%"
|
||||||
@ -156,3 +165,10 @@
|
|||||||
"!"
|
"!"
|
||||||
"{"
|
"{"
|
||||||
"}"
|
"}"
|
||||||
|
"vA"
|
||||||
|
"vB"
|
||||||
|
"vC"
|
||||||
|
"vD"
|
||||||
|
"vS"
|
||||||
|
"vM"
|
||||||
|
"vE"
|
||||||
|
@ -72,6 +72,7 @@
|
|||||||
"svopt4"
|
"svopt4"
|
||||||
"config"
|
"config"
|
||||||
"nflag2"
|
"nflag2"
|
||||||
|
"vdtr"
|
||||||
"--"
|
"--"
|
||||||
"fuzzer"
|
"fuzzer"
|
||||||
"t-"
|
"t-"
|
||||||
@ -82,3 +83,10 @@
|
|||||||
"dexists"
|
"dexists"
|
||||||
"fexists"
|
"fexists"
|
||||||
"fnexists"
|
"fnexists"
|
||||||
|
"vA"
|
||||||
|
"vB"
|
||||||
|
"vC"
|
||||||
|
"vD"
|
||||||
|
"vS"
|
||||||
|
"vM"
|
||||||
|
"vE"
|
||||||
|
@ -24,7 +24,10 @@ namespace CLI {
|
|||||||
// [CLI11:config_hpp:verbatim]
|
// [CLI11:config_hpp:verbatim]
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
std::string convert_arg_for_ini(const std::string &arg, char stringQuote = '"', char characterQuote = '\'');
|
std::string convert_arg_for_ini(const std::string &arg,
|
||||||
|
char stringQuote = '"',
|
||||||
|
char characterQuote = '\'',
|
||||||
|
bool disable_multi_line = false);
|
||||||
|
|
||||||
/// Comma separated join, adds quotes if needed
|
/// Comma separated join, adds quotes if needed
|
||||||
std::string ini_join(const std::vector<std::string> &args,
|
std::string ini_join(const std::vector<std::string> &args,
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
// [CLI11:public_includes:end]
|
// [CLI11:public_includes:end]
|
||||||
@ -29,7 +30,6 @@ struct ConfigItem {
|
|||||||
|
|
||||||
/// This is the name
|
/// This is the name
|
||||||
std::string name{};
|
std::string name{};
|
||||||
|
|
||||||
/// Listing of inputs
|
/// Listing of inputs
|
||||||
std::vector<std::string> inputs{};
|
std::vector<std::string> inputs{};
|
||||||
|
|
||||||
|
@ -127,6 +127,9 @@ class BadNameString : public ConstructionError {
|
|||||||
return BadNameString("Long names strings require 2 dashes " + name);
|
return BadNameString("Long names strings require 2 dashes " + name);
|
||||||
}
|
}
|
||||||
static BadNameString BadLongName(std::string name) { return BadNameString("Bad long name: " + name); }
|
static BadNameString BadLongName(std::string name) { return BadNameString("Bad long name: " + name); }
|
||||||
|
static BadNameString BadPositionalName(std::string name) {
|
||||||
|
return BadNameString("Invalid positional Name: " + name);
|
||||||
|
}
|
||||||
static BadNameString DashesOnly(std::string name) {
|
static BadNameString DashesOnly(std::string name) {
|
||||||
return BadNameString("Must have a name, not just dashes: " + name);
|
return BadNameString("Must have a name, not just dashes: " + name);
|
||||||
}
|
}
|
||||||
|
@ -550,12 +550,12 @@ class Option : public OptionBase<Option> {
|
|||||||
if(!lnames_.empty()) {
|
if(!lnames_.empty()) {
|
||||||
return lnames_[0];
|
return lnames_[0];
|
||||||
}
|
}
|
||||||
if(!pname_.empty()) {
|
|
||||||
return pname_;
|
|
||||||
}
|
|
||||||
if(!snames_.empty()) {
|
if(!snames_.empty()) {
|
||||||
return snames_[0];
|
return snames_[0];
|
||||||
}
|
}
|
||||||
|
if(!pname_.empty()) {
|
||||||
|
return pname_;
|
||||||
|
}
|
||||||
return envname_;
|
return envname_;
|
||||||
}
|
}
|
||||||
/// The number of times the option expects to be included
|
/// The number of times the option expects to be included
|
||||||
@ -578,13 +578,13 @@ class Option : public OptionBase<Option> {
|
|||||||
CLI11_NODISCARD int get_items_expected() const { return get_items_expected_min(); }
|
CLI11_NODISCARD int get_items_expected() const { return get_items_expected_min(); }
|
||||||
|
|
||||||
/// True if the argument can be given directly
|
/// True if the argument can be given directly
|
||||||
CLI11_NODISCARD bool get_positional() const { return pname_.length() > 0; }
|
CLI11_NODISCARD bool get_positional() const { return !pname_.empty(); }
|
||||||
|
|
||||||
/// True if option has at least one non-positional name
|
/// True if option has at least one non-positional name
|
||||||
CLI11_NODISCARD bool nonpositional() const { return (snames_.size() + lnames_.size()) > 0; }
|
CLI11_NODISCARD bool nonpositional() const { return (!lnames_.empty() || !snames_.empty()); }
|
||||||
|
|
||||||
/// True if option has description
|
/// True if option has description
|
||||||
CLI11_NODISCARD bool has_description() const { return description_.length() > 0; }
|
CLI11_NODISCARD bool has_description() const { return !description_.empty(); }
|
||||||
|
|
||||||
/// Get the description
|
/// Get the description
|
||||||
CLI11_NODISCARD const std::string &get_description() const { return description_; }
|
CLI11_NODISCARD const std::string &get_description() const { return description_; }
|
||||||
|
@ -140,14 +140,16 @@ CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector<s
|
|||||||
|
|
||||||
/// Verify the first character of an option
|
/// Verify the first character of an option
|
||||||
/// - is a trigger character, ! has special meaning and new lines would just be annoying to deal with
|
/// - is a trigger character, ! has special meaning and new lines would just be annoying to deal with
|
||||||
template <typename T> bool valid_first_char(T c) { return ((c != '-') && (c != '!') && (c != ' ') && c != '\n'); }
|
template <typename T> bool valid_first_char(T c) {
|
||||||
|
return ((c != '-') && (static_cast<unsigned char>(c) > 33)); // space and '!' not allowed
|
||||||
|
}
|
||||||
|
|
||||||
/// Verify following characters of an option
|
/// Verify following characters of an option
|
||||||
template <typename T> bool valid_later_char(T c) {
|
template <typename T> bool valid_later_char(T c) {
|
||||||
// = and : are value separators, { has special meaning for option defaults,
|
// = and : are value separators, { has special meaning for option defaults,
|
||||||
// and \n would just be annoying to deal with in many places allowing space here has too much potential for
|
// and control codes other than tab would just be annoying to deal with in many places allowing space here has too
|
||||||
// inadvertent entry errors and bugs
|
// much potential for inadvertent entry errors and bugs
|
||||||
return ((c != '=') && (c != ':') && (c != '{') && (c != ' ') && c != '\n');
|
return ((c != '=') && (c != ':') && (c != '{') && ((static_cast<unsigned char>(c) > 32) || c == '\t'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify an option/subcommand name
|
/// Verify an option/subcommand name
|
||||||
@ -211,8 +213,11 @@ template <typename Callable> inline std::string find_and_modify(std::string str,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Split a string '"one two" "three"' into 'one two', 'three'
|
/// Split a string '"one two" "three"' into 'one two', 'three'
|
||||||
/// Quote characters can be ` ' or "
|
/// Quote characters can be ` ' or " or bracket characters [{(< with matching to the matching bracket
|
||||||
CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter = '\0');
|
CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter = '\0', bool removeQuotes = true);
|
||||||
|
|
||||||
|
/// get the value of an environmental variable or empty string if empty
|
||||||
|
CLI11_INLINE std::string get_environment_value(const std::string &env_name);
|
||||||
|
|
||||||
/// This function detects an equal or colon followed by an escaped quote after an argument
|
/// This function detects an equal or colon followed by an escaped quote after an argument
|
||||||
/// then modifies the string to replace the equality with a space. This is needed
|
/// then modifies the string to replace the equality with a space. This is needed
|
||||||
@ -220,8 +225,27 @@ CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter =
|
|||||||
/// the return value is the offset+1 which is required by the find_and_modify function.
|
/// the return value is the offset+1 which is required by the find_and_modify function.
|
||||||
CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset);
|
CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset);
|
||||||
|
|
||||||
/// get the value of an environmental variable or empty string if empty
|
/// @brief detect if a string has escapable characters
|
||||||
CLI11_INLINE std::string get_environment_value(const std::string &env_name);
|
/// @param str the string to do the detection on
|
||||||
|
/// @return true if the string has escapable characters
|
||||||
|
CLI11_INLINE bool has_escapable_character(const std::string &str);
|
||||||
|
|
||||||
|
/// @brief escape all escapable characters
|
||||||
|
/// @param str the string to escape
|
||||||
|
/// @return a string with the escapble characters escaped with '\'
|
||||||
|
CLI11_INLINE std::string add_escaped_characters(const std::string &str);
|
||||||
|
|
||||||
|
/// @brief replace the escaped characters with their equivalent
|
||||||
|
CLI11_INLINE std::string remove_escaped_characters(const std::string &str);
|
||||||
|
|
||||||
|
/// generate a string with all non printable characters escaped to hex codes
|
||||||
|
CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape);
|
||||||
|
|
||||||
|
CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string);
|
||||||
|
|
||||||
|
/// extract an escaped binary_string
|
||||||
|
CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string);
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
// [CLI11:string_tools_hpp:end]
|
// [CLI11:string_tools_hpp:end]
|
||||||
|
@ -163,6 +163,32 @@ CLI11_INLINE Option *App::add_option(std::string option_name,
|
|||||||
|
|
||||||
if(std::find_if(std::begin(options_), std::end(options_), [&myopt](const Option_p &v) { return *v == myopt; }) ==
|
if(std::find_if(std::begin(options_), std::end(options_), [&myopt](const Option_p &v) { return *v == myopt; }) ==
|
||||||
std::end(options_)) {
|
std::end(options_)) {
|
||||||
|
if(myopt.lnames_.empty() && myopt.snames_.empty()) {
|
||||||
|
// if the option is positional only there is additional potential for ambiguities in config files and needs
|
||||||
|
// to be checked
|
||||||
|
std::string test_name = "--" + myopt.get_single_name();
|
||||||
|
if(test_name.size() == 3) {
|
||||||
|
test_name.erase(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *op = get_option_no_throw(test_name);
|
||||||
|
if(op != nullptr) {
|
||||||
|
throw(OptionAlreadyAdded("added option positional name matches existing option: " + test_name));
|
||||||
|
}
|
||||||
|
} else if(parent_ != nullptr) {
|
||||||
|
for(auto &ln : myopt.lnames_) {
|
||||||
|
auto *op = parent_->get_option_no_throw(ln);
|
||||||
|
if(op != nullptr) {
|
||||||
|
throw(OptionAlreadyAdded("added option matches existing positional option: " + ln));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(auto &sn : myopt.snames_) {
|
||||||
|
auto *op = parent_->get_option_no_throw(sn);
|
||||||
|
if(op != nullptr) {
|
||||||
|
throw(OptionAlreadyAdded("added option matches existing positional option: " + sn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
options_.emplace_back();
|
options_.emplace_back();
|
||||||
Option_p &option = options_.back();
|
Option_p &option = options_.back();
|
||||||
option.reset(new Option(option_name, option_description, option_callback, this));
|
option.reset(new Option(option_name, option_description, option_callback, this));
|
||||||
@ -371,13 +397,14 @@ CLI11_INLINE bool App::remove_option(Option *opt) {
|
|||||||
CLI11_INLINE App *App::add_subcommand(std::string subcommand_name, std::string subcommand_description) {
|
CLI11_INLINE App *App::add_subcommand(std::string subcommand_name, std::string subcommand_description) {
|
||||||
if(!subcommand_name.empty() && !detail::valid_name_string(subcommand_name)) {
|
if(!subcommand_name.empty() && !detail::valid_name_string(subcommand_name)) {
|
||||||
if(!detail::valid_first_char(subcommand_name[0])) {
|
if(!detail::valid_first_char(subcommand_name[0])) {
|
||||||
throw IncorrectConstruction("Subcommand name starts with invalid character, '!' and '-' are not allowed");
|
throw IncorrectConstruction(
|
||||||
|
"Subcommand name starts with invalid character, '!' and '-' and control characters");
|
||||||
}
|
}
|
||||||
for(auto c : subcommand_name) {
|
for(auto c : subcommand_name) {
|
||||||
if(!detail::valid_later_char(c)) {
|
if(!detail::valid_later_char(c)) {
|
||||||
throw IncorrectConstruction(std::string("Subcommand name contains invalid character ('") + c +
|
throw IncorrectConstruction(std::string("Subcommand name contains invalid character ('") + c +
|
||||||
"'), all characters are allowed except"
|
"'), all characters are allowed except"
|
||||||
"'=',':','{','}', and ' '");
|
"'=',':','{','}', ' ', and control characters");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -553,7 +580,6 @@ CLI11_INLINE void App::parse(std::string commandline, bool program_name_included
|
|||||||
// remove all empty strings
|
// remove all empty strings
|
||||||
args.erase(std::remove(args.begin(), args.end(), std::string{}), args.end());
|
args.erase(std::remove(args.begin(), args.end(), std::string{}), args.end());
|
||||||
std::reverse(args.begin(), args.end());
|
std::reverse(args.begin(), args.end());
|
||||||
|
|
||||||
parse(std::move(args));
|
parse(std::move(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -723,7 +749,8 @@ CLI11_NODISCARD CLI11_INLINE std::string App::help(std::string prev, AppFormatMo
|
|||||||
CLI11_NODISCARD CLI11_INLINE std::string App::version() const {
|
CLI11_NODISCARD CLI11_INLINE std::string App::version() const {
|
||||||
std::string val;
|
std::string val;
|
||||||
if(version_ptr_ != nullptr) {
|
if(version_ptr_ != nullptr) {
|
||||||
auto rv = version_ptr_->results();
|
// copy the results for reuse later
|
||||||
|
results_t rv = version_ptr_->results();
|
||||||
version_ptr_->clear();
|
version_ptr_->clear();
|
||||||
version_ptr_->add_result("true");
|
version_ptr_->add_result("true");
|
||||||
try {
|
try {
|
||||||
@ -1395,12 +1422,11 @@ CLI11_INLINE void App::_parse_config(const std::vector<ConfigItem> &args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t level) {
|
CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t level) {
|
||||||
|
|
||||||
if(level < item.parents.size()) {
|
if(level < item.parents.size()) {
|
||||||
try {
|
try {
|
||||||
auto *subcom = get_subcommand(item.parents.at(level));
|
auto *subcom = get_subcommand(item.parents.at(level));
|
||||||
auto result = subcom->_parse_single_config(item, level + 1);
|
return subcom->_parse_single_config(item, level + 1);
|
||||||
|
|
||||||
return result;
|
|
||||||
} catch(const OptionNotFound &) {
|
} catch(const OptionNotFound &) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1430,10 +1456,11 @@ CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t
|
|||||||
if(item.name.size() == 1) {
|
if(item.name.size() == 1) {
|
||||||
op = get_option_no_throw("-" + item.name);
|
op = get_option_no_throw("-" + item.name);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(op == nullptr) {
|
if(op == nullptr) {
|
||||||
op = get_option_no_throw(item.name);
|
op = get_option_no_throw(item.name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(op == nullptr) {
|
if(op == nullptr) {
|
||||||
// If the option was not present
|
// If the option was not present
|
||||||
if(get_allow_config_extras() == config_extras_mode::capture)
|
if(get_allow_config_extras() == config_extras_mode::capture)
|
||||||
@ -1475,12 +1502,40 @@ CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t
|
|||||||
op->add_result(res);
|
op->add_result(res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(static_cast<int>(item.inputs.size()) > op->get_items_expected_max()) {
|
if(static_cast<int>(item.inputs.size()) > op->get_items_expected_max() &&
|
||||||
|
op->get_multi_option_policy() != MultiOptionPolicy::TakeAll) {
|
||||||
if(op->get_items_expected_max() > 1) {
|
if(op->get_items_expected_max() > 1) {
|
||||||
throw ArgumentMismatch::AtMost(item.fullname(), op->get_items_expected_max(), item.inputs.size());
|
throw ArgumentMismatch::AtMost(item.fullname(), op->get_items_expected_max(), item.inputs.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!op->get_disable_flag_override()) {
|
||||||
throw ConversionError::TooManyInputsFlag(item.fullname());
|
throw ConversionError::TooManyInputsFlag(item.fullname());
|
||||||
}
|
}
|
||||||
|
// if the disable flag override is set then we must have the flag values match a known flag value
|
||||||
|
// this is true regardless of the output value, so an array input is possible and must be accounted for
|
||||||
|
for(const auto &res : item.inputs) {
|
||||||
|
bool valid_value{false};
|
||||||
|
if(op->default_flag_values_.empty()) {
|
||||||
|
if(res == "true" || res == "false" || res == "1" || res == "0") {
|
||||||
|
valid_value = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(const auto &valid_res : op->default_flag_values_) {
|
||||||
|
if(valid_res.second == res) {
|
||||||
|
valid_value = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(valid_value) {
|
||||||
|
op->add_result(res);
|
||||||
|
} else {
|
||||||
|
throw InvalidError("invalid flag argument given");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
op->add_result(item.inputs);
|
op->add_result(item.inputs);
|
||||||
op->run_callback();
|
op->run_callback();
|
||||||
|
@ -19,11 +19,18 @@
|
|||||||
namespace CLI {
|
namespace CLI {
|
||||||
// [CLI11:config_inl_hpp:verbatim]
|
// [CLI11:config_inl_hpp:verbatim]
|
||||||
|
|
||||||
static constexpr auto tquote = R"(""")";
|
static constexpr auto triple_quote = R"(""")";
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
CLI11_INLINE std::string convert_arg_for_ini(const std::string &arg, char stringQuote, char characterQuote) {
|
CLI11_INLINE bool is_printable(const std::string &test_string) {
|
||||||
|
return std::all_of(test_string.begin(), test_string.end(), [](char x) {
|
||||||
|
return (isprint(static_cast<unsigned char>(x)) != 0 || x == '\n');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string
|
||||||
|
convert_arg_for_ini(const std::string &arg, char stringQuote, char characterQuote, bool disable_multi_line) {
|
||||||
if(arg.empty()) {
|
if(arg.empty()) {
|
||||||
return std::string(2, stringQuote);
|
return std::string(2, stringQuote);
|
||||||
}
|
}
|
||||||
@ -36,11 +43,22 @@ CLI11_INLINE std::string convert_arg_for_ini(const std::string &arg, char string
|
|||||||
using CLI::detail::lexical_cast;
|
using CLI::detail::lexical_cast;
|
||||||
double val = 0.0;
|
double val = 0.0;
|
||||||
if(lexical_cast(arg, val)) {
|
if(lexical_cast(arg, val)) {
|
||||||
|
if(arg.find_first_not_of("0123456789.-+eE") == std::string::npos) {
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// just quote a single non numeric character
|
// just quote a single non numeric character
|
||||||
if(arg.size() == 1) {
|
if(arg.size() == 1) {
|
||||||
|
if(isprint(static_cast<unsigned char>(arg.front())) == 0) {
|
||||||
|
return binary_escape_string(arg);
|
||||||
|
}
|
||||||
|
if(arg == "\\") {
|
||||||
|
return std::string(1, stringQuote) + "\\\\" + stringQuote;
|
||||||
|
}
|
||||||
|
if(arg == "'") {
|
||||||
|
return std::string(1, stringQuote) + "'" + stringQuote;
|
||||||
|
}
|
||||||
return std::string(1, characterQuote) + arg + characterQuote;
|
return std::string(1, characterQuote) + arg + characterQuote;
|
||||||
}
|
}
|
||||||
// handle hex, binary or octal arguments
|
// handle hex, binary or octal arguments
|
||||||
@ -61,14 +79,20 @@ CLI11_INLINE std::string convert_arg_for_ini(const std::string &arg, char string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(!is_printable(arg)) {
|
||||||
|
return binary_escape_string(arg);
|
||||||
|
}
|
||||||
if(arg.find_first_of('\n') != std::string::npos) {
|
if(arg.find_first_of('\n') != std::string::npos) {
|
||||||
return std::string(tquote) + arg + tquote;
|
if(disable_multi_line) {
|
||||||
|
return binary_escape_string(arg);
|
||||||
|
}
|
||||||
|
return std::string(triple_quote) + arg + triple_quote;
|
||||||
|
}
|
||||||
|
if(detail::has_escapable_character(arg)) {
|
||||||
|
return std::string(1, stringQuote) + detail::add_escaped_characters(arg) + stringQuote;
|
||||||
}
|
}
|
||||||
if(arg.find_first_of(stringQuote) == std::string::npos) {
|
|
||||||
return std::string(1, stringQuote) + arg + stringQuote;
|
return std::string(1, stringQuote) + arg + stringQuote;
|
||||||
}
|
}
|
||||||
return characterQuote + arg + characterQuote;
|
|
||||||
}
|
|
||||||
|
|
||||||
CLI11_INLINE std::string ini_join(const std::vector<std::string> &args,
|
CLI11_INLINE std::string ini_join(const std::vector<std::string> &args,
|
||||||
char sepChar,
|
char sepChar,
|
||||||
@ -76,9 +100,11 @@ CLI11_INLINE std::string ini_join(const std::vector<std::string> &args,
|
|||||||
char arrayEnd,
|
char arrayEnd,
|
||||||
char stringQuote,
|
char stringQuote,
|
||||||
char characterQuote) {
|
char characterQuote) {
|
||||||
|
bool disable_multi_line{false};
|
||||||
std::string joined;
|
std::string joined;
|
||||||
if(args.size() > 1 && arrayStart != '\0') {
|
if(args.size() > 1 && arrayStart != '\0') {
|
||||||
joined.push_back(arrayStart);
|
joined.push_back(arrayStart);
|
||||||
|
disable_multi_line = true;
|
||||||
}
|
}
|
||||||
std::size_t start = 0;
|
std::size_t start = 0;
|
||||||
for(const auto &arg : args) {
|
for(const auto &arg : args) {
|
||||||
@ -88,7 +114,7 @@ CLI11_INLINE std::string ini_join(const std::vector<std::string> &args,
|
|||||||
joined.push_back(' ');
|
joined.push_back(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
joined.append(convert_arg_for_ini(arg, stringQuote, characterQuote));
|
joined.append(convert_arg_for_ini(arg, stringQuote, characterQuote, disable_multi_line));
|
||||||
}
|
}
|
||||||
if(args.size() > 1 && arrayEnd != '\0') {
|
if(args.size() > 1 && arrayEnd != '\0') {
|
||||||
joined.push_back(arrayEnd);
|
joined.push_back(arrayEnd);
|
||||||
@ -170,6 +196,7 @@ checkParentSegments(std::vector<ConfigItem> &output, const std::string ¤tS
|
|||||||
output.back().name = "++";
|
output.back().name = "++";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief checks if a string represents a multiline comment
|
||||||
CLI11_INLINE bool hasMLString(std::string const &fullString, char check) {
|
CLI11_INLINE bool hasMLString(std::string const &fullString, char check) {
|
||||||
if(fullString.length() < 3) {
|
if(fullString.length() < 3) {
|
||||||
return false;
|
return false;
|
||||||
@ -190,6 +217,7 @@ inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) cons
|
|||||||
bool inSection{false};
|
bool inSection{false};
|
||||||
bool inMLineComment{false};
|
bool inMLineComment{false};
|
||||||
bool inMLineValue{false};
|
bool inMLineValue{false};
|
||||||
|
|
||||||
char aStart = (isINIArray) ? '[' : arrayStart;
|
char aStart = (isINIArray) ? '[' : arrayStart;
|
||||||
char aEnd = (isINIArray) ? ']' : arrayEnd;
|
char aEnd = (isINIArray) ? ']' : arrayEnd;
|
||||||
char aSep = (isINIArray && arraySeparator == ' ') ? ',' : arraySeparator;
|
char aSep = (isINIArray && arraySeparator == ' ') ? ',' : arraySeparator;
|
||||||
@ -198,14 +226,14 @@ inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) cons
|
|||||||
while(getline(input, buffer)) {
|
while(getline(input, buffer)) {
|
||||||
std::vector<std::string> items_buffer;
|
std::vector<std::string> items_buffer;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
bool literalName{false};
|
||||||
line = detail::trim_copy(buffer);
|
line = detail::trim_copy(buffer);
|
||||||
std::size_t len = line.length();
|
std::size_t len = line.length();
|
||||||
// lines have to be at least 3 characters to have any meaning to CLI just skip the rest
|
// lines have to be at least 3 characters to have any meaning to CLI just skip the rest
|
||||||
if(len < 3) {
|
if(len < 3) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(line.compare(0, 3, tquote) == 0 || line.compare(0, 3, "'''") == 0) {
|
if(line.compare(0, 3, triple_quote) == 0 || line.compare(0, 3, "'''") == 0) {
|
||||||
inMLineComment = true;
|
inMLineComment = true;
|
||||||
auto cchar = line.front();
|
auto cchar = line.front();
|
||||||
while(inMLineComment) {
|
while(inMLineComment) {
|
||||||
@ -249,20 +277,32 @@ inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) cons
|
|||||||
|
|
||||||
// comment lines
|
// comment lines
|
||||||
if(line.front() == ';' || line.front() == '#' || line.front() == commentChar) {
|
if(line.front() == ';' || line.front() == '#' || line.front() == commentChar) {
|
||||||
|
if(line.compare(2, 13, "cli11:literal") == 0) {
|
||||||
|
literalName = true;
|
||||||
|
getline(input, buffer);
|
||||||
|
line = detail::trim_copy(buffer);
|
||||||
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find = in string, split and recombine
|
// Find = in string, split and recombine
|
||||||
auto delimiter_pos = line.find_first_of(valueDelimiter);
|
auto delimiter_pos = line.find_first_of(valueDelimiter, 1);
|
||||||
auto comment_pos = line.find_first_of(commentChar);
|
auto comment_pos = (literalName) ? std::string::npos : line.find_first_of(commentChar);
|
||||||
|
|
||||||
if(comment_pos < delimiter_pos) {
|
if(comment_pos < delimiter_pos) {
|
||||||
delimiter_pos = std::string::npos;
|
delimiter_pos = std::string::npos;
|
||||||
}
|
}
|
||||||
if(delimiter_pos != std::string::npos) {
|
if(delimiter_pos != std::string::npos) {
|
||||||
|
|
||||||
name = detail::trim_copy(line.substr(0, delimiter_pos));
|
name = detail::trim_copy(line.substr(0, delimiter_pos));
|
||||||
std::string item = detail::trim_copy(line.substr(delimiter_pos + 1, comment_pos - delimiter_pos - 1));
|
std::string item = detail::trim_copy(line.substr(delimiter_pos + 1, std::string::npos));
|
||||||
if(item.compare(0, 3, "'''") == 0 || item.compare(0, 3, tquote) == 0) {
|
bool mlquote = (item.compare(0, 3, "'''") == 0 || item.compare(0, 3, triple_quote) == 0);
|
||||||
|
if(!mlquote && comment_pos != std::string::npos && !literalName) {
|
||||||
|
auto citems = detail::split_up(item, commentChar, false);
|
||||||
|
item = detail::trim_copy(citems.front());
|
||||||
|
}
|
||||||
|
if(mlquote) {
|
||||||
// mutliline string
|
// mutliline string
|
||||||
auto keyChar = item.front();
|
auto keyChar = item.front();
|
||||||
item = buffer.substr(delimiter_pos + 1, std::string::npos);
|
item = buffer.substr(delimiter_pos + 1, std::string::npos);
|
||||||
@ -318,11 +358,11 @@ inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) cons
|
|||||||
detail::trim(multiline);
|
detail::trim(multiline);
|
||||||
item += multiline;
|
item += multiline;
|
||||||
}
|
}
|
||||||
items_buffer = detail::split_up(item.substr(1, item.length() - 2), aSep);
|
items_buffer = detail::split_up(item.substr(1, item.length() - 2), aSep, false);
|
||||||
} else if((isDefaultArray || isINIArray) && item.find_first_of(aSep) != std::string::npos) {
|
} else if((isDefaultArray || isINIArray) && item.find_first_of(aSep) != std::string::npos) {
|
||||||
items_buffer = detail::split_up(item, aSep);
|
items_buffer = detail::split_up(item, aSep, false);
|
||||||
} else if((isDefaultArray || isINIArray) && item.find_first_of(' ') != std::string::npos) {
|
} else if((isDefaultArray || isINIArray) && item.find_first_of(' ') != std::string::npos) {
|
||||||
items_buffer = detail::split_up(item);
|
items_buffer = detail::split_up(item, '\0', false);
|
||||||
} else {
|
} else {
|
||||||
items_buffer = {item};
|
items_buffer = {item};
|
||||||
}
|
}
|
||||||
@ -331,14 +371,24 @@ inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) cons
|
|||||||
items_buffer = {"true"};
|
items_buffer = {"true"};
|
||||||
}
|
}
|
||||||
if(name.find(parentSeparatorChar) == std::string::npos) {
|
if(name.find(parentSeparatorChar) == std::string::npos) {
|
||||||
|
if(!literalName) {
|
||||||
detail::remove_quotes(name);
|
detail::remove_quotes(name);
|
||||||
}
|
}
|
||||||
// clean up quotes on the items
|
}
|
||||||
|
// clean up quotes on the items and check for escaped strings
|
||||||
for(auto &it : items_buffer) {
|
for(auto &it : items_buffer) {
|
||||||
detail::remove_quotes(it);
|
detail::remove_quotes(it);
|
||||||
|
if(detail::is_binary_escaped_string(it)) {
|
||||||
|
it = detail::extract_binary_string(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<std::string> parents;
|
||||||
|
if(literalName) {
|
||||||
|
std::string noname{};
|
||||||
|
parents = detail::generate_parents(currentSection, noname, parentSeparatorChar);
|
||||||
|
} else {
|
||||||
|
parents = detail::generate_parents(currentSection, name, parentSeparatorChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> parents = detail::generate_parents(currentSection, name, parentSeparatorChar);
|
|
||||||
if(parents.size() > maximumLayers) {
|
if(parents.size() > maximumLayers) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -382,6 +432,10 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description,
|
|||||||
commentLead.push_back(commentChar);
|
commentLead.push_back(commentChar);
|
||||||
commentLead.push_back(' ');
|
commentLead.push_back(' ');
|
||||||
|
|
||||||
|
std::string commentTest = "#;";
|
||||||
|
commentTest.push_back(commentChar);
|
||||||
|
commentTest.push_back(parentSeparatorChar);
|
||||||
|
|
||||||
std::vector<std::string> groups = app->get_groups();
|
std::vector<std::string> groups = app->get_groups();
|
||||||
bool defaultUsed = false;
|
bool defaultUsed = false;
|
||||||
groups.insert(groups.begin(), std::string("Options"));
|
groups.insert(groups.begin(), std::string("Options"));
|
||||||
@ -408,12 +462,15 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string name = prefix + opt->get_single_name();
|
std::string name = prefix + opt->get_single_name();
|
||||||
|
if(name == prefix) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
std::string value = detail::ini_join(
|
std::string value = detail::ini_join(
|
||||||
opt->reduced_results(), arraySeparator, arrayStart, arrayEnd, stringQuote, characterQuote);
|
opt->reduced_results(), arraySeparator, arrayStart, arrayEnd, stringQuote, characterQuote);
|
||||||
|
|
||||||
if(value.empty() && default_also) {
|
if(value.empty() && default_also) {
|
||||||
if(!opt->get_default_str().empty()) {
|
if(!opt->get_default_str().empty()) {
|
||||||
value = detail::convert_arg_for_ini(opt->get_default_str(), stringQuote, characterQuote);
|
value = detail::convert_arg_for_ini(opt->get_default_str(), stringQuote, characterQuote, false);
|
||||||
} else if(opt->get_expected_min() == 0) {
|
} else if(opt->get_expected_min() == 0) {
|
||||||
value = "false";
|
value = "false";
|
||||||
} else if(opt->get_run_callback_for_default()) {
|
} else if(opt->get_run_callback_for_default()) {
|
||||||
@ -423,12 +480,36 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description,
|
|||||||
|
|
||||||
if(!value.empty()) {
|
if(!value.empty()) {
|
||||||
if(!opt->get_fnames().empty()) {
|
if(!opt->get_fnames().empty()) {
|
||||||
|
try {
|
||||||
value = opt->get_flag_value(name, value);
|
value = opt->get_flag_value(name, value);
|
||||||
|
} catch(const CLI::ArgumentMismatch &) {
|
||||||
|
bool valid{false};
|
||||||
|
for(const auto &test_name : opt->get_fnames()) {
|
||||||
|
try {
|
||||||
|
value = opt->get_flag_value(test_name, value);
|
||||||
|
name = test_name;
|
||||||
|
valid = true;
|
||||||
|
} catch(const CLI::ArgumentMismatch &) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!valid) {
|
||||||
|
value = detail::ini_join(
|
||||||
|
opt->results(), arraySeparator, arrayStart, arrayEnd, stringQuote, characterQuote);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(write_description && opt->has_description()) {
|
if(write_description && opt->has_description()) {
|
||||||
out << '\n';
|
out << '\n';
|
||||||
out << commentLead << detail::fix_newlines(commentLead, opt->get_description()) << '\n';
|
out << commentLead << detail::fix_newlines(commentLead, opt->get_description()) << '\n';
|
||||||
}
|
}
|
||||||
|
if(name.find_first_of(commentTest) != std::string::npos || name.compare(0, 3, triple_quote) == 0 ||
|
||||||
|
name.compare(0, 3, "'''") == 0 || (name.front() == '[' && name.back() == ']') ||
|
||||||
|
(name.front() == stringQuote && name.back() == stringQuote) ||
|
||||||
|
(name.front() == characterQuote && name.back() == characterQuote) ||
|
||||||
|
(name.front() == '`' && name.back() == '`')) {
|
||||||
|
out << commentChar << " cli11:literal\n";
|
||||||
|
}
|
||||||
out << name << valueDelimiter << value << '\n';
|
out << name << valueDelimiter << value << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,15 +518,33 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description,
|
|||||||
auto subcommands = app->get_subcommands({});
|
auto subcommands = app->get_subcommands({});
|
||||||
for(const App *subcom : subcommands) {
|
for(const App *subcom : subcommands) {
|
||||||
if(subcom->get_name().empty()) {
|
if(subcom->get_name().empty()) {
|
||||||
|
if(!default_also && (subcom->count_all() == 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if(write_description && !subcom->get_group().empty()) {
|
if(write_description && !subcom->get_group().empty()) {
|
||||||
out << '\n' << commentLead << subcom->get_group() << " Options\n";
|
out << '\n' << commentLead << subcom->get_group() << " Options\n";
|
||||||
}
|
}
|
||||||
|
/*if (!prefix.empty() || app->get_parent() == nullptr) {
|
||||||
|
out << '[' << prefix << "___"<< subcom->get_group() << "]\n";
|
||||||
|
} else {
|
||||||
|
std::string subname = app->get_name() + parentSeparatorChar + "___"+subcom->get_group();
|
||||||
|
const auto *p = app->get_parent();
|
||||||
|
while(p->get_parent() != nullptr) {
|
||||||
|
subname = p->get_name() + parentSeparatorChar +subname;
|
||||||
|
p = p->get_parent();
|
||||||
|
}
|
||||||
|
out << '[' << subname << "]\n";
|
||||||
|
}
|
||||||
|
*/
|
||||||
out << to_config(subcom, default_also, write_description, prefix);
|
out << to_config(subcom, default_also, write_description, prefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const App *subcom : subcommands) {
|
for(const App *subcom : subcommands) {
|
||||||
if(!subcom->get_name().empty()) {
|
if(!subcom->get_name().empty()) {
|
||||||
|
if(!default_also && (subcom->count_all() == 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if(subcom->get_configurable() && app->got_subcommand(subcom)) {
|
if(subcom->get_configurable() && app->got_subcommand(subcom)) {
|
||||||
if(!prefix.empty() || app->get_parent() == nullptr) {
|
if(!prefix.empty() || app->get_parent() == nullptr) {
|
||||||
out << '[' << prefix << subcom->get_name() << "]\n";
|
out << '[' << prefix << subcom->get_name() << "]\n";
|
||||||
|
@ -309,13 +309,29 @@ CLI11_INLINE void Option::run_callback() {
|
|||||||
|
|
||||||
CLI11_NODISCARD CLI11_INLINE const std::string &Option::matching_name(const Option &other) const {
|
CLI11_NODISCARD CLI11_INLINE const std::string &Option::matching_name(const Option &other) const {
|
||||||
static const std::string estring;
|
static const std::string estring;
|
||||||
for(const std::string &sname : snames_)
|
for(const std::string &sname : snames_) {
|
||||||
if(other.check_sname(sname))
|
if(other.check_sname(sname))
|
||||||
return sname;
|
return sname;
|
||||||
for(const std::string &lname : lnames_)
|
if(other.check_lname(sname))
|
||||||
|
return sname;
|
||||||
|
}
|
||||||
|
for(const std::string &lname : lnames_) {
|
||||||
if(other.check_lname(lname))
|
if(other.check_lname(lname))
|
||||||
return lname;
|
return lname;
|
||||||
|
if(lname.size() == 1) {
|
||||||
|
if(other.check_sname(lname)) {
|
||||||
|
return lname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(snames_.empty() && lnames_.empty() && !pname_.empty()) {
|
||||||
|
if(other.check_sname(pname_) || other.check_lname(pname_) || pname_ == other.pname_)
|
||||||
|
return pname_;
|
||||||
|
}
|
||||||
|
if(other.snames_.empty() && other.fnames_.empty() && !other.pname_.empty()) {
|
||||||
|
if(check_sname(other.pname_) || check_lname(other.pname_) || (pname_ == other.pname_))
|
||||||
|
return other.pname_;
|
||||||
|
}
|
||||||
if(ignore_case_ ||
|
if(ignore_case_ ||
|
||||||
ignore_underscore_) { // We need to do the inverse, in case we are ignore_case or ignore underscore
|
ignore_underscore_) { // We need to do the inverse, in case we are ignore_case or ignore underscore
|
||||||
for(const std::string &sname : other.snames_)
|
for(const std::string &sname : other.snames_)
|
||||||
@ -369,6 +385,9 @@ CLI11_NODISCARD CLI11_INLINE std::string Option::get_flag_value(const std::strin
|
|||||||
if(default_ind >= 0) {
|
if(default_ind >= 0) {
|
||||||
// We can static cast this to std::size_t because it is more than 0 in this block
|
// We can static cast this to std::size_t because it is more than 0 in this block
|
||||||
if(default_flag_values_[static_cast<std::size_t>(default_ind)].second != input_value) {
|
if(default_flag_values_[static_cast<std::size_t>(default_ind)].second != input_value) {
|
||||||
|
if(input_value == default_str_ && force_callback_) {
|
||||||
|
return input_value;
|
||||||
|
}
|
||||||
throw(ArgumentMismatch::FlagOverride(name));
|
throw(ArgumentMismatch::FlagOverride(name));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -106,7 +106,6 @@ get_names(const std::vector<std::string> &input) {
|
|||||||
std::vector<std::string> short_names;
|
std::vector<std::string> short_names;
|
||||||
std::vector<std::string> long_names;
|
std::vector<std::string> long_names;
|
||||||
std::string pos_name;
|
std::string pos_name;
|
||||||
|
|
||||||
for(std::string name : input) {
|
for(std::string name : input) {
|
||||||
if(name.length() == 0) {
|
if(name.length() == 0) {
|
||||||
continue;
|
continue;
|
||||||
@ -127,12 +126,15 @@ get_names(const std::vector<std::string> &input) {
|
|||||||
} else if(name == "-" || name == "--") {
|
} else if(name == "-" || name == "--") {
|
||||||
throw BadNameString::DashesOnly(name);
|
throw BadNameString::DashesOnly(name);
|
||||||
} else {
|
} else {
|
||||||
if(pos_name.length() > 0)
|
if(!pos_name.empty())
|
||||||
throw BadNameString::MultiPositionalNames(name);
|
throw BadNameString::MultiPositionalNames(name);
|
||||||
|
if(valid_name_string(name)) {
|
||||||
pos_name = name;
|
pos_name = name;
|
||||||
|
} else {
|
||||||
|
throw BadNameString::BadPositionalName(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_tuple(short_names, long_names, pos_name);
|
return std::make_tuple(short_names, long_names, pos_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
// [CLI11:public_includes:set]
|
// [CLI11:public_includes:set]
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
// [CLI11:public_includes:end]
|
// [CLI11:public_includes:end]
|
||||||
|
|
||||||
@ -180,9 +181,79 @@ find_member(std::string name, const std::vector<std::string> names, bool ignore_
|
|||||||
return (it != std::end(names)) ? (it - std::begin(names)) : (-1);
|
return (it != std::end(names)) ? (it - std::begin(names)) : (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter) {
|
static const std::string escapedChars("'\"`])>}\\");
|
||||||
|
static const std::string bracketChars{"'\"`[(<{"};
|
||||||
|
static const std::string matchBracketChars("'\"`])>}");
|
||||||
|
|
||||||
|
CLI11_INLINE bool has_escapable_character(const std::string &str) {
|
||||||
|
return (str.find_first_of(escapedChars) != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string add_escaped_characters(const std::string &str) {
|
||||||
|
std::string out;
|
||||||
|
out.reserve(str.size() + 4);
|
||||||
|
for(char s : str) {
|
||||||
|
if(escapedChars.find_first_of(s) != std::string::npos) {
|
||||||
|
out.push_back('\\');
|
||||||
|
}
|
||||||
|
out.push_back(s);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string remove_escaped_characters(const std::string &str) {
|
||||||
|
|
||||||
|
std::string out;
|
||||||
|
out.reserve(str.size());
|
||||||
|
for(auto loc = str.begin(); loc < str.end(); ++loc) {
|
||||||
|
if(*loc == '\\') {
|
||||||
|
if(escapedChars.find_first_of(*(loc + 1)) != std::string::npos) {
|
||||||
|
out.push_back(*(loc + 1));
|
||||||
|
++loc;
|
||||||
|
} else {
|
||||||
|
out.push_back(*loc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.push_back(*loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::pair<std::size_t, bool> close_sequence(const std::string &str, std::size_t start, char closure_char) {
|
||||||
|
std::string closures;
|
||||||
|
closures.push_back(closure_char);
|
||||||
|
auto loc = start + 1;
|
||||||
|
bool inQuote = closure_char == '"' || closure_char == '\'' || closure_char == '`';
|
||||||
|
bool hasControlSequence{false};
|
||||||
|
while(loc < str.size()) {
|
||||||
|
if(str[loc] == closures.back()) {
|
||||||
|
closures.pop_back();
|
||||||
|
if(closures.empty()) {
|
||||||
|
return {loc, hasControlSequence};
|
||||||
|
}
|
||||||
|
inQuote = false;
|
||||||
|
}
|
||||||
|
if(str[loc] == '\\') {
|
||||||
|
if(inQuote) {
|
||||||
|
hasControlSequence = true;
|
||||||
|
}
|
||||||
|
++loc;
|
||||||
|
}
|
||||||
|
if(!inQuote) {
|
||||||
|
auto bracket_loc = bracketChars.find(str[loc]);
|
||||||
|
if(bracket_loc != std::string::npos) {
|
||||||
|
closures.push_back(matchBracketChars[bracket_loc]);
|
||||||
|
inQuote = (bracket_loc <= 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++loc;
|
||||||
|
}
|
||||||
|
return {loc, hasControlSequence};
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter, bool removeQuotes) {
|
||||||
|
|
||||||
const std::string delims("\'\"`");
|
|
||||||
auto find_ws = [delimiter](char ch) {
|
auto find_ws = [delimiter](char ch) {
|
||||||
return (delimiter == '\0') ? std::isspace<char>(ch, std::locale()) : (ch == delimiter);
|
return (delimiter == '\0') ? std::isspace<char>(ch, std::locale()) : (ch == delimiter);
|
||||||
};
|
};
|
||||||
@ -190,27 +261,19 @@ CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter)
|
|||||||
|
|
||||||
std::vector<std::string> output;
|
std::vector<std::string> output;
|
||||||
bool embeddedQuote = false;
|
bool embeddedQuote = false;
|
||||||
char keyChar = ' ';
|
std::size_t adjust = removeQuotes ? 1 : 0;
|
||||||
while(!str.empty()) {
|
while(!str.empty()) {
|
||||||
if(delims.find_first_of(str[0]) != std::string::npos) {
|
if(bracketChars.find_first_of(str[0]) != std::string::npos) {
|
||||||
keyChar = str[0];
|
auto bracketLoc = bracketChars.find_first_of(str[0]);
|
||||||
auto end = str.find_first_of(keyChar, 1);
|
auto closure = close_sequence(str, 0, matchBracketChars[bracketLoc]);
|
||||||
while((end != std::string::npos) && (str[end - 1] == '\\')) { // deal with escaped quotes
|
auto end = closure.first;
|
||||||
end = str.find_first_of(keyChar, end + 1);
|
output.push_back(str.substr(adjust, end + 1 - 2 * adjust));
|
||||||
embeddedQuote = true;
|
|
||||||
}
|
|
||||||
if(end != std::string::npos) {
|
|
||||||
output.push_back(str.substr(1, end - 1));
|
|
||||||
if(end + 2 < str.size()) {
|
if(end + 2 < str.size()) {
|
||||||
str = str.substr(end + 2);
|
str = str.substr(end + 2);
|
||||||
} else {
|
} else {
|
||||||
str.clear();
|
str.clear();
|
||||||
}
|
}
|
||||||
|
embeddedQuote = embeddedQuote || closure.second;
|
||||||
} else {
|
|
||||||
output.push_back(str.substr(1));
|
|
||||||
str = "";
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
auto it = std::find_if(std::begin(str), std::end(str), find_ws);
|
auto it = std::find_if(std::begin(str), std::end(str), find_ws);
|
||||||
if(it != std::end(str)) {
|
if(it != std::end(str)) {
|
||||||
@ -219,12 +282,12 @@ CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter)
|
|||||||
str = std::string(it + 1, str.end());
|
str = std::string(it + 1, str.end());
|
||||||
} else {
|
} else {
|
||||||
output.push_back(str);
|
output.push_back(str);
|
||||||
str = "";
|
str.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// transform any embedded quotes into the regular character
|
// transform any embedded quotes into the regular character if the quotes are removed
|
||||||
if(embeddedQuote) {
|
if(embeddedQuote && removeQuotes) {
|
||||||
output.back() = find_and_replace(output.back(), std::string("\\") + keyChar, std::string(1, keyChar));
|
output.back() = remove_escaped_characters(output.back());
|
||||||
embeddedQuote = false;
|
embeddedQuote = false;
|
||||||
}
|
}
|
||||||
trim(str);
|
trim(str);
|
||||||
@ -244,6 +307,105 @@ CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) {
|
|||||||
return offset + 1;
|
return offset + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape) {
|
||||||
|
// s is our escaped output string
|
||||||
|
std::string escaped_string{};
|
||||||
|
// loop through all characters
|
||||||
|
for(char c : string_to_escape) {
|
||||||
|
// check if a given character is printable
|
||||||
|
// the cast is necessary to avoid undefined behaviour
|
||||||
|
if(isprint(static_cast<unsigned char>(c)) == 0) {
|
||||||
|
std::stringstream stream;
|
||||||
|
// if the character is not printable
|
||||||
|
// we'll convert it to a hex string using a stringstream
|
||||||
|
// note that since char is signed we have to cast it to unsigned first
|
||||||
|
stream << std::hex << static_cast<unsigned int>(static_cast<unsigned char>(c));
|
||||||
|
std::string code = stream.str();
|
||||||
|
escaped_string += std::string("\\x") + (code.size() < 2 ? "0" : "") + code;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
escaped_string.push_back(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(escaped_string != string_to_escape) {
|
||||||
|
auto sqLoc = escaped_string.find('\'');
|
||||||
|
while(sqLoc != std::string::npos) {
|
||||||
|
escaped_string.replace(sqLoc, sqLoc + 1, "\\x27");
|
||||||
|
sqLoc = escaped_string.find('\'');
|
||||||
|
}
|
||||||
|
escaped_string.insert(0, "'B\"(");
|
||||||
|
escaped_string.push_back(')');
|
||||||
|
escaped_string.push_back('"');
|
||||||
|
escaped_string.push_back('\'');
|
||||||
|
}
|
||||||
|
return escaped_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string) {
|
||||||
|
size_t ssize = escaped_string.size();
|
||||||
|
if(escaped_string.compare(0, 3, "B\"(") == 0 && escaped_string.compare(ssize - 2, 2, ")\"") == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (escaped_string.compare(0, 4, "'B\"(") == 0 && escaped_string.compare(ssize - 3, 3, ")\"'") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string) {
|
||||||
|
std::size_t start{0};
|
||||||
|
std::size_t tail{0};
|
||||||
|
size_t ssize = escaped_string.size();
|
||||||
|
if(escaped_string.compare(0, 3, "B\"(") == 0 && escaped_string.compare(ssize - 2, 2, ")\"") == 0) {
|
||||||
|
start = 3;
|
||||||
|
tail = 2;
|
||||||
|
} else if(escaped_string.compare(0, 4, "'B\"(") == 0 && escaped_string.compare(ssize - 3, 3, ")\"'") == 0) {
|
||||||
|
start = 4;
|
||||||
|
tail = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(start == 0) {
|
||||||
|
return escaped_string;
|
||||||
|
}
|
||||||
|
std::string outstring;
|
||||||
|
|
||||||
|
outstring.reserve(ssize - start - tail);
|
||||||
|
std::size_t loc = start;
|
||||||
|
while(loc < ssize - tail) {
|
||||||
|
// ssize-2 to skip )" at the end
|
||||||
|
if(escaped_string[loc] == '\\' && (escaped_string[loc + 1] == 'x' || escaped_string[loc + 1] == 'X')) {
|
||||||
|
auto c1 = escaped_string[loc + 2];
|
||||||
|
auto c2 = escaped_string[loc + 3];
|
||||||
|
int res{0};
|
||||||
|
bool invalid{false};
|
||||||
|
if(c1 >= '0' && c1 <= '9') {
|
||||||
|
res = (c1 - '0') * 16;
|
||||||
|
} else if(c1 >= 'A' && c1 <= 'F') {
|
||||||
|
res = (c1 - 'A' + 10) * 16;
|
||||||
|
} else if(c1 >= 'a' && c1 <= 'f') {
|
||||||
|
res = (c1 - 'a' + 10) * 16;
|
||||||
|
} else {
|
||||||
|
invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c2 >= '0' && c2 <= '9') {
|
||||||
|
res += (c2 - '0');
|
||||||
|
} else if(c2 >= 'A' && c2 <= 'F') {
|
||||||
|
res += (c2 - 'A' + 10);
|
||||||
|
} else if(c2 >= 'a' && c2 <= 'f') {
|
||||||
|
res += (c2 - 'a' + 10);
|
||||||
|
} else {
|
||||||
|
invalid = true;
|
||||||
|
}
|
||||||
|
if(!invalid) {
|
||||||
|
loc += 4;
|
||||||
|
outstring.push_back(static_cast<char>(res));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outstring.push_back(escaped_string[loc]);
|
||||||
|
++loc;
|
||||||
|
}
|
||||||
|
return outstring;
|
||||||
|
}
|
||||||
|
|
||||||
std::string get_environment_value(const std::string &env_name) {
|
std::string get_environment_value(const std::string &env_name) {
|
||||||
char *buffer = nullptr;
|
char *buffer = nullptr;
|
||||||
std::string ename_string;
|
std::string ename_string;
|
||||||
|
@ -80,28 +80,6 @@ TEST_CASE_METHOD(TApp, "OneFlagShortWindows", "[app]") {
|
|||||||
CHECK(app.count("--count") == 1u);
|
CHECK(app.count("--count") == 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(TApp, "WindowsLongShortMix1", "[app]") {
|
|
||||||
app.allow_windows_style_options();
|
|
||||||
|
|
||||||
auto *a = app.add_flag("-c");
|
|
||||||
auto *b = app.add_flag("--c");
|
|
||||||
args = {"/c"};
|
|
||||||
run();
|
|
||||||
CHECK(a->count() == 1u);
|
|
||||||
CHECK(b->count() == 0u);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE_METHOD(TApp, "WindowsLongShortMix2", "[app]") {
|
|
||||||
app.allow_windows_style_options();
|
|
||||||
|
|
||||||
auto *a = app.add_flag("--c");
|
|
||||||
auto *b = app.add_flag("-c");
|
|
||||||
args = {"/c"};
|
|
||||||
run();
|
|
||||||
CHECK(a->count() == 1u);
|
|
||||||
CHECK(b->count() == 0u);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE_METHOD(TApp, "CountNonExist", "[app]") {
|
TEST_CASE_METHOD(TApp, "CountNonExist", "[app]") {
|
||||||
app.add_flag("-c,--count");
|
app.add_flag("-c,--count");
|
||||||
args = {"-c"};
|
args = {"-c"};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
if(CLI11_SANITIZERS)
|
if(CLI11_SANITIZERS AND ${CMAKE_VERSION} VERSION_GREATER "3.13.0")
|
||||||
message(STATUS "Using arsenm/sanitizers-cmake")
|
message(STATUS "Using arsenm/sanitizers-cmake")
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
sanitizers
|
sanitizers
|
||||||
|
@ -2018,6 +2018,41 @@ TEST_CASE_METHOD(TApp, "IniNotConfigurable", "[config]") {
|
|||||||
CHECK_NOTHROW(run());
|
CHECK_NOTHROW(run());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(TApp, "IniFlagDisableOverrideFlagArray", "[config]") {
|
||||||
|
|
||||||
|
TempFile tmpini{"TestIniTmp.ini"};
|
||||||
|
|
||||||
|
app.set_config("--config", tmpini);
|
||||||
|
int value{0};
|
||||||
|
app.add_flag("--val", value)->configurable(true)->disable_flag_override();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::ofstream out{tmpini};
|
||||||
|
out << "[default]" << std::endl;
|
||||||
|
out << "val=[1,true,false,true]" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(run());
|
||||||
|
CHECK(value == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(TApp, "IniFlagInvalidDisableOverrideFlagArray", "[config]") {
|
||||||
|
|
||||||
|
TempFile tmpini{"TestIniTmp.ini"};
|
||||||
|
|
||||||
|
app.set_config("--config", tmpini);
|
||||||
|
int value{0};
|
||||||
|
app.add_flag("--val", value)->configurable(true)->disable_flag_override();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::ofstream out{tmpini};
|
||||||
|
out << "[default]" << std::endl;
|
||||||
|
out << "val=[1,true,false,not_valid]" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_THROWS_AS(run(), CLI::InvalidError);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(TApp, "IniSubFailure", "[config]") {
|
TEST_CASE_METHOD(TApp, "IniSubFailure", "[config]") {
|
||||||
|
|
||||||
TempFile tmpini{"TestIniTmp.ini"};
|
TempFile tmpini{"TestIniTmp.ini"};
|
||||||
@ -2666,6 +2701,7 @@ TEST_CASE_METHOD(TApp, "TomlOutputOptionGroupMultiLineDescription", "[config]")
|
|||||||
og->description("Option group description.\n"
|
og->description("Option group description.\n"
|
||||||
"That has multiple lines.");
|
"That has multiple lines.");
|
||||||
og->add_flag("--" + flag, description);
|
og->add_flag("--" + flag, description);
|
||||||
|
args = {"--" + flag};
|
||||||
run();
|
run();
|
||||||
|
|
||||||
std::string str = app.config_to_str(true, true);
|
std::string str = app.config_to_str(true, true);
|
||||||
@ -2955,7 +2991,7 @@ TEST_CASE_METHOD(TApp, "TomlOutputQuoted", "[config]") {
|
|||||||
|
|
||||||
std::string str = app.config_to_str();
|
std::string str = app.config_to_str();
|
||||||
CHECK_THAT(str, Contains("val1=\"I am a string\""));
|
CHECK_THAT(str, Contains("val1=\"I am a string\""));
|
||||||
CHECK_THAT(str, Contains("val2='I am a \"confusing\" string'"));
|
CHECK_THAT(str, Contains("val2=\"I am a \\\"confusing\\\" string\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(TApp, "DefaultsTomlOutputQuoted", "[config]") {
|
TEST_CASE_METHOD(TApp, "DefaultsTomlOutputQuoted", "[config]") {
|
||||||
@ -2970,7 +3006,7 @@ TEST_CASE_METHOD(TApp, "DefaultsTomlOutputQuoted", "[config]") {
|
|||||||
|
|
||||||
std::string str = app.config_to_str(true);
|
std::string str = app.config_to_str(true);
|
||||||
CHECK_THAT(str, Contains("val1=\"I am a string\""));
|
CHECK_THAT(str, Contains("val1=\"I am a string\""));
|
||||||
CHECK_THAT(str, Contains("val2='I am a \"confusing\" string'"));
|
CHECK_THAT(str, Contains("val2=\"I am a \\\"confusing\\\" string\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
// #298
|
// #298
|
||||||
@ -3421,7 +3457,7 @@ TEST_CASE_METHOD(TApp, "IniOutputQuoted", "[config]") {
|
|||||||
|
|
||||||
std::string str = app.config_to_str();
|
std::string str = app.config_to_str();
|
||||||
CHECK_THAT(str, Contains("val1=\"I am a string\""));
|
CHECK_THAT(str, Contains("val1=\"I am a string\""));
|
||||||
CHECK_THAT(str, Contains("val2='I am a \"confusing\" string'"));
|
CHECK_THAT(str, Contains("val2=\"I am a \\\"confusing\\\" string\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(TApp, "DefaultsIniOutputQuoted", "[config]") {
|
TEST_CASE_METHOD(TApp, "DefaultsIniOutputQuoted", "[config]") {
|
||||||
@ -3436,5 +3472,5 @@ TEST_CASE_METHOD(TApp, "DefaultsIniOutputQuoted", "[config]") {
|
|||||||
|
|
||||||
std::string str = app.config_to_str(true);
|
std::string str = app.config_to_str(true);
|
||||||
CHECK_THAT(str, Contains("val1=\"I am a string\""));
|
CHECK_THAT(str, Contains("val1=\"I am a string\""));
|
||||||
CHECK_THAT(str, Contains("val2='I am a \"confusing\" string'"));
|
CHECK_THAT(str, Contains("val2=\"I am a \\\"confusing\\\" string\""));
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,16 @@ TEST_CASE_METHOD(TApp, "AddingExistingWithCase", "[creation]") {
|
|||||||
CHECK_NOTHROW(app.add_flag("--Cat,-C"));
|
CHECK_NOTHROW(app.add_flag("--Cat,-C"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(TApp, "AddingExistingShortLong", "[creation]") {
|
||||||
|
app.add_flag("-c");
|
||||||
|
CHECK_THROWS_AS(app.add_flag("--c"), CLI::OptionAlreadyAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(TApp, "AddingExistingLongShort", "[creation]") {
|
||||||
|
app.add_flag("--c");
|
||||||
|
CHECK_THROWS_AS(app.add_option("-c"), CLI::OptionAlreadyAdded);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(TApp, "AddingExistingWithCaseAfter", "[creation]") {
|
TEST_CASE_METHOD(TApp, "AddingExistingWithCaseAfter", "[creation]") {
|
||||||
auto *count = app.add_flag("-c,--count");
|
auto *count = app.add_flag("-c,--count");
|
||||||
app.add_flag("--Cat,-C");
|
app.add_flag("--Cat,-C");
|
||||||
@ -68,6 +78,37 @@ TEST_CASE_METHOD(TApp, "AddingExistingWithUnderscoreAfter2", "[creation]") {
|
|||||||
CHECK_THROWS_AS(count->ignore_underscore(), CLI::OptionAlreadyAdded);
|
CHECK_THROWS_AS(count->ignore_underscore(), CLI::OptionAlreadyAdded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(TApp, "matchPositional", "[creation]") {
|
||||||
|
app.add_option("firstoption");
|
||||||
|
CHECK_THROWS_AS(app.add_option("--firstoption"), CLI::OptionAlreadyAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(TApp, "matchPositional2", "[creation]") {
|
||||||
|
app.add_option("--firstoption");
|
||||||
|
CHECK_THROWS_AS(app.add_option("firstoption"), CLI::OptionAlreadyAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(TApp, "matchPositionalInOptionGroup1", "[creation]") {
|
||||||
|
|
||||||
|
auto *g1 = app.add_option_group("group_b");
|
||||||
|
g1->add_option("--firstoption");
|
||||||
|
CHECK_THROWS_AS(app.add_option("firstoption"), CLI::OptionAlreadyAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(TApp, "matchPositionalInOptionGroup2", "[creation]") {
|
||||||
|
|
||||||
|
app.add_option("firstoption");
|
||||||
|
auto *g1 = app.add_option_group("group_b");
|
||||||
|
CHECK_THROWS_AS(g1->add_option("--firstoption"), CLI::OptionAlreadyAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(TApp, "matchPositionalInOptionGroup3", "[creation]") {
|
||||||
|
|
||||||
|
app.add_option("f");
|
||||||
|
auto *g1 = app.add_option_group("group_b");
|
||||||
|
CHECK_THROWS_AS(g1->add_option("-f"), CLI::OptionAlreadyAdded);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(TApp, "AddingMultipleInfPositionals", "[creation]") {
|
TEST_CASE_METHOD(TApp, "AddingMultipleInfPositionals", "[creation]") {
|
||||||
std::vector<std::string> one, two;
|
std::vector<std::string> one, two;
|
||||||
app.add_option("one", one);
|
app.add_option("one", one);
|
||||||
|
@ -58,3 +58,40 @@ TEST_CASE("file_fail") {
|
|||||||
} catch(const CLI::ParseError & /*e*/) {
|
} catch(const CLI::ParseError & /*e*/) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("app_file_gen_fail") {
|
||||||
|
CLI::FuzzApp fuzzdata;
|
||||||
|
auto app = fuzzdata.generateApp();
|
||||||
|
|
||||||
|
int index = GENERATE(range(1, 33));
|
||||||
|
std::string optionString, flagString;
|
||||||
|
auto parseData = loadFailureFile("fuzz_app_file_fail", index);
|
||||||
|
if(parseData.size() > 25) {
|
||||||
|
optionString = parseData.substr(0, 25);
|
||||||
|
parseData.erase(0, 25);
|
||||||
|
}
|
||||||
|
if(parseData.size() > 25) {
|
||||||
|
flagString = parseData.substr(0, 25);
|
||||||
|
parseData.erase(0, 25);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
|
||||||
|
if(!optionString.empty()) {
|
||||||
|
app->add_option(optionString, fuzzdata.buffer);
|
||||||
|
}
|
||||||
|
if(!flagString.empty()) {
|
||||||
|
app->add_flag(flagString, fuzzdata.intbuffer);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
app->parse(parseData);
|
||||||
|
} catch(const CLI::ParseError & /*e*/) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch(const CLI::ConstructionError & /*e*/) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::string configOut = app->config_to_str();
|
||||||
|
app->clear();
|
||||||
|
std::stringstream out(configOut);
|
||||||
|
app->parse_from_stream(out);
|
||||||
|
}
|
||||||
|
@ -237,6 +237,77 @@ TEST_CASE("StringTools: Validation", "[helpers]") {
|
|||||||
CHECK_FALSE(CLI::detail::isalpha("test2"));
|
CHECK_FALSE(CLI::detail::isalpha("test2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("StringTools: binaryEscapseConversion", "[helpers]") {
|
||||||
|
std::string testString("string1");
|
||||||
|
std::string estring = CLI::detail::binary_escape_string(testString);
|
||||||
|
CHECK(testString == estring);
|
||||||
|
CHECK_FALSE(CLI::detail::is_binary_escaped_string(estring));
|
||||||
|
|
||||||
|
std::string testString2("\nstring1\n");
|
||||||
|
estring = CLI::detail::binary_escape_string(testString2);
|
||||||
|
CHECK_FALSE(testString == estring);
|
||||||
|
CHECK(CLI::detail::is_binary_escaped_string(estring));
|
||||||
|
std::string rstring = CLI::detail::extract_binary_string(estring);
|
||||||
|
CHECK(rstring == testString2);
|
||||||
|
|
||||||
|
testString2.push_back(0);
|
||||||
|
testString2.push_back(static_cast<char>(197));
|
||||||
|
testString2.push_back(78);
|
||||||
|
testString2.push_back(-34);
|
||||||
|
|
||||||
|
rstring = CLI::detail::extract_binary_string(CLI::detail::binary_escape_string(testString2));
|
||||||
|
CHECK(rstring == testString2);
|
||||||
|
|
||||||
|
testString2.push_back('b');
|
||||||
|
testString2.push_back('G');
|
||||||
|
|
||||||
|
rstring = CLI::detail::extract_binary_string(CLI::detail::binary_escape_string(testString2));
|
||||||
|
CHECK(rstring == testString2);
|
||||||
|
auto rstring2 = CLI::detail::extract_binary_string(rstring);
|
||||||
|
CHECK(rstring == rstring2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("StringTools: binaryStrings", "[helpers]") {
|
||||||
|
std::string rstring = "B\"()\"";
|
||||||
|
CHECK(CLI::detail::extract_binary_string(rstring).empty());
|
||||||
|
|
||||||
|
rstring = "B\"(\\x35\\xa7)\"";
|
||||||
|
auto result = CLI::detail::extract_binary_string(rstring);
|
||||||
|
CHECK(result[0] == static_cast<char>(0x35));
|
||||||
|
CHECK(result[1] == static_cast<char>(0xa7));
|
||||||
|
|
||||||
|
rstring = "B\"(\\x3e\\xf7)\"";
|
||||||
|
result = CLI::detail::extract_binary_string(rstring);
|
||||||
|
CHECK(result[0] == static_cast<char>(0x3e));
|
||||||
|
CHECK(result[1] == static_cast<char>(0xf7));
|
||||||
|
|
||||||
|
rstring = "B\"(\\x3E\\xf7)\"";
|
||||||
|
result = CLI::detail::extract_binary_string(rstring);
|
||||||
|
CHECK(result[0] == static_cast<char>(0x3e));
|
||||||
|
CHECK(result[1] == static_cast<char>(0xf7));
|
||||||
|
|
||||||
|
rstring = "B\"(\\X3E\\XF7)\"";
|
||||||
|
result = CLI::detail::extract_binary_string(rstring);
|
||||||
|
CHECK(result[0] == static_cast<char>(0x3e));
|
||||||
|
CHECK(result[1] == static_cast<char>(0xf7));
|
||||||
|
|
||||||
|
rstring = "B\"(\\XME\\XK7)\"";
|
||||||
|
result = CLI::detail::extract_binary_string(rstring);
|
||||||
|
CHECK(result == "\\XME\\XK7");
|
||||||
|
|
||||||
|
rstring = "B\"(\\XEM\\X7K)\"";
|
||||||
|
result = CLI::detail::extract_binary_string(rstring);
|
||||||
|
CHECK(result == "\\XEM\\X7K");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("StringTools: escapeConversion", "[helpers]") {
|
||||||
|
CHECK(CLI::detail::remove_escaped_characters("test\\\"") == "test\"");
|
||||||
|
CHECK(CLI::detail::remove_escaped_characters("test\\}") == "test}");
|
||||||
|
CHECK(CLI::detail::remove_escaped_characters("test\\\\") == "test\\");
|
||||||
|
CHECK(CLI::detail::remove_escaped_characters("test\\\\") == "test\\");
|
||||||
|
CHECK(CLI::detail::remove_escaped_characters("test\\k") == "test\\k");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Trim: Various", "[helpers]") {
|
TEST_CASE("Trim: Various", "[helpers]") {
|
||||||
std::string s1{" sdlfkj sdflk sd s "};
|
std::string s1{" sdlfkj sdflk sd s "};
|
||||||
std::string a1{"sdlfkj sdflk sd s"};
|
std::string a1{"sdlfkj sdflk sd s"};
|
||||||
@ -909,6 +980,20 @@ TEST_CASE("SplitUp: SimpleDifferentQuotes", "[helpers]") {
|
|||||||
CHECK(result == oput);
|
CHECK(result == oput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SplitUp: SimpleMissingQuotes", "[helpers]") {
|
||||||
|
std::vector<std::string> oput = {"one", "two three"};
|
||||||
|
std::string orig{R"(one `two three)"};
|
||||||
|
std::vector<std::string> result = CLI::detail::split_up(orig);
|
||||||
|
CHECK(result == oput);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SplitUp: SimpleMissingQuotesEscaped", "[helpers]") {
|
||||||
|
std::vector<std::string> oput = {"one", "two three`"};
|
||||||
|
std::string orig{R"(one `two three\`)"};
|
||||||
|
std::vector<std::string> result = CLI::detail::split_up(orig);
|
||||||
|
CHECK(result == oput);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("SplitUp: SimpleDifferentQuotes2", "[helpers]") {
|
TEST_CASE("SplitUp: SimpleDifferentQuotes2", "[helpers]") {
|
||||||
std::vector<std::string> oput = {"one", "two three"};
|
std::vector<std::string> oput = {"one", "two three"};
|
||||||
std::string orig{R"(one 'two three')"};
|
std::string orig{R"(one 'two three')"};
|
||||||
@ -916,6 +1001,41 @@ TEST_CASE("SplitUp: SimpleDifferentQuotes2", "[helpers]") {
|
|||||||
CHECK(result == oput);
|
CHECK(result == oput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SplitUp: Bracket1", "[helpers]") {
|
||||||
|
std::vector<std::string> oput = {"one", "[two, three]"};
|
||||||
|
std::string orig{"one, [two, three]"};
|
||||||
|
std::vector<std::string> result = CLI::detail::split_up(orig, ',', false);
|
||||||
|
CHECK(result == oput);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SplitUp: Bracket2", "[helpers]") {
|
||||||
|
std::vector<std::string> oput = {"one", "<two, three>"};
|
||||||
|
std::string orig{"one, <two, three>"};
|
||||||
|
std::vector<std::string> result = CLI::detail::split_up(orig, ',', false);
|
||||||
|
CHECK(result == oput);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SplitUp: Bracket3", "[helpers]") {
|
||||||
|
std::vector<std::string> oput = {"one", "(two, three)"};
|
||||||
|
std::string orig{"one, (two, three)"};
|
||||||
|
std::vector<std::string> result = CLI::detail::split_up(orig, ',', false);
|
||||||
|
CHECK(result == oput);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SplitUp: Bracket4", "[helpers]") {
|
||||||
|
std::vector<std::string> oput = {"one", "{two, three}"};
|
||||||
|
std::string orig{"one, {two, three}"};
|
||||||
|
std::vector<std::string> result = CLI::detail::split_up(orig, ',', false);
|
||||||
|
CHECK(result == oput);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SplitUp: Comment", "[helpers]") {
|
||||||
|
std::vector<std::string> oput = {R"(["quote1", "#"])"};
|
||||||
|
std::string orig{R"(["quote1", "#"])"};
|
||||||
|
std::vector<std::string> result = CLI::detail::split_up(orig, '#', false);
|
||||||
|
CHECK(result == oput);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("SplitUp: Layered", "[helpers]") {
|
TEST_CASE("SplitUp: Layered", "[helpers]") {
|
||||||
std::vector<std::string> output = {R"(one 'two three')"};
|
std::vector<std::string> output = {R"(one 'two three')"};
|
||||||
std::string orig{R"("one 'two three'")"};
|
std::string orig{R"("one 'two three'")"};
|
||||||
|
0
tests/fuzzFail/fuzz_app_file_fail1
Normal file
0
tests/fuzzFail/fuzz_app_file_fail1
Normal file
3
tests/fuzzFail/fuzz_app_file_fail10
Normal file
3
tests/fuzzFail/fuzz_app_file_fail10
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-e-vC
|
||||||
|
,cÌC
|
||||||
|
,cÌÛÑÒ
|
1
tests/fuzzFail/fuzz_app_file_fail11
Normal file
1
tests/fuzzFail/fuzz_app_file_fail11
Normal file
@ -0,0 +1 @@
|
|||||||
|
=666666666~5Ë5Ë--oo?ptvtup@
|
BIN
tests/fuzzFail/fuzz_app_file_fail12
Normal file
BIN
tests/fuzzFail/fuzz_app_file_fail12
Normal file
Binary file not shown.
1
tests/fuzzFail/fuzz_app_file_fail13
Normal file
1
tests/fuzzFail/fuzz_app_file_fail13
Normal file
@ -0,0 +1 @@
|
|||||||
|
``'``'######################
|
4
tests/fuzzFail/fuzz_app_file_fail14
Normal file
4
tests/fuzzFail/fuzz_app_file_fail14
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
--vB
|
||||||
|
s
|
||||||
|
'
|
||||||
|
sub
|
1
tests/fuzzFail/fuzz_app_file_fail15
Normal file
1
tests/fuzzFail/fuzz_app_file_fail15
Normal file
@ -0,0 +1 @@
|
|||||||
|
""K<><4B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"鰫
|
BIN
tests/fuzzFail/fuzz_app_file_fail16
Normal file
BIN
tests/fuzzFail/fuzz_app_file_fail16
Normal file
Binary file not shown.
9
tests/fuzzFail/fuzz_app_file_fail17
Normal file
9
tests/fuzzFail/fuzz_app_file_fail17
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
--vE
|
||||||
|
|
||||||
|
˙˙˙˙˙
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
1
tests/fuzzFail/fuzz_app_file_fail18
Normal file
1
tests/fuzzFail/fuzz_app_file_fail18
Normal file
@ -0,0 +1 @@
|
|||||||
|
--vD \<5C><EFBFBD><7F><EFBFBD> \
|
1
tests/fuzzFail/fuzz_app_file_fail19
Normal file
1
tests/fuzzFail/fuzz_app_file_fail19
Normal file
@ -0,0 +1 @@
|
|||||||
|
1-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ceeecae
|
1
tests/fuzzFail/fuzz_app_file_fail2
Normal file
1
tests/fuzzFail/fuzz_app_file_fail2
Normal file
@ -0,0 +1 @@
|
|||||||
|
-c
|
1
tests/fuzzFail/fuzz_app_file_fail20
Normal file
1
tests/fuzzFail/fuzz_app_file_fail20
Normal file
@ -0,0 +1 @@
|
|||||||
|
································-é#e,cecb
|
BIN
tests/fuzzFail/fuzz_app_file_fail21
Normal file
BIN
tests/fuzzFail/fuzz_app_file_fail21
Normal file
Binary file not shown.
1
tests/fuzzFail/fuzz_app_file_fail22
Normal file
1
tests/fuzzFail/fuzz_app_file_fail22
Normal file
@ -0,0 +1 @@
|
|||||||
|
dwrap'a
|
BIN
tests/fuzzFail/fuzz_app_file_fail23
Normal file
BIN
tests/fuzzFail/fuzz_app_file_fail23
Normal file
Binary file not shown.
BIN
tests/fuzzFail/fuzz_app_file_fail24
Normal file
BIN
tests/fuzzFail/fuzz_app_file_fail24
Normal file
Binary file not shown.
BIN
tests/fuzzFail/fuzz_app_file_fail25
Normal file
BIN
tests/fuzzFail/fuzz_app_file_fail25
Normal file
Binary file not shown.
1
tests/fuzzFail/fuzz_app_file_fail26
Normal file
1
tests/fuzzFail/fuzz_app_file_fail26
Normal file
@ -0,0 +1 @@
|
|||||||
|
--vC opCB (3tp"o3#
|
2
tests/fuzzFail/fuzz_app_file_fail27
Normal file
2
tests/fuzzFail/fuzz_app_file_fail27
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
--vD<0C> `
|
||||||
|
-5
|
5
tests/fuzzFail/fuzz_app_file_fail28
Normal file
5
tests/fuzzFail/fuzz_app_file_fail28
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
--vB
|
||||||
|
--vB
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD>-vC
|
4
tests/fuzzFail/fuzz_app_file_fail29
Normal file
4
tests/fuzzFail/fuzz_app_file_fail29
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
--vE
|
||||||
|
-3vE
|
||||||
|
0)-bb=`',,l
|
1
tests/fuzzFail/fuzz_app_file_fail3
Normal file
1
tests/fuzzFail/fuzz_app_file_fail3
Normal file
@ -0,0 +1 @@
|
|||||||
|
`--vM```-````-c`
|
1
tests/fuzzFail/fuzz_app_file_fail30
Normal file
1
tests/fuzzFail/fuzz_app_file_fail30
Normal file
@ -0,0 +1 @@
|
|||||||
|
[驎驎驎驎驎驎珉ppt1"wrappt1""\","""\""\","
|
1
tests/fuzzFail/fuzz_app_file_fail31
Normal file
1
tests/fuzzFail/fuzz_app_file_fail31
Normal file
@ -0,0 +1 @@
|
|||||||
|
--$,,,,,,,,,,,,,,,,,,,,A,,,,,,,,,,,-$,,,,,,,,,,,,,,,,,,,,A,,,,,,,,,,,,,,,,,,,,,;--svopt2#,,,,-sC
|
1
tests/fuzzFail/fuzz_app_file_fail32
Normal file
1
tests/fuzzFail/fuzz_app_file_fail32
Normal file
@ -0,0 +1 @@
|
|||||||
|
-¬,,,,,,,,,,,,,,,,,,,opt1śa
|
1
tests/fuzzFail/fuzz_app_file_fail4
Normal file
1
tests/fuzzFail/fuzz_app_file_fail4
Normal file
@ -0,0 +1 @@
|
|||||||
|
-ccaaaa
|
6
tests/fuzzFail/fuzz_app_file_fail5
Normal file
6
tests/fuzzFail/fuzz_app_file_fail5
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Š
|
||||||
|
atd
|
||||||
|
ŸVVV-baÒî=
|
||||||
|
î
|
||||||
|
<EFBFBD>
|
||||||
|
.-' -
|
BIN
tests/fuzzFail/fuzz_app_file_fail6
Normal file
BIN
tests/fuzzFail/fuzz_app_file_fail6
Normal file
Binary file not shown.
3
tests/fuzzFail/fuzz_app_file_fail7
Normal file
3
tests/fuzzFail/fuzz_app_file_fail7
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
.br-bN3CLI10ParseErrorEa5
|
BIN
tests/fuzzFail/fuzz_app_file_fail8
Normal file
BIN
tests/fuzzFail/fuzz_app_file_fail8
Normal file
Binary file not shown.
1
tests/fuzzFail/fuzz_app_file_fail9
Normal file
1
tests/fuzzFail/fuzz_app_file_fail9
Normal file
@ -0,0 +1 @@
|
|||||||
|
=o˙˙˙˙˙˙˙˙˙˙p--2v˙˙t'Í-č-
|
Loading…
x
Reference in New Issue
Block a user