4

I'm writing a program using Boost's program_options library. Now, I want to allow it to extend with arbitrary code, which the configuration parser is not aware of - but which would still get some specific options passed to it.

My idea was to somehow pass it a key-value map, possibly even a program_options::variable_map . The thing is, program_options needs to know which options to expect in advance, I can't directly a map with the keys I like.

So, I was thinking maybe I could get program_options to accept arbitrary key-value pairs with string keys (if necessary, string values), put those in some map from string to either string or std::experimental::any, and pass that onwards.

To be more concrete, I'll give an example (although it doesn't have to be quite like this exactly). I would write:

$ magic_app --key1 val1 --key2 val2 --key3 val3 positional1 positional2

and suppose program_options knows about key2 but not about key1 or key3. Then it will...

  • parse key2,
  • create a map containins two keys, key1 and key3, with values val1 and val2 respectively (say string values), and
  • parse the positional arguments positional1 and positional2.

So that the app can pass on the map (perhaps after some transformation) to another component with its own argument processor.

Is this doable? Is there a simpler/better alternative I could use with boost::program_options?

Notes:

  • Somewhat related to this question, which could serve as a crude implementation with some post-parsing - keys will be odd elements in the list, values will be the even elements.
  • The user must be able to specify the options unknown to program_options just like all other options.
Community
  • 1
  • 1
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • Can you provide an example (code or pseudo-code) of what you want to do? – rhashimoto Feb 12 '16 at 16:59
  • The main point of Boost.ProgramOptions is to be able for it detect if the user entered the wrong keys. You basically just want a program option *lexer*, which breaks the options down into tokens that you will process and decide which are valid. – Nicol Bolas Feb 13 '16 at 23:38

2 Answers2

3

You can define a string option that can be given multiple times...

( 
  "kvp",
  boost::program_options::value< std::vector< std::string > >(),
  "key-value pair"
)

...and then give that option as often as you like:

--kvp key1:val1 --kvp key2:val2

At that point, you have your key-value pairs as strings in a vector, which should be easy enough to parse.

if ( vm.count( "kvp" ) )
{
    std::vector< std::string > kvps = vm["kvp"].as< std::vector< std::string > >();

    for ( auto & kvp : kvps )
    {
        // kvp is one key-value pair
    }
}
DevSolar
  • 67,862
  • 21
  • 134
  • 209
1

Lots of options to choose from:

theProgram.exe --unknown_key_values "key1:value1 key2:value2 ..."

Tokenize on blanks and then on ":" to get your key value pairs.

theProgram.exe --unknown_key_values "--key1 value1 --key2 value2 ..."

and pass the string into a second program_options parser that knows the keys expected

theProgram.exe --key key1 --value value1 --key key2 --value value2 ...

which will give you two string vectors with each key and its value in corresponding indices.

theProgram.exe --key1 value1 --key2 value2 ...

If key1 etc are unknown you will get an exception from the parser which you can catch and handle the raw string. If you hace a mixture of known and unknown keys, you will have to handle each unknown key ( storing it and stripping it out of the command line ) then loop around to process the remaining keys until you do not get an exception

ravenspoint
  • 19,093
  • 6
  • 57
  • 103
  • Ah, no. It's important that the user specify these options just as if they were regular program options. S/he can also specify them in a config file, which `program_options` supports, and I certainly do not want the config file to look like that. – einpoklum Feb 12 '16 at 17:44