|
Boost : |
From: Misha Bergal (mbergal_at_[hidden])
Date: 2003-06-02 05:00:19
I have 2 use cases for program options library. I would say that they are
fairly advanced but nevertheless typical ones:
Due to severe time constraints I am going to describe just the first use
case, which I think will highlight significant number of
boost::program_options benefits and problems .
----------------- USE CASE -----------------------------
1. Program options of Perforce version control "p4" client.
p4 program options come from (in the order of descending priority)
1. Command line
2.standard input
3. config file
4. Windows registry
1. The command line has the general format:
p4 [global-options] <command> [command-options]
where global options are:
-c client
-d dir
-G
-H host
-p port
-P pass
-s
-u user
-x file
-C charset
-L language
-V
-h
and command-options depending on command. For example the command "submit"
has the following possible options
p4 [g-opts] submit [-r] [-s] [files]
p4 [g-opts] submit [-r] -c changelist#
p4 [g-opts] submit -i [-r] [-s]
Please note, that "-c" option has semantic is different between
global-options and command options
2. The arguments can be read directly from the standard input, in this case
they should be separated by newline character.
3. The config file has the structure
P4<KEYWORD>=value
for example, instead of specifying option "-c myclient" in command line,
user can write
P4USER=myclient
4. The "most default" values are stored in Windows registry in format
similar to config file.
----------------- END OF USE CASE -----------------------------
It seems to be important to support the handling of this syntax style,
because:
1. It seems to be very "widespread", meaning the number of people, not
necessarily the number of products.
2. It is structurally complicated enough to break the simplistic
implementation.
I will try to iteratively go through implementation, highlighting the
problems and helpful features, soliciting library author feedback on the
way.
--------- IMPLEMENTATION (PSEUDOCODE) ROUND 1 ------------------
1. Options storage
variable_map go; // global_options
or
struct global_options
{
boost::optional<std::string> client; // Need optional
boost::optional<std::string> dir;
bool pythonize;
bool show_version
....
};
global_options go;
or may be?
lexical_map go; // idea of Aleksey Gurtovoy
2.Describe options
global_options_desc.add_options()
( "c", parameters( "<client>", &go.client ), "some comments here" )
// Problem #1.
// The first parameter is a mini-language. Usually C++ tends to avoid
minilanguages.
// For example: iostreams don't use "w+", "rw", "a", although
iostreams are not always
// the example of practices to follow.
// Still, for users minilanguage might be unexpected here
// Note: need to make sure that parameter can take optional<>
or ( "c", parameters( "<client>" ), "some comments here" ) // store it in
the ..._map later
3. Read - lowest priority first
// 3.1. Read registry and config file
// Problem #2 - the names in the registry and config file are not the same
as the names given in options_description
// actually it seems that the information in options description is
primarily for command line, not for config files.
// --- custom written ---
mtn::copy( config_file( ".p4config" ), inserter( go ) ); // insert options
in go (variables_map, or lexical_map)
// --- end custom written ---
// 3.2. Read command line
// 3.2.1 Separate global options from command options
options_and_arguments oa = parse_command_line(argc, argv, desc);
// Problem #3: Would be nice if options_and_arguments was a sequence
command_options_and_arguments = mtn::find_if( options_and_arguments,
&is_argument );
global_options_and_arguments = mtn::iterator_range(
options_and_arguments.begin(), command.begin() );
// 3.2.2. Find out whether I need to read a rest of arguments from standard
input
// Problem #4: Seems that it is too late to ask boost::program_options to
do that
// May be the arguments need to be read from stdin and the command line
parsed again?
// 3.2.3 Store global_options
store( global_options_and_arguments , go, desc);
or // Problem #5: need to check how to store into struct global_options
{}
// 3.2.4 What command?
std::string command = *command_options_and_arguments.begin();
// 3.2.5 Route to module handling command
modules[ command ].handle_command( command_options_and_arguments );
or modules[ command ].handle_command( slice(
command_options_and_arguments, 1 ) ); //without command itself
// 3.2.5 Handle command in module
handle_command( command_options_and_arguments )
{
// define options_descriptions
store( command_options_and_arguments, desc, command_options );
}
--------- END OF IMPLEMENTATION (PSEUDOCODE) ROUND 1 ------------------
Current problems:
1. Early draft - I might have a limited ubdrestanding of some questions (for
example, composing usage strings from command registrar)
2. No STL conformity - boost::po objects and data structures are hard to
operate with.
3. Need to see how additional storage is supported (lexical_map,
non-container storage)
4. It doesn't seem that library can help with config files in this use case
What is needed:
0 .More sleep :-)
1. Some ideas regarding 2,3,4
2. Produce a working implementation (make it an boost::program_options
example - seems like a significant amount of work, may be not now?).
TO REVIEW MANAGER: Would it be possible to extend the review period for
boost::program_options at least to another weekend?
Misha Bergal
MetaCommunications Engineering
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk