cxxopts
cxxopts copied to clipboard
Conflicts between repeated arguments and vector arguments
Hi,
I have an argument that can be repeated multiple time (let's call it --location). So I declare it as a vector of string.
--location paris --location london
I believe my problem is when there is a comma in the location. I will butcher New Jersey and write it with a comma in it. Now my argument count will be 2, but when I cast to a vector of string the vector size is 3.
--location paris --location new,jersey
In practice we have big json blobs with lots of comma in those options.
Repro program
#include <cxxopts.hpp>
int main(int argc, char * argv[])
{
cxxopts::Options options( "vector_test" );
options.add_options()
("location", "Location", cxxopts::value<std::vector<std::string>>())
;
auto result = options.parse(argc, argv);
auto cnt = result.count("location");
std::cerr << "result.count " << cnt << std::endl;
if (cnt)
{
auto locations = result["location"].as<std::vector<std::string>>();
std::cerr << "locations size " << locations.size() << std::endl;
}
return 0;
}
Results
$ vector_test --location paris --location london
result.count 2
locations size 2
$ vector_test --location paris --location 'new,jersey'
result.count 2
locations size 3
Notice that before 2.2.0 got released with the comma arg separator, I was getting a count of 2 for both. We are using 2.1.2 right now as a workaround.
The comma is used as a separator for writing vector arguments in one option. If comma is an acceptable character you can redefine the separator to something else by #define
ing CXXOPTS_VECTOR_DELIMITER.
Ok, so if we want to disable this feature for having json or anything in one option, maybe a non-printable character would work, such a the nul character, which according to this table is equal to 0 in ascii.
~$ cat foo.cpp
#include <string>
#include <sstream>
#ifndef CXXOPTS_VECTOR_DELIMITER
#define CXXOPTS_VECTOR_DELIMITER ','
#endif
int main()
{
std::stringstream in("caca");
std::string token;
std::getline(in, token, CXXOPTS_VECTOR_DELIMITER);
return 0;
}
But I can't make it work, when passing a macro my compiler wants a printable ascii char.
~$ g++ -DCXXOPTS_VECTOR_DELIMITER=0 foo.cpp
foo.cpp:12:5: error: no matching function for call to 'getline'
std::getline(in, token, CXXOPTS_VECTOR_DELIMITER);
^~~~~~~~~~~~
Should we have an option like CXXOPTS_VECTOR_DELIMITER_NONE to disable that feature ?
template <typename T>
void
parse_value(const std::string& text, std::vector<T>& value)
{
#ifndef CXXOPTS_VECTOR_DELIMITER_NONE
std::stringstream in(text);
std::string token;
while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
T v;
parse_value(token, v);
value.emplace_back(std::move(v));
}
#endif
}
That might be reasonable. Although what happens if you define it to '\0x00'
, or maybe you could use newline?
The first one does not compile, but the newline does compile.
// #define CXXOPTS_VECTOR_DELIMITER '\0x00' #define CXXOPTS_VECTOR_DELIMITER '\n'
Maybe there is even another \ thing that can be used like \a or something really 'invisible'.
On Oct 18, 2020, at 4:54 PM, jarro2783 [email protected] wrote:
That might be reasonable. Although what happens if you define it to '\0x00', or maybe you could use newline?
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jarro2783/cxxopts/issues/262#issuecomment-711442966, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC2O6UOQ5OYBHCM4VMFFPXDSLN52BANCNFSM4STRFCTQ.
You could simply use '\0'
which denotes the zero-byte, i.e. what was probably intended with '\0x00'
.
This should work fine because your command line arguments usually aren't supposed to include zero bytes.
That's a good tip, however I remember trying it and it lead to a compiler error or warning but I should give it another try.
I think the best way in my opinion would be to have a proper (static) function to call to do this, or doing it in the constructor of the option class, as opposed to a preprocessor macro. I hope I can find the time to make a PR for it.
On Nov 1, 2020, at 3:26 AM, Georg Sauthoff [email protected] wrote:
You could simply use '\0' which denotes the zero-byte, i.e. what was probably intended with '\0x00'.
This should work fine because your command line arguments usually aren't supposed to include zero bytes.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jarro2783/cxxopts/issues/262#issuecomment-720073427, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC2O6UIT7QPC64TZVM5GPODSNVAU7ANCNFSM4STRFCTQ.
Yeah I agree that it shouldn't be a preprocessor macro. If you want to do a PR for it then that would be great.