inicpp
C++ parser of INI files with schema validation.
schema.cpp
1 #include "schema.h"
2 
3 namespace inicpp
4 {
6  {
7  }
8 
9  schema::schema(const schema &source)
10  {
11  // we have to do deep copies of section schemas
12  sections_.reserve(source.sections_.size());
13  for (auto &sect : source.sections_) {
14  sections_.push_back(std::make_shared<section_schema>(*sect));
15  }
16 
17  // we already have constructed section schemas... now push them into map
18  for (auto &sect : sections_) {
19  sections_map_.insert(sect_schema_map_pair(sect->get_name(), sect));
20  }
21  }
22 
24  {
25  if (this != &source) {
26  schema new_src(source);
27  std::swap(*this, new_src);
28  }
29 
30  return *this;
31  }
32 
34  {
35  *this = std::move(source);
36  }
37 
39  {
40  if (this != &source) {
41  sections_ = std::move(source.sections_);
42  sections_map_ = std::move(source.sections_map_);
43  }
44 
45  return *this;
46  }
47 
48  void schema::add_section(const section_schema &sect_schema)
49  {
50  auto add_it = sections_map_.find(sect_schema.get_name());
51  if (add_it == sections_map_.end()) {
52  std::shared_ptr<section_schema> add = std::make_shared<section_schema>(sect_schema);
53  sections_.push_back(add);
54  sections_map_.insert(sect_schema_map_pair(add->get_name(), add));
55  } else {
56  throw ambiguity_exception(sect_schema.get_name());
57  }
58  }
59 
61  {
62  auto add_it = sections_map_.find(arguments.name);
63  if (add_it == sections_map_.end()) {
64  std::shared_ptr<section_schema> add = std::make_shared<section_schema>(arguments);
65  sections_.push_back(add);
66  sections_map_.insert(sect_schema_map_pair(add->get_name(), add));
67  } else {
68  throw ambiguity_exception(arguments.name);
69  }
70  }
71 
72  void schema::add_option(const std::string &section_name, const option_schema &opt_schema)
73  {
74  auto sect_it = sections_map_.find(section_name);
75  if (sect_it != sections_map_.end()) {
76  sect_it->second->add_option(opt_schema);
77  } else {
78  throw not_found_exception(section_name);
79  }
80  }
81 
82  size_t schema::size() const
83  {
84  return sections_.size();
85  }
86 
88  {
89  if (index >= sections_.size()) {
90  throw not_found_exception(index);
91  }
92 
93  return *sections_[index];
94  }
95 
96  const section_schema &schema::operator[](size_t index) const
97  {
98  if (index >= sections_.size()) {
99  throw not_found_exception(index);
100  }
101 
102  return *sections_[index];
103  }
104 
105  section_schema &schema::operator[](const std::string &section_name)
106  {
107  std::shared_ptr<section_schema> result;
108  try {
109  result = sections_map_.at(section_name);
110  } catch (std::out_of_range) {
111  throw not_found_exception(section_name);
112  }
113  return *result;
114  }
115 
116  const section_schema &schema::operator[](const std::string &section_name) const
117  {
118  std::shared_ptr<section_schema> result;
119  try {
120  result = sections_map_.at(section_name);
121  } catch (std::out_of_range) {
122  throw not_found_exception(section_name);
123  }
124  return *result;
125  }
126 
127  bool schema::contains(const std::string &section_name) const
128  {
129  try {
130  sections_map_.at(section_name);
131  return true;
132  } catch (std::out_of_range) {
133  return false;
134  }
135  }
136 
137  void schema::validate_config(config &cfg, schema_mode mode) const
138  {
139  /*
140  * Here should be done:
141  * - check if config has proper sections (compare by names) - depends on mode
142  * - for sections with given schema call validate on that section
143  * - sections which are in schema but not in config
144  * will be added to config with all their options
145  */
146 
147  // firstly go through section schemas
148  for (auto &sect : sections_) {
149  bool contains = cfg.contains(sect->get_name());
150 
151  if (contains) {
152  // even if section is not mandatory, we execute validation of section (both modes)
153  sect->validate_section(cfg[sect->get_name()], mode);
154  } else if (sect->is_mandatory()) {
155  // mandatory section is not present in given config (both modes)
156  throw validation_exception("Mandatory section '" + sect->get_name() + "' is missing in config");
157  } else {
158  // section is not mandatory and not in given config
159  // => add section to config and all its options with default values
160  cfg.add_section(sect->get_name());
161  for (size_t i = 0; i < sect->size(); ++i) {
162  auto &opt = sect->operator[](i);
163  cfg.add_option(sect->get_name(), opt.get_name(), opt.get_default_value());
164  }
165  }
166  }
167 
168  // secondly go through sections
169  for (auto &sect : cfg) {
170  bool contains = this->contains(sect.get_name());
171 
172  // if schema contains section everything is fine, we handled this above
173  if (contains) {
174  continue;
175  }
176 
177  // we have strict mode and section which is not in schema
178  if (mode == schema_mode::strict) {
179  throw validation_exception("Section '" + sect.get_name() + "' not specified in schema");
180  }
181  }
182  }
183 
184  std::ostream &operator<<(std::ostream &os, const schema &schm)
185  {
186  for (auto &sect : schm.sections_) {
187  os << *sect;
188  }
189 
190  return os;
191  }
192 }
void add_option(const std::string &section_name, const option &opt)
Definition: config.cpp:89
Definition: config.h:15
bool contains(const std::string &section_name) const
Definition: schema.cpp:127
INICPP_API friend std::ostream & operator<<(std::ostream &os, const schema &schm)
Definition: schema.cpp:184
void validate_config(config &cfg, schema_mode mode) const
Definition: schema.cpp:137
bool contains(const std::string &section_name) const
Definition: config.cpp:154
size_t size() const
Definition: schema.cpp:82
void add_section(const section_schema &sect_schema)
Definition: schema.cpp:48
section_schema & operator[](size_t index)
Definition: schema.cpp:87
const std::string & get_name() const
void add_option(const std::string &section_name, const option_schema &opt_schema)
Definition: schema.cpp:72
schema & operator=(const schema &source)
Definition: schema.cpp:23
void add_section(const section &sect)
Definition: config.cpp:48