cpp-hocon 0.3.0
Loading...
Searching...
No Matches
program_options.hpp
1#pragma once
2
3#include "config.hpp"
4#include "config_list.hpp"
5
6#include <boost/format.hpp>
7#include <boost/program_options.hpp>
8
9namespace hocon { namespace program_options {
10 namespace po = boost::program_options;
11
12 template<class charT>
13 po::basic_parsed_options<charT>
14 parse_hocon(shared_config cfg, const po::options_description& desc, bool allow_unregistered) {
15 po::parsed_options result(&desc);
16
17 std::map<std::string, shared_config> to_do;
18 to_do.emplace("", cfg);
19
20 while (!to_do.empty()) {
21 auto iter = to_do.begin();
22 auto prefix = iter->first;
23 auto cfg = iter->second;
24 to_do.erase(iter);
25
26 for (const auto& entry : cfg->entry_set()) {
27 po::option opt;
28 if (prefix.empty()) {
29 opt.string_key = entry.first;
30 } else {
31 opt.string_key = prefix + "." + entry.first;
32 }
33
34 // Skips options that are not registered in the description.
35 // This is different behavior than the built in program_options
36 // parsers, which pass the options along somehow. But for now
37 // it stops an exception from being thrown if there is an unknown
38 // item in the config file.
39 if (allow_unregistered && !desc.find_nothrow(opt.string_key, false)) {
40 continue;
41 }
42
43 if (entry.second->value_type() == config_value::type::LIST) {
44 // if this is a list, we want to check if any of the entries are
45 // objects. If so, we need to further expand those sub-trees, with
46 // list indices being expanded into our key
47
48 auto list = std::dynamic_pointer_cast<const config_list>(entry.second);
49 for (size_t i = 0; i < list->size(); ++i) {
50 const auto& value = list->get(i);
51 if (value->value_type() == config_value::type::LIST ||
52 value->value_type() == config_value::type::OBJECT) {
53 boost::throw_exception(po::invalid_config_file_syntax(list->transform_to_string(), po::invalid_syntax::unrecognized_line));
54 } else {
55 opt.value.push_back(value->transform_to_string());
56 }
57 }
58 } else {
59 opt.value.push_back(entry.second->transform_to_string());
60 }
61 if (!opt.value.empty()) {
62 result.options.emplace_back(std::move(opt));
63 }
64 }
65 }
66
67 // let Boost convert our utf-8 entries to wchars if needed
68 return po::basic_parsed_options<charT>(result);
69 }
70
71 template<class charT>
72 po::basic_parsed_options<charT>
73 parse_file(std::basic_string<charT> file_basename, const po::options_description& desc, bool allow_unregistered=false) {
74 shared_config cfg = config::parse_file_any_syntax(file_basename)->resolve();
75 return parse_hocon<charT>(cfg, desc, allow_unregistered);
76 }
77
78 template<class charT>
79 po::basic_parsed_options<charT>
80 parse_string(std::basic_string<charT> s, const po::options_description& desc, bool allow_unregistered=false) {
81 shared_config cfg = config::parse_string(s)->resolve();
82 return parse_hocon<charT>(cfg, desc, allow_unregistered);
83 }
84}}
static shared_config parse_file_any_syntax(std::string file_basename, config_parse_options options)
Parses a file with a flexible extension.
static shared_config parse_string(std::string s, config_parse_options options)
Parses a string (which should be valid HOCON or JSON by default, or the syntax specified in the optio...
Factory for creating config_document instances.
Definition: config.hpp:18