cxxopts icon indicating copy to clipboard operation
cxxopts copied to clipboard

Comma delimiter shouldn't be used for positional arguments

Open equeim opened this issue 5 years ago • 4 comments

If you use cxxopts like this:

std::vector<std::string> files;
cxxopts::Options opts(appName, versionString);
opts.add_options()
    ("files", "", cxxopts::value<std::vector<std::string>>(files));
opts.parse_positional("files");

And call executable like this (notice the quotes): ./foo /home/bar/file_without_comma "/home/bar/file, with comma" files vector will contain three items instead of two, despite presence of quotes.

Of course you can workaround this behaviour, either by defining CXXOPTS_VECTOR_DELIMITER with null character which will also prevent you from using option arguments with delimiters (which is not desirable), or by iterating over ParseResult::arguments() which in this case contains two items with key "files". I, however, feel that this behaviour is unintuitive.

equeim avatar Apr 09 '20 13:04 equeim

Is having commas in your filenames common? The comma is only the default, you can redefine it yourself. I think removing this functionality is also not desirable because people now rely on it.

I might have to look at what other parsers do with this, since a few people were requesting a way to parse a list of arguments by some delimiter at some point, which is why this feature was added.

jarro2783 avatar Apr 19 '20 22:04 jarro2783

It doesn't matter how common this is (although it is quite common in my case, yes), if a program takes filenames as arguments it must process them correctly. On Unix-like systems filenames can contain any characters except '\0', even newlines. Besides, positional arguments are already lists by their very nature, there is simply no need to split them by delimiters. Although I of course understand backwards compatibility concerns.

The problem with redefining CXXOPTS_VECTOR_DELIMITER is that it used to parse all std::vector arguments. What if some cxxopts user wanted to to parse regular list argument, like --foo=42,666 splitted by commas, and to parse positional arguments without special handling for commas in the same program? They would have to either redefine CXXOPTS_VECTOR_DELIMITER and do splitting themselves, or leave CXXOPTS_VECTOR_DELIMITER untouched and iterate over ParseResult::arguments() to get unsplitted positional arguments.

I think the best solution would be to be able to either configure list delimiter per option or simply disable delimiter splitting for select option. I have no idea how hard it would be implement though.

equeim avatar Apr 19 '20 23:04 equeim

Yeah that's a good point. Doing this per argument might be more reasonable.

This isn't just for positional arguments though. It's possible to have some non-positional arguments that can appear multiple times. So instead of writing --arg a --arg b --arg c you can then just write --arg a,b,c.

jarro2783 avatar Apr 20 '20 01:04 jarro2783

Actual usecase in gvfs, in f3d-app/f3d#1044, where a gvfs user uses , in the file path for perfectly valid reasons.

mwestphal avatar Oct 08 '23 17:10 mwestphal