Ответ 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 здесь. Пожалуйста, не стесняйтесь загружать и играть с ним.