7

I use boost.program_options library. Consider this simplified case.

po::options_description desc("Usage");
desc.add_options()
("uninstall,u", "uninstall program")
("custom,c", po::wvalue<std::wstring>(), "specify custom action");

po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);

I want to produce error on such command-line:

testprog.exe -u c- action1

Note, user made a typo "c-" instead of "-c". But the parser understands this as a single -u option. How do I handle such cases?

user10101
  • 1,704
  • 2
  • 20
  • 49

3 Answers3

4

I want to produce error on such command-line:

testprog.exe -u c- action1

Note, user made a typo "c-" instead of "-c". But the parser understands this as a single -u option. How do I handle such cases?

Instruct the program_options library to accept no positional arguments and you get the desired behavior

code & compile:

macmini:stackoverflow samm$ cat po.cc
#include <boost/program_options.hpp>
#include <boost/version.hpp>

#include <iostream>

int
main(int argc, char* argv[])
{
    namespace po = boost::program_options;
    po::options_description desc("Usage");
    desc.add_options()
        ("uninstall,u", "uninstall program")
        ("custom,c", po::wvalue<std::wstring>(), "specify custom action")
        ;

    po::variables_map vm;
    po::command_line_parser cmd_line( argc, argv );
    cmd_line.options( desc );
    cmd_line.positional( po::positional_options_description() );

    try {
        po::store( cmd_line.run(), vm );

        po::notify(vm);
    } catch ( const std::exception& e ) {
        std::cerr << e.what() << std::endl;
        return -1;
    }

    return 0;
}
macmini:stackoverflow samm$ g++ po.cc -I /opt/local/include -L/opt/local/lib -lboost_program_options -Wl,-rpath,/opt/local/lib

run:

macmini:stackoverflow samm$ ./a.out -u c- action1
too many positional options
macmini:stackoverflow samm$ ./a.out -u -c action1
macmini:stackoverflow samm$ 
Sam Miller
  • 23,808
  • 4
  • 67
  • 87
2

Compare argc-1 to the number of arguments found by program_options? If it doesn't match, there is a syntax error.

It won't catch all cases but it may catch those important to you.

0

I think the only way you can do this is to ensure that each argument you require is present, for example by testing the count of each type.

if (vm.count("uninstall")) { ... }
if (vm.count("custom")) { ... }

You can generate an error if the options you require are not present (i.e. count is 0) or are present (for example -u and -c cannot be specified would be count of both is >0).

Nim
  • 33,299
  • 2
  • 62
  • 101
  • -c option is optional. User may specify a single -u option or both -u and -c options. The problem is if user make the above typo the library treats command line as if there is a single parameter and program may do something unexpected for him or her. – user10101 Oct 25 '11 at 12:22
  • in this case then you have no choice but to somehow validate the arguments, so if `-u` is provided, check the passed in argument matches what you require before taking action. AFAIK, there is no other way - to account for user error.... – Nim Oct 25 '11 at 12:32
  • -u option is registered as option without values. So if I try to validate arguments passed in then boost::bad_any_cast exception is thrown. std::wstring value = vm["custom"].as(); – user10101 Oct 25 '11 at 12:39
  • Normally with something like this (esp something that sounds like uninstall), it's always worth double checking with the user ("are you *sure* you want to uninstall?") If that was an error, this allows the users to stop the action. In the case of `custom`, the validation exception should be caught and the appropriate usage message displayed. This is what I mean by validating user input. – Nim Oct 25 '11 at 12:49
  • I agree with you that it is worth to prompt user before proceeding. On the other hand, the description of -u and -u + -c actions looks similar and he/she may not spot the difference. Also bad_any_cast exception is _always_ raised for -u option because it is registered as option without values. So I don't see any sense to catch it. – user10101 Oct 25 '11 at 13:04