Search code examples
c++boostboost-program-options

boost::program_options reports no error when unexpected positional argument is specified


Here is a simple program using boost to parse options:

#include <iostream>
#include <boost/program_options.hpp>

namespace po = boost::program_options;

int main(int argc, char **argv) 
{
    try
    {
        size_t param = std::numeric_limits<size_t>::max();

        po::options_description desc("Syntax: [options] \"input binary file\".\nAllowed options:");
        desc.add_options()
            ("help,h", "produce help message")
            ("param,p", po::value<size_t>(&param), "param");

        po::variables_map vm;
        po::store(po::parse_command_line(argc, argv, desc), vm);
        po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
        po::notify(vm);

        if (vm.count("help")) 
        {
            std::cout << desc << "\n";
        }
        else
        {
            std::cout << "Running with param " << param << std::endl;
            return 0;
        }
    }
    catch(std::exception& e) {
        std::cerr << "error: " << e.what() << "\n";
    }
    catch(...) {
        std::cerr << "Exception of unknown type!\n";
    }
    return 1;
}

Here are the outputs produced:

  • hex2txt.exe outputs Running with param 0
  • hex2txt.exe --param 3 outputs Running with param 3
  • hex2txt.exe --toto outputs error: unrecognised option '--toto'

All this is expected, however: hex2txt.exe foo outputs Running with param 0

I would have expected to get an error as "foo" is not expected. What am I doing wrong here?


Solution

  • Positionals are accepted by default. You could either check that you received none, or you can specify that you don't allow any:

    po::positional_options_description positionals;
    po::store(po::command_line_parser(args.size(), args.data())
                    .options(desc)
                    .positional(positionals)
                    .run(),
    

    DEMO

    Live On Coliru

    #include <boost/program_options.hpp>
    #include <iostream>
    #include <iomanip>
    
    namespace po = boost::program_options;
    
    int main() {
        std::vector<char const*> const cases[] = {
            { "hex2txt.exe" }, // outputs Running with param 0
            { "hex2txt.exe", "--param", "3" }, // outputs Running with param 3
            { "hex2txt.exe", "--toto" }, // outputs error: unrecognised option '--toto'
            // All this is expected, however:
            { "hex2txt.exe", "foo" }, // outputs Running with param 0
        };
    
        for (auto args : cases) {
            std::cout << "------";
            for (auto arg : args)
                std::cout << " " << std::quoted(arg);
            std::cout << "\n";
    
            try {
                size_t param = 0; // std::numeric_limits<size_t>::max();
    
                po::options_description desc(
                    "Syntax: [options] \"input binary file\".\nAllowed options:");
                desc.add_options()("help,h", "produce help message")(
                    "param,p", po::value<size_t>(&param), "param");
    
                po::positional_options_description positionals;
    
                po::variables_map vm;
                po::store(po::command_line_parser(args.size(), args.data())
                        .options(desc)
                        .positional(positionals)
                        .run(),
                    vm);
                po::notify(vm);
    
                if (vm.count("help")) {
                    std::cout << desc << "\n";
                } else {
                    std::cout << "Running with param " << param << std::endl;
                    //return 0;
                }
            } catch (std::exception const& e) {
                std::cerr << "error: " << e.what() << "\n";
            } catch (...) {
                std::cerr << "Exception of unknown type!\n";
            }
        }
    }
    

    Prints

    ------ "hex2txt.exe"
    Running with param 0
    ------ "hex2txt.exe" "--param" "3"
    Running with param 3
    ------ "hex2txt.exe" "--toto"
    error: unrecognised option '--toto'
    ------ "hex2txt.exe" "foo"
    error: too many positional options have been specified on the command line