Expect a specific order of the provided CLI arguments using boost program_options

68 views Asked by At

Let's assume we have the following boost::program_options-specific options description:

po::options_description main_desc("Usage: my_app [--version] OBJECT { COMMAND | --help }\n"
                                  "OBJECT := { pizza | pasta | drink }\n"
                                  "OPTIONS");
// clang-format off
main_desc.add_options()
("version,v", "Prints the version of the app.")
("help,h", "Prints usage information.");
// clang-format on

and the following parsing related code

variables_map main_vm;
po::parsed_options main_parsed_opt = po::command_line_parser(argc, argv)
                                         .options(main_desc)
                                         .allow_unregistered()
                                         .run();

store(main_parsed_opt, main_vm);

if (main_vm.count("version")) {
    std::cout << "my_app v0.0.1 << std::endl;
    return 0;
}

The question is: How is it possible to check whether the "--version" option got passed as first argument, so that the following invocation isn't supported:

./my_app pizza add --version

I am looking for something similar to this here:

if (main_vm.count("version") && main_vm.position("version") == 1) {
    std::cout << "my_app v0.0.1 << std::endl";
    return 0;
}

I want to make sure, that if the option --version got provided, it got provided as the first argument as indicated by the command-line-semantic

my_app [--version] OBJECT { COMMAND | --help }

Full code:

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

int main(int argc, char *argv[])
{
    try {
        po::options_description main_desc("Usage: my_app [--version] OBJECT { COMMAND | --help }\n"
                                          "OBJECT := { pizza | pasta | drink }\n"
                                          "OPTIONS");
        // clang-format off
        main_desc.add_options()
        ("version,v", "Prints the version of the app.")
        ("help,h", "Prints usage information.");
        // clang-format on

        variables_map main_vm;
        po::parsed_options main_parsed_opt = po::command_line_parser(argc, argv)
                                                 .options(main_desc)
                                                 .allow_unregistered()
                                                 .run();

        store(main_parsed_opt, main_vm);

        if (main_vm.count("version")) {
            std::cout << "my_app v0.0.1 << std::endl" << std::endl;
                return 0;
        }

//      if (main_vm.count("version") && main_vm.position("version") == 1) ) {
//              std::cout << "my_app v0.0.1 << std::endl" << std::endl;  //
//              return 0;
//      }

    } catch (std::exception &e) {
        cout << e.what() << "\n";
    }
}
1

There are 1 answers

0
Degoah On

After digging a bit around, I have found the answer to my question by myself.

The object of type boost::program_options::parsed_options and returned by the method boost::program_options::command_line_parser::run offers the method options. It can be used retrieve a vector of elements of type basic_option<charT>. The order of the elements in the vector corresponds to the order of the command-line arguments. Knowing this, the member basic_option<charT>::string_key can be used to check which option has been provided at which order:

if (main_vm.count("version") && main_parsed_opt.options.at(0).string_key == "version") {
    std::cout << "my_app: v0.0.1" << std::endl;
    return 0;
}

This leads us to the following complete example code:

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

int main(int argc, char *argv[])
{
    try {
        po::options_description main_desc("Usage: my_app [--version] OBJECT { COMMAND | --help }\n"
                                          "OBJECT := { pizza | pasta | drink }\n"
                                          "OPTIONS");
        // clang-format off
               main_desc.add_options()
               ("version,v", "Prints the version of the app.")
               ("help,h", "Prints usage information.");
           // clang-format on

        variables_map main_vm;
        po::parsed_options main_parsed_opt = po::command_line_parser(argc, argv)
                                                 .options(main_desc)
                                                 .allow_unregistered()
                                                 .run();

        store(main_parsed_opt, main_vm);
        
        if (main_vm.count("version") && main_parsed_opt.options.at(0).string_key == "version") {
            std::cout << "my_app: v0.0.1" << std::endl;
            return 0;
        }

    } catch (std::exception &e) {
        cout << e.what() << "\n";
    }
}