Я использую Boost program_options для синтаксического анализа файла конфигурации стандартным образом показанном в файле примеров multiple_sources.cpp файла program_options.
ifstream ini_file("config.ini");
po::store(po::parse_config_file(ini_file, desc, true), vm);
po::notify(vm);
Однако в файле config.ini есть пустые пары key = value, такие как:
key1=value1
key2=value2
key3=
key4=
key5=value5
Попытка прочитать этот файл приводит к ошибке Boost:
boost::program_options::invalid_option_value
Есть ли какой-либо механизм в boost:: program_options для чтения таких файлов конфигурации с пустыми?
Любая помощь будет высоко оценена.
Я редактирую этот вопрос, поскольку проблема еще не решена. Я просто приведу пример из Boost (1.53).
Это полный файл multiple_sources.cpp:
#include <boost/program_options.hpp>
namespace po = boost::program_options;
#include <iostream>
#include <fstream>
#include <iterator>
using namespace std;
// A helper function to simplify the main part.
template<class T>
ostream& operator<<(ostream& os, const vector<T>& v)
{
copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
return os;
}
int main(int ac, char* av[])
{
try {
int opt;
string config_file;
// Declare a group of options that will be
// allowed only on command line
po::options_description generic("Generic options");
generic.add_options()
("version,v", "print version string")
("help", "produce help message")
//("optimization","optimization level")
("config,c", po::value<string>(&config_file)->default_value("multiple_sources.cfg"),
"name of a file of a configuration.")
;
// Declare a group of options that will be
// allowed both on command line and in
// config file
po::options_description config("Configuration");
config.add_options()
("optimization", po::value<int>(&opt)->default_value(10),
"optimization level")
("include-path,I", po::value< vector<string> >()->composing(),
"include path")
;
// Hidden options, will be allowed both on command line and
// in config file, but will not be shown to the user.
po::options_description hidden("Hidden options");
hidden.add_options()
("input-file", po::value< vector<string> >(), "input file")
;
po::options_description cmdline_options;
cmdline_options.add(generic).add(config).add(hidden);
po::options_description config_file_options;
config_file_options.add(config).add(hidden);
po::options_description visible("Allowed options");
visible.add(generic).add(config);
po::positional_options_description p;
p.add("input-file", -1);
po::variables_map vm;
store(po::command_line_parser(ac, av).
options(cmdline_options).positional(p).run(), vm);
notify(vm);
ifstream ifs(config_file.c_str());
if (!ifs)
{
cout << "can not open config file: " << config_file << "\n";
return 0;
}
else
{
store(parse_config_file(ifs, config_file_options), vm);
notify(vm);
}
if (vm.count("help")) {
cout << visible << "\n";
return 0;
}
if (vm.count("version")) {
cout << "Multiple sources example, version 1.0\n";
return 0;
}
if (vm.count("include-path"))
{
cout << "Include paths are: "
<< vm["include-path"].as< vector<string> >() << "\n";
}
if (vm.count("input-file"))
{
cout << "Input files are: "
<< vm["input-file"].as< vector<string> >() << "\n";
}
cout << "Optimization level is " << opt << "\n";
}
catch(exception& e)
{
cout << e.what() << "\n";
return 1;
}
return 0;
}
И соответствующий файл конфигурации (multiple_sources.cfg):
#
# Comment out this line to use hard-coded default value of 10
#
optimization = 1
include-path = /opt
Если этот файл теперь изменен на:
#
# Comment out this line to use hard-coded default value of 10
#
optimization =
include-path = /opt
Выдается следующее сообщение об ошибке:
the argument for option 'optimization' is invalid
Предлагаемые решения с проверкой перегрузки и т.д. кажутся излишне сложными, тем более, что для каждого типа данных может потребоваться написать функцию проверки, включающую возможность распознавания "\n" другого белого пространства.
Любые предложения? Спасибо всем за то, что нашли время.
Следуя предложению Aditya, я заменил следующую строку:
("optimization", po::value<int>(&opt)->default_value(10),
"optimization level")
со следующим:
("optimization", po::value<int>(&opt)->zero_tokens(),
"optimization level")
и:
("optimization", po::value<int>(&opt)->implicit_value(10),
"optimization level")
и ни один из них не читает пустые опции. Пример примера программы "parser_test.cpp" обходит использование zero_tokens() или implicit_value() путем считывания пар ключ-значение в вектор следующим образом:
void test_config_file(const char* config_file)
{
options_description desc;
desc.add_options()
("gv1", new untyped_value)
("gv2", new untyped_value)
("empty_value", new untyped_value)
("plug*", new untyped_value)
("m1.v1", new untyped_value)
("m1.v2", new untyped_value)
("b", bool_switch())
;
const char content1[] =
" gv1 = 0#asd\n"
"empty_value = \n"
"plug3 = 7\n"
"b = true\n"
"[m1]\n"
"v1 = 1\n"
"\n"
"v2 = 2\n"
;
vector<option> a2 = parse_config_file<char>(config_file, desc).options;
BOOST_REQUIRE(a2.size() == 6);
check_value(a2[0], "gv1", "0");
check_value(a2[1], "empty_value", "");
check_value(a2[2], "plug3", "7");
check_value(a2[3], "b", "true");
check_value(a2[4], "m1.v1", "1");
check_value(a2[5], "m1.v2", "2");
}