cpp-hocon  0.3.0
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 
9 namespace 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_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
static shared_config parse_file_any_syntax(std::string file_basename, config_parse_options options)
Parses a file with a flexible extension.