Подтвердить что ты не робот

Как реализовать подкоманды с помощью Boost.Program_options?

Я хотел бы реализовать подкоманды в моей программе. Мне также нужна возможность иметь разные аргументы для разных подкоманд. Какой лучший способ сделать это с помощью Boost.Program_options?

Подкоманды используются в таких программах, как svn, git и apt-get.

Например, в git некоторые из доступных подкоманд:

git status  
git push  
git add  
git pull  

Мой вопрос в основном такой же, как у этого парня: http://boost.2283326.n4.nabble.com/subcommands-with-program-options-like-svn-command-td2585537.html

4b9b3361

Ответ 1

Если я правильно понял проблему, вы хотите проанализировать параметры командной строки в следующем виде:

[--generic-option ...] cmd [--cmd-specific-option ... ] 

Вот мое примерное решение. Для ясности я буду опускать любой код проверки, но, надеюсь, вы можете увидеть, как он будет добавлен довольно просто.

В этом примере у нас есть подкоманда "ls" и, возможно, другие. Каждая подкоманда имеет некоторые конкретные параметры, и, кроме того, существуют общие варианты. Поэтому давайте начнем с разбора общих опций и имени команды.

po::options_description global("Global options");
global.add_options()
    ("debug", "Turn on debug output")
    ("command", po::value<std::string>(), "command to execute")
    ("subargs", po::value<std::vector<std::string> >(), "Arguments for command");

po::positional_options_description pos;
pos.add("command", 1).
    add("subargs", -1);

po::variables_map vm;

po::parsed_options parsed = po::command_line_parser(argc, argv).
    options(global).
    positional(pos).
    allow_unregistered().
    run();

po::store(parsed, vm);

Обратите внимание, что мы создали единую позиционную опцию для имени команды и несколько параметров позиционирования для параметров команды.

Теперь мы перейдем к соответствующему имени команды и снова проанализируем. Вместо передачи в исходных argc и argv мы переходим к нераспознанным параметрам в виде массива строк. Функция collect_unrecognized может обеспечить это - все, что нам нужно сделать, это удалить имя (positional) команды и повторно проанализировать с помощью соответствующего options_description.

std::string cmd = vm["command"].as<std::string>();
if (cmd == "ls")
{
    // ls command has the following options:
    po::options_description ls_desc("ls options");
    ls_desc.add_options()
        ("hidden", "Show hidden files")
        ("path", po::value<std::string>(), "Path to list");

    // Collect all the unrecognized options from the first pass. This will include the
    // (positional) command name, so we need to erase that.
    std::vector<std::string> opts = po::collect_unrecognized(parsed.options, po::include_positional);
    opts.erase(opts.begin());

    // Parse again...
    po::store(po::command_line_parser(opts).options(ls_desc).run(), vm);

Обратите внимание, что мы использовали тот же variables_map для параметров, специфичных для команды, как и для общих. Из этого мы можем выполнить соответствующие действия.

Здесь фрагменты кода взяты из компилируемого исходного файла, который включает некоторые модульные тесты. Вы можете найти его на gist здесь. Пожалуйста, не стесняйтесь загружать и играть с ним.

Ответ 2

Вы можете взять имя подкоманды из командной строки с помощью позиционных опций - см. этот учебник.

Кажется, что нет никакой встроенной поддержки подкоманд - вам нужно установить опцию allow_unregistered вверху -level parser, найдите имя команды, а затем запустите ее через второй парсер, чтобы получить какие-либо параметры подкоманды.