[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: CommandLine parser: optional args and callback handlers



On Sun, Jan 22, 2012 at 08:31, Daniel Hartwig <mandyke@gmail.com> wrote:
> * Optional args
>
> Optional args can only be supplied with the "=arg" syntax (otherwise
> it is ambiguous whether what follows is the argument or another
> option).  This is already tracked within 'HandleOpt' by the variable
> 'CertainArg', so the additional required is minimal.
>
> The default value to assign when no argument is present could be specified by:
>  a) a well-known value, e.g. "1" (matches boolean options);
>  b) a class-wide map (LongOpt -> Default);
>  c) a callback handler (see next section);
>  d) a new string member of struct Args; or
>  e) extending Args::LongOpt to permit an optional syntax of "longopt=default".

mhh. Currently the default values of an option are defined at the place they
are used by e.g. Find("Config::Option", true) == false, so it feels a bit
strange to move some default values for optional args now into the Args
struct, while all others are determined at runtime. In that case we should
allow to set default values for other options as well, or?

For me f) would be the addition of a Find("config::option", default, unset)
method. The commandline parser could set the option to an empty value
if he encounters an option with an optional arg which wasn't given on the
commandline. An option can't be set to be 'empty' on the commandline,
so this Find from above could work with the simple ruleset:
If config::option.empty() == false
   return value
else if config::option.empty() == true
   return default
else // if exists(config::option) == false
   return unset;

That's the same behavior as before if we
set unset = default by default ([no] pun intended).

This gives empty a bit of a special meaning, but in the end it closely
resembles what is given on the commandline…


> Side note: does anyone know of any actual uses for the 'prefix'
> semantics of Args::ConfName? (ConfName = "APT::Item PREFIX" would
> prepend "PREFIX" to every value assigned via that option to
> "APT::Item").

More than two years of APT development and i still learn new things…
A quick bzr blame told me that it was added in revision 212 (1999!)
but doesn't indicate any user for it and I at least couldn't find a user now.


> * Callback handlers
>
> These are for non-trival options, for example, aptitude has
> "--without-recommends" which is equivalent to:
>
>  Apt::Install-Recommends "false";
>  Apt::AutoRemove::RecommendsImportant "true";
>
> and "--log-resolver", equivalent to:
>
>  Aptitude::Logging::Levels:: "aptitude.resolver.search:trace";
>  Aptitude::Logging::Levels:: "aptitude.resolver.search.costs:info";
>
> Currently I have a work-around for this:
>  1) option parsing sets a temp. config item
>  2) post-parsing checks for the temp. items and does the real config

I think i have used the some workaround somewhere (but i am not sure),
so you are not alone and we should really find a (better) solution for this.


> It may be just as much effort to convert CommandLine to a wrapper
> around argp or similar, which already has support for callback
> handlers and some other features that would be of use...

argp is interesting, indeed, but i think for APT we should avoid it
as it is glibc specific and APT lowlevel enough to be ported to a lot of
plattforms with different (less fearureful) libc's so we should keep it
relatively easy if possible.


> These options could also be handled by 'chaining' several options together:
>
>  {'R', "without-recommends", "Apt::Install-Recommends", InvBoolean | Chain},
>  {'R', "without-recommends", "Apt::AutoRemove::RecommendsImportant", Boolean},

Chaining feels a bit dirty beside that it solves only this specific case,
so in the longrun a callback as you suggested could really be interesting.

How about a new Callback member for the Args struct which is called in
case the option is parsed and the callback isn't NULL similar to
DispatchArg. If we talk about a boolean for example it would just have the
parameters handle_config_option("config::option", void* -> bool)
That's very few state, but should be easy to implement and enough for chains
and alike and in the end i can't imagine too many uses for a handler who
consumes multiple arguments and would therefore require a global handler,
but even if we would need it we could still add that, too.
A global handler just feels like overkill for chaining two (or more)
options together…


Best regards

David Kalnischkies


Reply to: