Loading...
Searching...
No Matches
configuration_tree.cpp
1/*---------------------------------------------------------------------------*\
2*
3* bitpit
4*
5* Copyright (C) 2015-2021 OPTIMAD engineering Srl
6*
7* -------------------------------------------------------------------------
8* License
9* This file is part of bitpit.
10*
11* bitpit is free software: you can redistribute it and/or modify it
12* under the terms of the GNU Lesser General Public License v3 (LGPL)
13* as published by the Free Software Foundation.
14*
15* bitpit is distributed in the hope that it will be useful, but WITHOUT
16* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18* License for more details.
19*
20* You should have received a copy of the GNU Lesser General Public License
21* along with bitpit. If not, see <http://www.gnu.org/licenses/>.
22*
23\*---------------------------------------------------------------------------*/
24
25#include "configuration_tree.hpp"
26
27#include <unordered_set>
28
29namespace bitpit {
30
31namespace config {
32
33namespace tree {
34
41void importTree(boost::property_tree::ptree const &root, Config *config)
42{
43 for (boost::property_tree::ptree::value_type const &node : root) {
44 std::string key = node.first;
45 if (key == "<xmlattr>") {
46 continue;
47 } else if (key == "") {
48 continue;
49 }
50
51 bool isSection = (node.second.size() != 0);
52 if (isSection) {
53 // Check if the section defines an array
54 //
55 // A node can define a single section or an array of sections. Arrays of sections are
56 // stored as key/value pairs where the key is an empty string.
57 bool isArray = true;
58 for (boost::property_tree::ptree::value_type const &itemCandidate : node.second) {
59 if (itemCandidate.first != "") {
60 isArray = false;
61 break;
62 }
63 }
64
65 // Read section
66 if (isArray) {
67 if (!config->isMultiSectionsEnabled()) {
68 throw std::runtime_error("config::tree:readNode reading array but Config MultiSection disabled");
69 }
70
71 for (boost::property_tree::ptree::value_type const &item : node.second) {
72 Config::Section *section = &(config->addSection(key));
73 importTree(item.second, section);
74 }
75 } else {
76 Config::Section *section;
77 if (!config->isMultiSectionsEnabled() && config->hasSection(key)) {
78 section = &(config->getSection(key));
79 } else {
80 section = &(config->addSection(key));
81 }
82
83 importTree(node.second, section);
84 }
85 } else {
86 std::string value = readNodeValue(node.second);
87 config->set(key, value);
88 }
89 }
90}
91
99void exportTree(const Config &config, bool areArraysAllowed, boost::property_tree::ptree *root)
100{
101 // Write the options
102 for (const auto &entry : config.getOptions()) {
103 const std::string &key = entry.first;
104 const std::string &value = entry.second;
105 root->add(key, value);
106 }
107
108 // Write the sections
109 std::unordered_set<std::string> processedKeys;
110 for (const auto &entry : config.getSections()) {
111 const std::string &key = entry.first;
112 if (areArraysAllowed && processedKeys.count(key) != 0) {
113 continue;
114 }
115
116 // Create the section tree
117 root->push_back(boost::property_tree::ptree::value_type(key, boost::property_tree::ptree()));
118 auto &sectionChild = root->back();
119 auto &sectionRoot = sectionChild.second;
120
121 // Check if the section defines an array
122 bool isArray = areArraysAllowed && (config.getSectionCount(key) > 1);
123 if (isArray) {
124 // Fill the section with the elements of the array
125 //
126 // Arrays of sections should be stored as key/value pairs where the key is an
127 // empty string.
128 for (const auto &itemEntry : config.getSections(key)) {
129 // Create the item tree
130 sectionRoot.push_back(boost::property_tree::ptree::value_type("", boost::property_tree::ptree()));
131 auto &itemChild = sectionRoot.back();
132
133 // Fill the section
134 const Config::Section &itemSection = *itemEntry;
135 exportTree(itemSection, areArraysAllowed, &(itemChild.second));
136 }
137 } else {
138 // Fill the section
139 const Config::Section &section = *(entry.second);
140 exportTree(section, areArraysAllowed, &sectionRoot);
141 }
142
143 // The key has been processed
144 if (areArraysAllowed) {
145 processedKeys.insert(key);
146 }
147 }
148}
149
157void writeTree(const std::string &filename, SourceFormat format, boost::property_tree::ptree &propertyTree)
158{
159 if (format == SOURCE_FORMAT_XML) {
160 boost::property_tree::xml_writer_settings<std::string> settings(' ', 4);
161 write_xml(filename, propertyTree, std::locale(), settings);
162 } else if (format == SOURCE_FORMAT_JSON) {
163 write_json(filename, propertyTree, std::locale(), true);
164 }
165}
166
173std::string readNodeValue(const boost::property_tree::ptree &node)
174{
175 std::string value = node.get_value("");
176
177 std::string lowercaseValue = value;
178 std::transform(lowercaseValue.begin(), lowercaseValue.end(), lowercaseValue.begin(), ::tolower);
179 if (value == "true") {
180 return std::to_string(1);
181 } else if (value == "false") {
182 return std::to_string(0);
183 } else {
184 return value;
185 }
186}
187
188}
189
190}
191
192}
GlobalConfigParser & root
--- layout: doxygen_footer ---