[program_options] patch - optional argument support (gnu getopt_long style)
Attached is a patch to program_options that implements optional argument support, in the style of GNU getopt_long. It adds one new method to 'value_type': 'implicit_value()'. The idea is that, if the option is given without an argument, it is assigned an "implicit" value. Otherwise, if the long-option is given an explicit argument via the equals sign (--arg=value), or the short-option is given an adjacent argument (-avalue), the explicit value will override the implicit one. For example: desc.add_options() ("proxy,p", value<int>(&proxy_port)->implicit_value(DefaultProxyPort), "run proxy service") ; ... if (vm.count("proxy")) enable_the_proxy(proxy_port); ./prog --proxy --opt2 --opt3 -> enables proxy on default port. ./prog --proxy=9000 --opt2 --opt3 -> enables proxy on port 9000. ./prog --opt2 --opt3 -> does not enable the proxy. -Bryan
Very useful to me, thanks! I'm guessing that the implicit_value is distinct from the default_value, so that the default can be set seperately if the option is completely absent from the command line? My worry would be explaining the different command line syntax for applications with this type of option to my users, but I understand why it is necessary. Vladimir, will you be merging this? Does it need to be posted to the developers list instead? Steven Bryan Green wrote:
Attached is a patch to program_options that implements optional argument support, in the style of GNU getopt_long. It adds one new method to 'value_type': 'implicit_value()'. The idea is that, if the option is given without an argument, it is assigned an "implicit" value. Otherwise, if the long-option is given an explicit argument via the equals sign (--arg=value), or the short-option is given an adjacent argument (-avalue), the explicit value will override the implicit one.
For example: desc.add_options() ("proxy,p", value<int>(&proxy_port)->implicit_value(DefaultProxyPort), "run proxy service") ; ... if (vm.count("proxy")) enable_the_proxy(proxy_port);
./prog --proxy --opt2 --opt3 -> enables proxy on default port. ./prog --proxy=9000 --opt2 --opt3 -> enables proxy on port 9000. ./prog --opt2 --opt3 -> does not enable the proxy.
-Bryan
------------------------------------------------------------------------
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On Tue, Jul 24, 2007 at 09:02:02AM +0100, Steven Mackenzie wrote:
Very useful to me, thanks!
I'm guessing that the implicit_value is distinct from the default_value, so that the default can be set seperately if the option is completely absent from the command line?
That is the idea. I just tested it, and it appears to work as expected.
My worry would be explaining the different command line syntax for applications with this type of option to my users, but I understand why it is necessary.
Hmm, perhaps you could look at the getopt_long manpage for inspiration. I'm not sure how great my 'name()' method is for generating the usage statement. Ideas welcome. -Bryan
Steven Mackenzie wrote:
Very useful to me, thanks!
I'm guessing that the implicit_value is distinct from the default_value, so that the default can be set seperately if the option is completely absent from the command line?
Heh, that's what I referred to in some previous discussion -- we kinda have *two* different default values, which can be confusing. - Volodya
Bryan Green wrote:
Attached is a patch to program_options that implements optional argument support, in the style of GNU getopt_long. It adds one new method to 'value_type': 'implicit_value()'. The idea is that, if the option is given without an argument, it is assigned an "implicit" value. Otherwise, if the long-option is given an explicit argument via the equals sign (--arg=value), or the short-option is given an adjacent argument (-avalue), the explicit value will override the implicit one.
Hi Bryan,
thanks for the patch. I have some comments about it:
1. I'd appreciate doxygen comments for the 'implicit_value'
methods you've added, so that generated docs say something
about those.
2. In value_semantics.hpp, you have this:
- if (!m_default_value.empty() && !m_default_value_as_text.empty()) {
+ if (!m_implicit_value.empty() && !m_implicit_value_as_text.empty()) {
+ return "[=arg] (=" + m_implicit_value_as_text + ")";
+ }
So apparently, if implicit value is provided, the default value is
not shown? Is this intended, and why is this good?
3. In this code:
void
typed_value
Vladimir Prus writes:
Bryan Green wrote:
Attached is a patch to program_options that implements optional argument support, in the style of GNU getopt_long. It adds one new method to 'value_type': 'implicit_value()'.
2. In value_semantics.hpp, you have this:
- if (!m_default_value.empty() && !m_default_value_as_text.empty()) { + if (!m_implicit_value.empty() && !m_implicit_value_as_text.empty()) { + return "[=arg] (=" + m_implicit_value_as_text + ")"; + }
So apparently, if implicit value is provided, the default value is not shown? Is this intended, and why is this good?
Well, the assumption I'm making is that when using an implicit argument, the default argument (if given) is not of interest to the user, but is just a convenience to the programmer, since it makes the 'vm.count("arg")' test unnecessary. In general, it seems that the "default value" is fairly implicit given the context of the option - it usually means "don't do anything in this regard". However, I suppose the library is more flexible if such an assumption was not made. I'll try the alternative in an updated patch. Just to provide some real world examples, for context:
From GNU sed:
-i[SUFFIX], --in-place[=SUFFIX] edit files in place (makes backup if extension supplied)
From GNU rm:
--interactive[=WHEN] prompt according to WHEN: never, once (-I), or always (-i). Without WHEN, prompt always
From GNU uniq:
-D, --all-repeated[=delimit-method] print all duplicate lines delimit-method={none(default),prepend,separate} Delimiting is done with blank lines. The color option for GNU ls: --color[=WHEN] control whether color is used to distinguish file types. WHEN may be `never', `always', or `auto' ... The man page then goes into detail at the end of the section: By default, color is not used to distinguish types of files. That is equivalent to using --color=none. Using the --color option without the optional WHEN argument is equivalent to using --color=always. With --color=auto, color codes are output only if standard output is con- nected to a terminal (tty). The environment variable LS_COLORS can influence the colors, and can be set easily by the dircolors command. Regards, Bryan
Vladimir Prus writes:
5. For + // A value is optional if min_tokens == 0, but max_tokens > 0. + // If a value is optional, it must appear in opt.value (because + // it was 'adjacent'. Otherwise, remove the expectation of a + // non-adjacent value. + if (min_tokens == 0 && max_tokens > 0 && opt.value.empty()) + --max_tokens; +
what will happen if in future, there's some option that accepts [0,10] tokens. Your code will make it access [0,9] tokens, IIUC. Maybe you should explicitly check for max_tokens == 1?
My intuition was that it is not possible to have an option that accepted [0,10] arguments without raising ambiguities, unless it used an extension to the implicit_argument format. When checking how 'multi_token' worked, I found that it in fact doesn't work (ticket #1132). The extension I envision would use commas as delimiters, such as: --do-something=again,and_again,with_feeling_this_time Under special circumstances, I can see a way to eliminate the ambiguity in multitoken - you just need a unique marker indicating the end of the option: either the leading '-' of the next option, or EOL, or some user-defined delimiter that identified the beginning of positional parameters. If such a future possibility is preferable over the suggested implicit_argument method for multiple tokens, I'd be happy to change the check to be (max_tokens == 1). Regards, Bryan
Bryan Green wrote:
Vladimir Prus writes:
5. For + // A value is optional if min_tokens == 0, but max_tokens > 0. + // If a value is optional, it must appear in opt.value (because + // it was 'adjacent'. Otherwise, remove the expectation of a + // non-adjacent value. + if (min_tokens == 0 && max_tokens > 0 && opt.value.empty()) + --max_tokens; +
what will happen if in future, there's some option that accepts [0,10] tokens. Your code will make it access [0,9] tokens, IIUC. Maybe you should explicitly check for max_tokens == 1?
My intuition was that it is not possible to have an option that accepted [0,10] arguments without raising ambiguities, unless it used an extension [to the implicit_argument format. When checking how 'multi_token' worked, I found that it in fact doesn't work (ticket #1132).
Yea, it's broken now.
The extension I envision would use commas as delimiters, such as:
--do-something=again,and_again,with_feeling_this_time
Under special circumstances, I can see a way to eliminate the ambiguity in multitoken - you just need a unique marker indicating the end of the option: either the leading '-' of the next option, or EOL, or some user-defined delimiter that identified the beginning of positional parameters.
If such a future possibility is preferable over the suggested implicit_argument method for multiple tokens, I'd be happy to change the check to be (max_tokens == 1).
I'm presently thinking that multitoken option should stop on any token that looks like an option. That includes "--" -- which can be used to terminate the list of options and start positional options. So yes, I think max_tokens == 1 will be right now for. - Volodya
Regards, Bryan
Vladimir Prus writes:
3. In this code:
void typed_value
::notify(const boost::any& value_store) const { - const T* value = boost::any_cast<const T>(&value_store); + const T* value; + if (value_store.empty()) + value = boost::any_cast<const T>(&m_implicit_value); + else + value = boost::any_cast<const T>(&value_store); if (m_store_to) { *m_store_to = *value; } why value_store can end up being empty? I would expect that the xparse method, in the event that no explicit value is provided, would store m_implicit_value in value_store. The way you do this, it seems that the right value will be stored by 'notify', but the value stored to variables_map will be wrong.
I think you are correct about this.
6. I'd surely appreciate a test ;-)
Do you think you can adjust the patch per above? Clearly, I'd need to code qu estions to be settled before applying this. I'd very much like test/comment changes too, but if you're out of time we can skip them.
I've created a new patch that I think takes all your suggestions into account. I have modified 'example/options_description.cpp' to test it. I also added tests to 'test/variable_map_test.cpp', but I don't know how to compile/run it. The new patch has been added to ticket #1131. Regards, Bryan
Bryan Green wrote:
6. I'd surely appreciate a test ;-)
Do you think you can adjust the patch per above? Clearly, I'd need to code qu estions to be settled before applying this. I'd very much like test/comment changes too, but if you're out of time we can skip them.
I've created a new patch that I think takes all your suggestions into account. I have modified 'example/options_description.cpp' to test it. I also added tests to 'test/variable_map_test.cpp', but I don't know how to compile/run it.
You basically run "bjam" in the libs/program_options/test folder.
The new patch has been added to ticket #1131.
I have applied your patch, thanks! There was a minor issue with the testcase, namely: char* cmdline6_[] = { "--imp=1 -m" }; should have being: char* cmdline6_[] = { "--imp=1", "-m" }; But otherwise there were no problems. Thanks, Volodya
Vladimir Prus writes:
I have applied your patch, thanks! There was a minor issue with the testcase, namely:
char* cmdline6_[] = { "--imp=1 -m" };
should have being:
char* cmdline6_[] = { "--imp=1", "-m" };
But otherwise there were no problems.
Thanks! Bryan
participants (3)
-
Bryan Green
-
Steven Mackenzie
-
Vladimir Prus