Как реализовать подкоманды, используя 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

22

Решение

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

[--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 функция может обеспечить это — все, что нам нужно сделать, это удалить (позиционное) имя команды и повторно проанализировать с соответствующим 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 для специфичных для команды опций как для общих. Из этого мы можем выполнить соответствующие действия.

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

42

Другие решения

Вы можете удалить имя подкоманды из командной строки, используя позиционные варианты — увидеть этот урок.

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

3