[med-svn] [Git][med-team/argh][upstream] New upstream version 1.3.2+ds
Étienne Mollier (@emollier)
gitlab at salsa.debian.org
Sun May 15 12:50:03 BST 2022
Étienne Mollier pushed to branch upstream at Debian Med / argh
Commits:
366ab582 by Étienne Mollier at 2022-05-15T13:26:08+02:00
New upstream version 1.3.2+ds
- - - - -
4 changed files:
- CMakeLists.txt
- README.md
- argh.h
- argh_tests.cpp
Changes:
=====================================
CMakeLists.txt
=====================================
@@ -1,46 +1,54 @@
-project(argh)
cmake_minimum_required(VERSION 3.1)
-set (CMAKE_CXX_STANDARD 11)
+project(argh)
+
+set(CMAKE_CXX_STANDARD 11)
-option(BUILD_TESTS "Build tests. Uncheck for install only runs" ON)
-option(BUILD_EXAMPLES "Build examples. Uncheck for install only runs" ON)
+# Check if argh is being used directly or via add_subdirectory
+set(ARGH_MASTER_PROJECT OFF)
+if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
+ set(ARGH_MASTER_PROJECT ON)
+endif()
+
+option(BUILD_TESTS "Build tests. Uncheck for install only runs"
+ ${ARGH_MASTER_PROJECT})
+option(BUILD_EXAMPLES "Build examples. Uncheck for install only runs"
+ ${ARGH_MASTER_PROJECT})
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "(Clang|GNU)")
+ list(APPEND flags "-Wall" "-Wextra" "-Wshadow" "-Wnon-virtual-dtor" "-pedantic")
+elseif(MSVC)
+ list(APPEND flags "/W4" "/WX")
+endif()
if(BUILD_EXAMPLES)
add_executable(argh_example example.cpp)
+ target_compile_options(argh_example PRIVATE ${flags})
endif()
if(BUILD_TESTS)
add_executable(argh_tests argh_tests.cpp)
+ target_compile_options(argh_tests PRIVATE ${flags})
+ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT argh_tests)
endif()
add_library(argh INTERFACE)
target_include_directories(argh INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}> $<INSTALL_INTERFACE:include>)
-set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT argh_tests)
+if(ARGH_MASTER_PROJECT)
+ install(TARGETS argh EXPORT arghTargets)
-if(BUILD_EXAMPLES OR BUILD_TESTS)
- if(UNIX OR CMAKE_COMPILER_IS_GNUCXX)
- add_definitions("-Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic")
- else(MSVC)
- add_definitions("/W4 /WX")
- endif()
-endif()
-
-install(TARGETS argh EXPORT arghTargets)
-
-if(CMAKE_SYSTEM_NAME STREQUAL Linux)
-# this might be a bit too restrictive, since for other (BSD, ...) this might apply also
-# but this can be fixed later in extra pull requests from people on the platform
include(GNUInstallDirs)
install(FILES "${CMAKE_CURRENT_LIST_DIR}/argh.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES "${CMAKE_CURRENT_LIST_DIR}/LICENSE" DESTINATION ${CMAKE_INSTALL_DOCDIR})
install(FILES "${CMAKE_CURRENT_LIST_DIR}/README.md" DESTINATION ${CMAKE_INSTALL_DOCDIR})
- install(FILES argh-config.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/argh)
- install(EXPORT arghTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/argh)
-else()
- install(FILES "${CMAKE_CURRENT_LIST_DIR}/argh.h" DESTINATION include)
- install(FILES "${CMAKE_CURRENT_LIST_DIR}/LICENSE" DESTINATION license)
- install(FILES "${CMAKE_CURRENT_LIST_DIR}/README.md" DESTINATION .)
- install(FILES argh-config.cmake DESTINATION CMake)
- install(EXPORT arghTargets DESTINATION CMake)
+
+ if(CMAKE_SYSTEM_NAME STREQUAL Linux)
+ # this might be a bit too restrictive, since for other (BSD, ...) this might apply also
+ # but this can be fixed later in extra pull requests from people on the platform
+ install(FILES argh-config.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/argh)
+ install(EXPORT arghTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/argh)
+ else()
+ install(FILES argh-config.cmake DESTINATION CMake)
+ install(EXPORT arghTargets DESTINATION CMake)
+ endif()
endif()
=====================================
README.md
=====================================
@@ -30,6 +30,10 @@ int main(int, char* argv[])
return EXIT_SUCCESS;
}
```
+#### TL;DR Videos
+- [Arguments over Arguments - Adi Shavit - Core C++ 2019](https://youtu.be/hCbEHzDvLno)
+- [Arguments over Arguments, but you already know this... - Adi Shavit - CppCon 2019](https://youtu.be/KkjKkGuQUqU)
+
## Philosophy
Contrary to many alternatives, `argh` takes a minimalist *laissez-faire* approach, very suitable for fuss-less prototyping with the following rules:
@@ -151,43 +155,49 @@ for (auto& param : cmdl.params())
By default, options are assumed to be boolean flags.
When this is not what you want, there are several ways to specify when an option is a parameter with an associated value.
-Specify **`PREFER_PARAM_FOR_UNREG_OPTION`** mode to interpret *any* `<option> <non-option>` as `<parameter-name> <parameter-value>`:
-```cpp
-using namespace argh;
-auto cmdl = parser(argc, argv, parser::PREFER_PARAM_FOR_UNREG_OPTION);
+ 1. Specify **`PREFER_PARAM_FOR_UNREG_OPTION`** mode to interpret *any* `<option> <non-option>` as `<parameter-name> <parameter-value>`:
+ ```cpp
+ using namespace argh;
+ auto cmdl = parser(argc, argv, parser::PREFER_PARAM_FOR_UNREG_OPTION);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-cout << cmdl("--threshold").str() << '\n';
-```
-Pre-register an expected parameter name with `add_param()` (before calling `parse()`):
-```cpp
-argh::parser cmdl;
-cmdl.add_param("threshold"); // pre-register "threshold" as a param: name + value
-cmdl.parse(argc, argv);
-cout << cmdl("threshold").str() << '\n';
-```
-You can also *batch* pre-register multiple options as parameters with `add_params({ ... })`:
-```cpp
-argh::parser cmdl;
-cmdl.add_params({ "-t", "--threshold", "-s", "--scale" }); // batch pre-register multiple params: name + value
-cmdl.parse(argc, argv);
-cout << cmdl("threshold").str() << '\n';
-```
-Since pre-registration has to be done *before* parsing, we might as well just use the ctor:
-```cpp
-argh::parser cmdl({ "-t", "--threshold", "-s", "--scale" }); // batch pre-register multiple params: name + value
-cmdl.parse(argc, argv);
-cout << cmdl("threshold").str() << '\n';
-```
-Use a `=` (with no spaces around it) within the option when *calling* the app:
-```cpp
->> my_app --threshold=42
-42
-```
-
+ cout << cmdl("--threshold").str() << '\n';
+ ```
+
+ 2. Pre-register an expected parameter name with `add_param()` (before calling `parse()`):
+ ```cpp
+ argh::parser cmdl;
+ cmdl.add_param("threshold"); // pre-register "threshold" as a param: name + value
+ cmdl.parse(argc, argv);
+ cout << cmdl("threshold").str() << '\n';
+ ```
+ You may also *batch* pre-register multiple options as parameters with `add_params({ ... })`:
+ ```cpp
+ argh::parser cmdl;
+ cmdl.add_params({ "-t", "--threshold", "-s", "--scale" }); // batch pre-register multiple params: name + value
+ cmdl.parse(argc, argv);
+ cout << cmdl("threshold").str() << '\n';
+ ```
+ _Unregistered_ options will default to boolean flags.
+
+ 3. Since pre-registration has to be done *before* parsing, we might as well just use the ctor:
+ ```cpp
+ argh::parser cmdl({ "-t", "--threshold", "-s", "--scale" }); // batch pre-register multiple params: name + value
+ cmdl.parse(argc, argv);
+ cout << cmdl("threshold").str() << '\n';
+ ```
+
+ 4. Use a `=` with no spaces around it within the option when *calling* the app:
+ ```cpp
+ >> my_app --threshold=42
+ 42
+ ```
+ This will automatically be interpreted as a named parameter-value pair.
+
+
### Tips
- By default, arguments of the form `--<name>=<value>` (with no spaces, one or more dashes), e.g. `--answer=42`, will be parsed as `<parameter-name> <parameter-value>`.
To disable this specify the **`NO_SPLIT_ON_EQUALSIGN`** mode.
-- Specifying the **`SINGLE_DASH_IS_MULTIFLAG`** mode will split a single-hyphen argument into multiple single-character flags (as is common in various POSIX tools).
+- Specifying the **`SINGLE_DASH_IS_MULTIFLAG`** mode, a.k.a _Compound Arguments_, will split a single-hyphen argument into multiple single-character flags (as is common in various POSIX tools).
- When using **`SINGLE_DASH_IS_MULTIFLAG`**, you can still pre-register the last character as a param with the value, such that if we pre-register `f` as a param, `>> myapp -xvf 42` will be parsed with two boolean flags `x` and `v` and a one param `f`=`42`.
- When parsing parameter values as strings that may contain spaces (e.g. `--config="C:\Folder\With Space\Config.ini"`), prefer using `.str()` instead of `>>` to avoid the default automatic whitespace input stream tokenization:
`cout << cmdl({ "-c", "--config" }).str()`.
@@ -220,7 +230,7 @@ Parse the command line using either
`parser(argv);`
### Special Parsing Modes
-Extra flexibility can be added be specifying parsing modes:
+Extra flexibility can be added by specifying parsing modes:
- **`NO_SPLIT_ON_EQUALSIGN`**:
By default, an option of the form `--pi=22/7` will be parsed as a *parameter* `pi` with an associated value `"22/7"`.
By setting this mode, it will be not be broken at the `=`.
@@ -232,7 +242,7 @@ Extra flexibility can be added be specifying parsing modes:
Interpret `<option> <non-option>` as `<parameter-name> <parameter-value>`.
e.g. `myapp --gamma 2.2` will have `gamma` as a parameter with the value "2.2".
- **`SINGLE_DASH_IS_MULTIFLAG`**:
- Splits an option with a *single* dash into separate boolean flags, one for each letter.
+ Splits an option with a *single* dash into separate boolean flags, one for each letter (a.k.a _Compound Arguments_).
e.g. in this mode, `-xvf` will be parsed as 3 separate flags: `x`, `v`, `f`.
### Argument Access
@@ -313,4 +323,6 @@ If you take `argh` as a submodule, then the visible target is `//:argh`.
## Colophon
-I ❤ your feedback. If you found Argh! useful - do Tweet about it to let [me](https://twitter.com/AdiShavit) know. If you found it lacking, please post an [issue](https://github.com/adishavit/argh/issues).
+I ❤ your feedback.
+If you found Argh! useful - do Tweet about it to let [me](https://twitter.com/AdiShavit) know.
+If you found it lacking, please post an [issue](https://github.com/adishavit/argh/issues).
=====================================
argh.h
=====================================
@@ -2,6 +2,7 @@
#include <algorithm>
#include <sstream>
+#include <limits>
#include <string>
#include <vector>
#include <set>
@@ -57,9 +58,9 @@ namespace argh
std::stringbuf* rdbuf() const { return stream_.rdbuf(); }
- // Check the state of the stream.
+ // Check the state of the stream.
// False when the most recent stream operation failed
- operator bool() const { return !!stream_; }
+ explicit operator bool() const { return !!stream_; }
~stringstream_proxy() = default;
private:
@@ -172,8 +173,13 @@ namespace argh
inline void parser::parse(int argc, const char* const argv[], int mode /*= PREFER_FLAG_FOR_UNREG_OPTION*/)
{
+ // clear out possible previous parsing remnants
+ flags_.clear();
+ params_.clear();
+ pos_args_.clear();
+
// convert to strings
- args_.resize(argc);
+ args_.resize(static_cast<decltype(args_)::size_type>(argc));
std::transform(argv, argv + argc, args_.begin(), [](const char* const arg) { return arg; });
// parse line
@@ -202,8 +208,8 @@ namespace argh
argh::parser::SINGLE_DASH_IS_MULTIFLAG & mode && // multi-flag mode
!is_param(name)) // unregistered
{
- std::string keep_param;
-
+ std::string keep_param;
+
if (!name.empty() && is_param(std::string(1ul, name.back()))) // last char is param
{
keep_param += name.back();
@@ -235,7 +241,7 @@ namespace argh
// if 'name' is a pre-registered option, then the next arg cannot be a free parameter to it is skipped
// otherwise we have 2 modes:
- // PREFER_FLAG_FOR_UNREG_OPTION: a non-registered 'name' is determined a flag.
+ // PREFER_FLAG_FOR_UNREG_OPTION: a non-registered 'name' is determined a flag.
// The following value (the next arg) will be a free parameter.
//
// PREFER_PARAM_FOR_UNREG_OPTION: a non-registered 'name' is determined a parameter, the next arg
@@ -256,7 +262,7 @@ namespace argh
{
flags_.emplace(name);
}
- };
+ }
}
//////////////////////////////////////////////////////////////////////////
@@ -367,6 +373,7 @@ namespace argh
return string_stream(optIt->second);
std::ostringstream ostr;
+ ostr.precision(std::numeric_limits<long double>::max_digits10);
ostr << def_val;
return string_stream(ostr.str()); // use default
}
@@ -382,8 +389,9 @@ namespace argh
auto optIt = params_.find(trim_leading_dashes(name));
if (params_.end() != optIt)
return string_stream(optIt->second);
- }
+ }
std::ostringstream ostr;
+ ostr.precision(std::numeric_limits<long double>::max_digits10);
ostr << def_val;
return string_stream(ostr.str()); // use default
}
@@ -406,6 +414,7 @@ namespace argh
if (pos_args_.size() <= ind)
{
std::ostringstream ostr;
+ ostr.precision(std::numeric_limits<long double>::max_digits10);
ostr << def_val;
return string_stream(ostr.str());
}
@@ -428,5 +437,3 @@ namespace argh
registeredParams_.insert(trim_leading_dashes(name));
}
}
-
-
=====================================
argh_tests.cpp
=====================================
@@ -220,6 +220,19 @@ TEST_CASE("Test default value")
val = -1;
CHECK(!(cmdl("c", "bad-default") >> val));
CHECK((-1 == val || 0 == val));
+
+ double pi = 3.1415926535897932384626433832795028841971693993751058209749445;
+ double pi_val = 0;
+ CHECK((cmdl({"-pi, --archimedes-constant"}, pi) >> pi_val));
+ CHECK(pi == pi_val);
+
+ pi_val = 0;
+ CHECK((cmdl("-pi", pi) >> pi_val));
+ CHECK(pi == pi_val);
+
+ pi_val = 0;
+ CHECK((cmdl(argc + 1, pi) >> pi_val));
+ CHECK(pi == pi_val);
}
TEST_CASE("Leading dashed are stripped")
@@ -412,21 +425,21 @@ TEST_CASE("Handles const char versions as expected")
CHECK(2 == cmdl.flags().size());
}
{
- char* argv[] = { "0", "-a", "1", "-b", "2", "3", "4" };
+ const char* argv[] = { "0", "-a", "1", "-b", "2", "3", "4" };
int argc = sizeof(argv) / sizeof(argv[0]);
auto cmdl = parser(argc, argv);
CHECK(5 == cmdl.pos_args().size());
CHECK(2 == cmdl.flags().size());
}
{
- char * const argv[] = { "0", "-a", "1", "-b", "2", "3", "4" };
+ const char* const argv[] = { "0", "-a", "1", "-b", "2", "3", "4" };
int argc = sizeof(argv) / sizeof(argv[0]);
auto cmdl = parser(argc, argv);
CHECK(5 == cmdl.pos_args().size());
CHECK(2 == cmdl.flags().size());
}
{
- char const* const argv[] = { "0", "-a", "1", "-b", "2", "3", "4" };
+ const char* const argv[] = { "0", "-a", "1", "-b", "2", "3", "4" };
int argc = sizeof(argv) / sizeof(argv[0]);
auto cmdl = parser(argc, argv);
CHECK(5 == cmdl.pos_args().size());
@@ -441,22 +454,22 @@ void test(int argc, T&& argv)
auto cmdl = parser(argc, argv);
CHECK(5 == cmdl.pos_args().size());
CHECK(2 == cmdl.flags().size());
-};
+}
TEST_CASE("Handles char** const versions as expected")
{
- char* argv[] = { "0", "-a", "1", "-b", "2", "3", "4" };
+ const char* argv[] = { "0", "-a", "1", "-b", "2", "3", "4" };
int argc = sizeof(argv) / sizeof(argv[0]);
char const * const * const argvp_ccc = argv;
char const * const * argvp_cc0 = argv;
- char * const * const argvp_cc1 = argv;
+ char const * const * const argvp_cc1 = argv;
// char const * * const argvp_cc2 = argv;
// const char * * argvp_c0 = argv;
- char * const * argvp_c1 = argv;
- char * * const argvp_c2 = argv;
+ char const * const * argvp_c1 = argv;
+ char const * * const argvp_c2 = argv;
test(argc, argvp_ccc);
@@ -764,3 +777,18 @@ TEST_CASE("Test size() member function")
CHECK(cmdl.flags().size() == cmdl.size());
}
}
+
+TEST_CASE("Test parse(...) idempotence") {
+ const char* argv_1[] = { "-a", "b", "-c=10", "d", "-f"};
+ const char* argv_2[] = { "-a", "b", "-d=c" };
+ int argc_1 = sizeof(argv_1) / sizeof(argv_1[0]);
+ int argc_2 = sizeof(argv_2) / sizeof(argv_2[0]);
+
+ parser cmdl(argc_1, argv_1);
+ cmdl.parse(argc_2, argv_2);
+
+ CHECK(std::multiset<std::string>{ "a" } == cmdl.flags());
+ CHECK(std::vector<std::string>{ "b" } == cmdl.pos_args());
+ CHECK(std::map<std::string, std::string>{ { "d", "c" } } == cmdl.params());
+}
+
View it on GitLab: https://salsa.debian.org/med-team/argh/-/commit/366ab5825ba4f7e39e57a48700542aef581e0145
--
View it on GitLab: https://salsa.debian.org/med-team/argh/-/commit/366ab5825ba4f7e39e57a48700542aef581e0145
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20220515/4fd1b148/attachment-0001.htm>
More information about the debian-med-commit
mailing list