diff --git a/.codacy.yml b/.codacy.yml new file mode 100644 index 00000000..03a1e522 --- /dev/null +++ b/.codacy.yml @@ -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" diff --git a/CPPLINT.cfg b/CPPLINT.cfg index 40bec371..e1d27d9f 100644 --- a/CPPLINT.cfg +++ b/CPPLINT.cfg @@ -9,6 +9,7 @@ filter=-readability/nolint # Conflicts with clang-tidy filter=-readability/check # Catch uses CHECK(a == b) (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/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/indent # Requires strange 3-space indent of private/protected/public markers filter=-whitespace/parens,-whitespace/braces # Conflict with clang-format diff --git a/book/chapters/config.md b/book/chapters/config.md index d8b2d475..e6720502 100644 --- a/book/chapters/config.md +++ b/book/chapters/config.md @@ -206,6 +206,16 @@ str3 = """\ 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. +### 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 If it is desired that multiple configuration be allowed. Use diff --git a/fuzz/cli11_app_fuzz.cpp b/fuzz/cli11_app_fuzz.cpp index 321d644d..bd3a5f9b 100644 --- a/fuzz/cli11_app_fuzz.cpp +++ b/fuzz/cli11_app_fuzz.cpp @@ -40,10 +40,16 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { try { app->parse(parseString); + } catch(const CLI::ParseError &e) { //(app)->exit(e); // 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; } diff --git a/fuzz/cli11_file_fuzz.cpp b/fuzz/cli11_file_fuzz.cpp index 5858822d..e69193b9 100644 --- a/fuzz/cli11_file_fuzz.cpp +++ b/fuzz/cli11_file_fuzz.cpp @@ -22,6 +22,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { auto app = fuzzdata.generateApp(); try { 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) { // (app)->exit(e); // this just indicates we caught an error known by CLI diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 9769fef9..794d2b6a 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -68,9 +68,9 @@ std::shared_ptr FuzzApp::generateApp() { auto *vgroup = fApp->add_option_group("vectors"); 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("--vopt4", vecvecd); + vgroup->add_option("--vopt4", vecvecd)->inject_separator(); fApp->add_option("--oopt1", od1); fApp->add_option("--oopt2", ods); @@ -121,6 +121,30 @@ std::shared_ptr FuzzApp::generateApp() { sub->add_option("--sdwrap", dwrap); 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()); + vldtr->add_option("--vdtr7", validator_strings[6])->join()->check(CLI::TypeValidator()); + 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; } diff --git a/fuzz/fuzzApp.hpp b/fuzz/fuzzApp.hpp index 45d02a17..2a97bc49 100644 --- a/fuzz/fuzzApp.hpp +++ b/fuzz/fuzzApp.hpp @@ -75,6 +75,7 @@ class FuzzApp { std::vector vv1{}; std::vector vstr{}; + std::vector> vecvecd{}; std::vector> vvs{}; std::optional od1{}; @@ -103,5 +104,15 @@ class FuzzApp { std::string buffer{}; int intbuffer{0}; std::atomic doubleAtomic{0.0}; + + // for testing restrictions and reduction methods + std::vector vstrA{}; + std::vector vstrB{}; + std::vector vstrC{}; + std::vector vstrD{}; + std::vector vstrE{}; + std::vector vstrF{}; + std::string mergeBuffer{}; + std::vector validator_strings{}; }; } // namespace CLI diff --git a/fuzz/fuzzCommand.cpp b/fuzz/fuzzCommand.cpp index 07ab0df2..f73386fc 100644 --- a/fuzz/fuzzCommand.cpp +++ b/fuzz/fuzzCommand.cpp @@ -20,5 +20,6 @@ int main(int argc, char **argv) { (app)->exit(e); // this just indicates we caught an error known by CLI } + return 0; } diff --git a/fuzz/fuzz_dictionary1.txt b/fuzz/fuzz_dictionary1.txt index 166642ec..327f658b 100644 --- a/fuzz/fuzz_dictionary1.txt +++ b/fuzz/fuzz_dictionary1.txt @@ -66,6 +66,14 @@ "--siwrap" "--svtup" "--satd" +"--vA" +"--vB" +"--vC" +"--vD" +"--vS" +"--vM" +"--vE" +"--vdtr" "nflag2" "stup1" "svtup" @@ -143,6 +151,7 @@ "stup4" "sdwrap" "siwrap" +"vdtr" "svtup" "satd" "%%" @@ -156,3 +165,10 @@ "!" "{" "}" +"vA" +"vB" +"vC" +"vD" +"vS" +"vM" +"vE" diff --git a/fuzz/fuzz_dictionary2.txt b/fuzz/fuzz_dictionary2.txt index 47f30afa..828be3a3 100644 --- a/fuzz/fuzz_dictionary2.txt +++ b/fuzz/fuzz_dictionary2.txt @@ -72,6 +72,7 @@ "svopt4" "config" "nflag2" +"vdtr" "--" "fuzzer" "t-" @@ -82,3 +83,10 @@ "dexists" "fexists" "fnexists" +"vA" +"vB" +"vC" +"vD" +"vS" +"vM" +"vE" diff --git a/include/CLI/Config.hpp b/include/CLI/Config.hpp index a91f0da6..d5c6bc34 100644 --- a/include/CLI/Config.hpp +++ b/include/CLI/Config.hpp @@ -24,7 +24,10 @@ namespace CLI { // [CLI11:config_hpp:verbatim] 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 std::string ini_join(const std::vector &args, diff --git a/include/CLI/ConfigFwd.hpp b/include/CLI/ConfigFwd.hpp index a9ae2176..76fc9fa7 100644 --- a/include/CLI/ConfigFwd.hpp +++ b/include/CLI/ConfigFwd.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include // [CLI11:public_includes:end] @@ -29,7 +30,6 @@ struct ConfigItem { /// This is the name std::string name{}; - /// Listing of inputs std::vector inputs{}; diff --git a/include/CLI/Error.hpp b/include/CLI/Error.hpp index 93f8469e..db222e72 100644 --- a/include/CLI/Error.hpp +++ b/include/CLI/Error.hpp @@ -127,6 +127,9 @@ class BadNameString : public ConstructionError { return BadNameString("Long names strings require 2 dashes " + 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) { return BadNameString("Must have a name, not just dashes: " + name); } diff --git a/include/CLI/Option.hpp b/include/CLI/Option.hpp index 0afbc978..89210bb5 100644 --- a/include/CLI/Option.hpp +++ b/include/CLI/Option.hpp @@ -550,12 +550,12 @@ class Option : public OptionBase