2016-06-23 3 views
2

Я хотел бы создать префиксную программу, такую ​​как strace с использованием Boost.Program_options. Префикс означает, что моя программа помещается перед другим произвольным command [args]. Следовательно, моя программа должна принять несколько ключевых аргументов/флагов, которые определены. Первый позиционный аргумент указывает на команду, которую я префикс. За этой командой может следовать любая комбинация параметров, которые я не знаю, и может пересекаться с параметрами моей программы. Поэтому это первый позиционная аргумент и все, что приходит после того, как он должен в конечном итоге в std::vector<std::string>:Создайте префиксную команду с Boost.Program_options

./foo --bar 13 command1      # Should run fine 
./foo command2 positional     # Should run fine 
./foo --bar 13 command3 --unknown argument # Should run fine 
./foo --unknown command4      # should fail 
./foo --bar 13 command5 --bar 42    # Should work but set bar to 13 
./foo command6 --bar 42      # Should not set bar at all 
./foo --bar 13 -- command7 --bar 42 --unknown argument  # Should work 

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

я попробовал два подхода:

1) Использование allow_unregistered:

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

namespace po = boost::program_options; 

int main(int argc, const char** argv) 
{ 
    int bar = 0; 
    po::options_description desc("Allowed options"); 

    desc.add_options() 
      ("bar", po::value(&bar), "bar"); 


    po::variables_map vm; 
    po::parsed_options parsed = 
     po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); 
    po::store(parsed, vm); 
    po::notify(vm); 

    auto command = po::collect_unrecognized(parsed.options, po::include_positional); 
    std::cout << "bar: " << bar << ", command:"; 
    for (const auto& c : command) std::cout << " " << c; 
    std::cout << std::endl; 
} 

Это не выполняется для команд 4,5,6

2) Один из позиционных вариантов с неограниченным числом вхождений

std::vector<std::string> command; 

desc.add_options() 
     ("bar", po::value(&bar), "bar") 
     ("command", po::value(&command)); 

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

po::variables_map vm; 
po::parsed_options parsed = 
    po::command_line_parser(argc, argv).options(desc).positional(p).run(); 
po::store(parsed, vm); 
po::notify(vm); 

Это не выполняется для команд 3,5,6.

+0

Просьба описать более подробно, как это будет работать, и какие комбинации должны быть разрешены и не разрешены, из этих 7 примеров не ясно, – alexeykuzmin0

+0

@ alexeykuzmin0, пожалуйста, см. Мое обновление: «Префикс означает, что моя программа ставится перед другим произвольным 'command [args]'. Следовательно, моя программа должна принимать несколько аргументов/флагов ключевого слова, которые определены. Первый позиционный аргумент указывает на команду, которую я префикс. Эта команда сама может следовать за любой комбинацией параметров, которые я делаю не знаю и может пересекаться с параметрами моей программы. Поэтому этот первый позиционный аргумент и все, что приходит после него, должно заканчиваться на 'std :: vector '. Примеры каждого представляют собой конкретные угловые случаи. – Zulan

+0

Могут ли аргументы содержать пробелы? В таком случае аргументы помещаются в «"? – alexeykuzmin0

ответ

2

Для этого на Boost Trac есть функция, включающая исправления: https://svn.boost.org/trac/boost/ticket/6991. В билете не так много движения, но патч по-прежнему применяется чисто для Boost (начиная с версии 1.61.0, последней версии).

Если ваша система сборки позволяет это, вы можете применить патч к своей локальной копии Boost; в противном случае вы могли бы извлечь boost::program_options::detail::cmdline от cmdline.hpp, detail/cmdline.hpp и cmdline.cpp, в свое собственное пространство имен, исправить этот компонент и использовать ваш исправленный компонент вместо boost::program_options::cmdline.

Еще один вариант взломать поведение boost::program_options::detail::cmdline, используя свой параметр extra_style_parser:

po::detail::cmdline cmdline(argc, argv); 
cmdline.set_options_description(desc); 
cmdline.set_positional_options(p); 
std::vector<po::detail::cmdline::style_parser> style_parsers{ 
    [&](auto& args) { return cmdline.parse_long_option(args); }, 
    [&](auto& args) { return cmdline.parse_short_option(args); }}; 
cmdline.extra_style_parser([&](std::vector<std::string>& args) { 
    auto const current_size = args.size(); 
    std::vector<po::option> result; 
    for (auto const& parser : style_parsers) { 
     auto const next = parser(args); 
     result.insert(result.end(), next.begin(), next.end()); 
     if (args.size() != current_size) 
      return result; 
    } 
    if (args.size() && args[0] != "--") args.insert(args.begin(), "--"); 
    auto const next = cmdline.parse_terminator(args); 
    result.insert(result.end(), next.begin(), next.end()); 
    return result; 
}); 
po::parsed_options parsed{&desc}; 
parsed.options = cmdline.run(); 
po::store(parsed, vm); 
po::notify(vm); 

Example. Предупреждение: это взлом с недокументированными внутренними библиотеками и может прерываться в любое время.

+0

Похоже, это именно то, что мне нужно. Грустно видеть, что этот патч никогда не снимался. Я посмотрю, будет ли это работать для меня. – Zulan

Смежные вопросы