diff --git a/README.md b/README.md index 3736fc5..77a2bb4 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ argparse::ArgumentParser program("program_name"); **NOTE:** There is an optional second argument to the `ArgumentParser` which is the program version. Example: `argparse::ArgumentParser program("libfoo", "1.9.0");` -**NOTE:** There is an optional third argument to the `ArgumentParser` which controls default arguments. Example: `argparse::ArgumentParser program("libfoo", "1.9.0", default_arguments::none);` See [Default Arguments](#default-arguments), below. +**NOTE:** There are optional third and fourth arguments to the `ArgumentParser` which control default arguments. Example: `argparse::ArgumentParser program("libfoo", "1.9.0", default_arguments::help, false);` See [Default Arguments](#default-arguments), below. To add a new argument, simply call ```.add_argument(...)```. You can provide a variadic list of argument names that you want to group together, e.g., ```-v``` and ```--verbose``` @@ -99,7 +99,7 @@ int main(int argc, char *argv[]) { catch (const std::runtime_error& err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } auto input = program.get("square"); @@ -559,7 +559,9 @@ The grammar follows `std::from_chars`, but does not exactly duplicate it. For ex ### Default Arguments -`argparse` provides predefined arguments and actions for `-h`/`--help` and `-v`/`--version`. These default actions **exit** the program after displaying a help or version message, respectively. These defaults arguments can be disabled during `ArgumentParser` creation so that you can handle these arguments in your own way. (Note that a program name and version must be included when choosing default arguments.) +`argparse` provides predefined arguments and actions for `-h`/`--help` and `-v`/`--version`. By default, these actions will **exit** the program after displaying a help or version message, respectively. This exit does not call destructors, skipping clean-up of taken resources. + +These default arguments can be disabled during `ArgumentParser` creation so that you can handle these arguments in your own way. (Note that a program name and version must be included when choosing default arguments.) ```cpp argparse::ArgumentParser program("test", "1.0", default_arguments::none); @@ -578,6 +580,12 @@ The above code snippet outputs a help message and continues to run. It does not The default is `default_arguments::all` for included arguments. No default arguments will be added with `default_arguments::none`. `default_arguments::help` and `default_arguments::version` will individually add `--help` and `--version`. +The default arguments can be used while disabling the default exit with these arguments. This forth argument to `ArgumentParser` (`exit_on_default_arguments`) is a bool flag with a default **true** value. The following call will retain `--help` and `--version`, but will not exit when those arguments are used. + +```cpp +argparse::ArgumentParser program("test", "1.0", default_arguments::all, false) +``` + ### Gathering Remaining Arguments `argparse` supports gathering "remaining" arguments at the end of the command, e.g., for use in a compiler: @@ -773,7 +781,7 @@ int main(int argc, char *argv[]) { catch (const std::runtime_error& err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } // Use arguments @@ -900,7 +908,7 @@ int main(int argc, char *argv[]) { catch (const std::runtime_error& err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } if (program.is_used("+f")) { @@ -948,7 +956,7 @@ int main(int argc, char *argv[]) { catch (const std::runtime_error& err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } if (program.is_used("--foo")) { @@ -1096,7 +1104,7 @@ int main(int argc, char *argv[]) { catch (const std::runtime_error& err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } if (program.is_used("--foo")) { diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index b77787b..633f782 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -1052,14 +1052,18 @@ class ArgumentParser { public: explicit ArgumentParser(std::string program_name = {}, std::string version = "1.0", - default_arguments add_args = default_arguments::all) + default_arguments add_args = default_arguments::all, + bool exit_on_default_arguments = true) : m_program_name(std::move(program_name)), m_version(std::move(version)), + m_exit_on_default_arguments(exit_on_default_arguments), m_parser_path(m_program_name) { if ((add_args & default_arguments::help) == default_arguments::help) { add_argument("-h", "--help") .action([&](const auto & /*unused*/) { std::cout << help().str(); - std::exit(0); + if (m_exit_on_default_arguments) { + std::exit(0); + } }) .default_value(false) .help("shows help message and exits") @@ -1070,7 +1074,9 @@ public: add_argument("-v", "--version") .action([&](const auto & /*unused*/) { std::cout << m_version << std::endl; - std::exit(0); + if (m_exit_on_default_arguments) { + std::exit(0); + } }) .default_value(false) .help("prints version information and exits") @@ -1676,6 +1682,7 @@ private: std::string m_version; std::string m_description; std::string m_epilog; + bool m_exit_on_default_arguments = true; std::string m_prefix_chars{"-"}; std::string m_assign_chars{"="}; bool m_is_parsed = false; diff --git a/samples/compound_arguments.cpp b/samples/compound_arguments.cpp index 66d5c92..4cfc037 100644 --- a/samples/compound_arguments.cpp +++ b/samples/compound_arguments.cpp @@ -19,7 +19,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } auto a = program.get("-a"); // true diff --git a/samples/custom_assignment_characters.cpp b/samples/custom_assignment_characters.cpp index d5deff1..7e35ae0 100644 --- a/samples/custom_assignment_characters.cpp +++ b/samples/custom_assignment_characters.cpp @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } if (program.is_used("--foo")) { diff --git a/samples/custom_prefix_characters.cpp b/samples/custom_prefix_characters.cpp index 01e248a..9f8917a 100644 --- a/samples/custom_prefix_characters.cpp +++ b/samples/custom_prefix_characters.cpp @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } if (program.is_used("+f")) { diff --git a/samples/gathering_remaining_arguments.cpp b/samples/gathering_remaining_arguments.cpp index 4f40454..be13f10 100644 --- a/samples/gathering_remaining_arguments.cpp +++ b/samples/gathering_remaining_arguments.cpp @@ -12,7 +12,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } try { diff --git a/samples/is_used.cpp b/samples/is_used.cpp index 27e0373..ffc05f8 100644 --- a/samples/is_used.cpp +++ b/samples/is_used.cpp @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } auto color = program.get("--color"); // "orange" diff --git a/samples/joining_repeated_optional_arguments.cpp b/samples/joining_repeated_optional_arguments.cpp index eebbdc6..0f6ab81 100644 --- a/samples/joining_repeated_optional_arguments.cpp +++ b/samples/joining_repeated_optional_arguments.cpp @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } auto colors = program.get>( diff --git a/samples/list_of_arguments.cpp b/samples/list_of_arguments.cpp index e533e47..996e748 100644 --- a/samples/list_of_arguments.cpp +++ b/samples/list_of_arguments.cpp @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } auto files = program.get>( diff --git a/samples/negative_numbers.cpp b/samples/negative_numbers.cpp index ac4284f..319245f 100644 --- a/samples/negative_numbers.cpp +++ b/samples/negative_numbers.cpp @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } if (program.is_used("integer")) { diff --git a/samples/optional_flag_argument.cpp b/samples/optional_flag_argument.cpp index 2f85954..f935ecf 100644 --- a/samples/optional_flag_argument.cpp +++ b/samples/optional_flag_argument.cpp @@ -15,7 +15,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } if (program["--verbose"] == true) { diff --git a/samples/positional_argument.cpp b/samples/positional_argument.cpp index 03ffb0a..4343863 100644 --- a/samples/positional_argument.cpp +++ b/samples/positional_argument.cpp @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } int input = program.get("square"); diff --git a/samples/required_optional_argument.cpp b/samples/required_optional_argument.cpp index efea523..0271f50 100644 --- a/samples/required_optional_argument.cpp +++ b/samples/required_optional_argument.cpp @@ -14,7 +14,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } std::cout << "Output written to " << program.get("-o") << "\n"; diff --git a/samples/subcommands.cpp b/samples/subcommands.cpp index 74d610e..ba1059d 100644 --- a/samples/subcommands.cpp +++ b/samples/subcommands.cpp @@ -60,7 +60,7 @@ int main(int argc, char *argv[]) { } catch (const std::runtime_error &err) { std::cerr << err.what() << std::endl; std::cerr << program; - std::exit(1); + return 1; } // Use arguments diff --git a/test/test_default_args.cpp b/test/test_default_args.cpp index 7b5e581..d0cdd25 100644 --- a/test/test_default_args.cpp +++ b/test/test_default_args.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include using doctest::test_suite; @@ -17,3 +19,13 @@ TEST_CASE("Do not include default arguments" * test_suite("default_args")) { REQUIRE_THROWS_AS(parser.get("--help"), std::logic_error); REQUIRE_THROWS_AS(parser.get("--version"), std::logic_error); } + +TEST_CASE("Do not exit on default arguments" * test_suite("default_args")) { + argparse::ArgumentParser parser("test", "1.0", + argparse::default_arguments::all, false); + std::stringstream buf; + std::streambuf* saved_cout_buf = std::cout.rdbuf(buf.rdbuf()); + parser.parse_args({"test", "--help"}); + std::cout.rdbuf(saved_cout_buf); + REQUIRE(parser.is_used("--help")); +}