Improve the process for GNU tools
[minix3.git] / external / bsd / kyua-cli / dist / utils / config / nodes.cpp
blob837405a9669da448a2c9a2122b6df3bdadb6d325
1 // Copyright 2012 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "utils/config/nodes.ipp"
31 #include <memory>
33 #include <lutok/state.ipp>
35 #include "utils/config/exceptions.hpp"
36 #include "utils/config/keys.hpp"
37 #include "utils/format/macros.hpp"
39 namespace config = utils::config;
42 /// Destructor.
43 config::detail::base_node::~base_node(void)
48 /// Constructor.
49 ///
50 /// \param dynamic_ Whether the node is dynamic or not.
51 config::detail::inner_node::inner_node(const bool dynamic_) :
52 _dynamic(dynamic_)
57 /// Destructor.
58 config::detail::inner_node::~inner_node(void)
60 for (children_map::const_iterator iter = _children.begin();
61 iter != _children.end(); ++iter)
62 delete (*iter).second;
66 /// Fills the given node with a copy of this node's data.
67 ///
68 /// \param node The node to fill. Should be the fresh return value of a
69 /// deep_copy() operation.
70 void
71 config::detail::inner_node::copy_into(inner_node* node) const
73 node->_dynamic = _dynamic;
74 for (children_map::const_iterator iter = _children.begin();
75 iter != _children.end(); ++iter) {
76 base_node* new_node = (*iter).second->deep_copy();
77 try {
78 node->_children[(*iter).first] = new_node;
79 } catch (...) {
80 delete new_node;
81 throw;
87 /// Finds a node without creating it if not found.
88 ///
89 /// This recursive algorithm traverses the tree searching for a particular key.
90 /// The returned node is constant, so this can only be used for querying
91 /// purposes. For this reason, this algorithm does not create intermediate
92 /// nodes if they don't exist (as would be necessary to set a new node).
93 ///
94 /// \param key The key to be queried.
95 /// \param key_pos The current level within the key to be examined.
96 ///
97 /// \return A reference to the located node, if successful.
98 ///
99 /// \throw unknown_key_error If the provided key is unknown.
100 const config::detail::base_node*
101 config::detail::inner_node::lookup_ro(const tree_key& key,
102 const tree_key::size_type key_pos) const
104 PRE(key_pos < key.size());
106 const children_map::const_iterator child_iter = _children.find(
107 key[key_pos]);
108 if (child_iter == _children.end())
109 throw unknown_key_error(key);
111 if (key_pos == key.size() - 1) {
112 return (*child_iter).second;
113 } else {
114 PRE(key_pos < key.size() - 1);
115 try {
116 const inner_node& child = dynamic_cast< const inner_node& >(
117 *(*child_iter).second);
118 return child.lookup_ro(key, key_pos + 1);
119 } catch (const std::bad_cast& e) {
120 throw unknown_key_error(
121 key, "Cannot address incomplete configuration property '%s'");
127 /// Finds a node and creates it if not found.
129 /// This recursive algorithm traverses the tree searching for a particular key,
130 /// creating any intermediate nodes if they do not already exist (for the case
131 /// of dynamic inner nodes). The returned node is non-constant, so this can be
132 /// used by the algorithms that set key values.
134 /// \param key The key to be queried.
135 /// \param key_pos The current level within the key to be examined.
136 /// \param new_node A function that returns a new leaf node of the desired
137 /// type. This is only called if the leaf cannot be found, but it has
138 /// already been defined.
140 /// \return A reference to the located node, if successful.
142 /// \throw unknown_key_error If the provided key is unknown.
143 /// \throw value_error If the resulting node of the search would be an inner
144 /// node.
145 config::leaf_node*
146 config::detail::inner_node::lookup_rw(const tree_key& key,
147 const tree_key::size_type key_pos,
148 new_node_hook new_node)
150 PRE(key_pos < key.size());
152 children_map::const_iterator child_iter = _children.find(key[key_pos]);
153 if (child_iter == _children.end()) {
154 if (_dynamic) {
155 base_node* const child = (key_pos == key.size() - 1) ?
156 static_cast< base_node* >(new_node()) :
157 static_cast< base_node* >(new dynamic_inner_node());
158 _children.insert(children_map::value_type(key[key_pos], child));
159 child_iter = _children.find(key[key_pos]);
160 } else {
161 throw unknown_key_error(key);
165 if (key_pos == key.size() - 1) {
166 try {
167 leaf_node& child = dynamic_cast< leaf_node& >(
168 *(*child_iter).second);
169 return &child;
170 } catch (const std::bad_cast& unused_error) {
171 throw value_error(F("Invalid value for key '%s'") %
172 flatten_key(key));
174 } else {
175 PRE(key_pos < key.size() - 1);
176 try {
177 inner_node& child = dynamic_cast< inner_node& >(
178 *(*child_iter).second);
179 return child.lookup_rw(key, key_pos + 1, new_node);
180 } catch (const std::bad_cast& e) {
181 throw unknown_key_error(
182 key, "Cannot address incomplete configuration property '%s'");
188 /// Converts the subtree to a collection of key/value string pairs.
190 /// \param [out] properties The accumulator for the generated properties. The
191 /// contents of the map are only extended.
192 /// \param key The path to the current node.
193 void
194 config::detail::inner_node::all_properties(properties_map& properties,
195 const tree_key& key) const
197 for (children_map::const_iterator iter = _children.begin();
198 iter != _children.end(); ++iter) {
199 tree_key child_key = key;
200 child_key.push_back((*iter).first);
201 try {
202 leaf_node& child = dynamic_cast< leaf_node& >(*(*iter).second);
203 if (child.is_set())
204 properties[flatten_key(child_key)] = child.to_string();
205 } catch (const std::bad_cast& unused_error) {
206 inner_node& child = dynamic_cast< inner_node& >(*(*iter).second);
207 child.all_properties(properties, child_key);
213 /// Constructor.
214 config::detail::static_inner_node::static_inner_node(void) :
215 inner_node(false)
220 /// Copies the node.
222 /// \return A dynamically-allocated node.
223 config::detail::base_node*
224 config::detail::static_inner_node::deep_copy(void) const
226 std::auto_ptr< inner_node > new_node(new static_inner_node());
227 copy_into(new_node.get());
228 return new_node.release();
232 /// Registers a key as valid and having a specific type.
234 /// This method does not raise errors on invalid/unknown keys or other
235 /// tree-related issues. The reasons is that define() is a method that does not
236 /// depend on user input: it is intended to pre-populate the tree with a
237 /// specific structure, and that happens once at coding time.
239 /// \param key The key to be registered.
240 /// \param key_pos The current level within the key to be examined.
241 /// \param new_node A function that returns a new leaf node of the desired
242 /// type.
243 void
244 config::detail::static_inner_node::define(const tree_key& key,
245 const tree_key::size_type key_pos,
246 new_node_hook new_node)
248 PRE(key_pos < key.size());
250 if (key_pos == key.size() - 1) {
251 PRE_MSG(_children.find(key[key_pos]) == _children.end(),
252 "Key already defined");
253 _children.insert(children_map::value_type(key[key_pos], new_node()));
254 } else {
255 PRE(key_pos < key.size() - 1);
256 const children_map::const_iterator child_iter = _children.find(
257 key[key_pos]);
259 if (child_iter == _children.end()) {
260 static_inner_node* const child_ptr = new static_inner_node();
261 _children.insert(children_map::value_type(key[key_pos], child_ptr));
262 child_ptr->define(key, key_pos + 1, new_node);
263 } else {
264 try {
265 static_inner_node& child = dynamic_cast< static_inner_node& >(
266 *(*child_iter).second);
267 child.define(key, key_pos + 1, new_node);
268 } catch (const std::bad_cast& e) {
269 UNREACHABLE;
276 /// Constructor.
277 config::detail::dynamic_inner_node::dynamic_inner_node(void) :
278 inner_node(true)
283 /// Copies the node.
285 /// \return A dynamically-allocated node.
286 config::detail::base_node*
287 config::detail::dynamic_inner_node::deep_copy(void) const
289 std::auto_ptr< inner_node > new_node(new dynamic_inner_node());
290 copy_into(new_node.get());
291 return new_node.release();
295 /// Destructor.
296 config::leaf_node::~leaf_node(void)
301 /// Copies the node.
303 /// \return A dynamically-allocated node.
304 config::detail::base_node*
305 config::bool_node::deep_copy(void) const
307 std::auto_ptr< bool_node > new_node(new bool_node());
308 new_node->_value = _value;
309 return new_node.release();
313 /// Pushes the node's value onto the Lua stack.
315 /// \param state The Lua state onto which to push the value.
316 void
317 config::bool_node::push_lua(lutok::state& state) const
319 state.push_boolean(value());
323 /// Sets the value of the node from an entry in the Lua stack.
325 /// \param state The Lua state from which to get the value.
326 /// \param value_index The stack index in which the value resides.
328 /// \throw value_error If the value in state(value_index) cannot be
329 /// processed by this node.
330 void
331 config::bool_node::set_lua(lutok::state& state, const int value_index)
333 if (state.is_boolean(value_index))
334 set(state.to_boolean(value_index));
335 else
336 throw value_error("Not a boolean");
340 /// Copies the node.
342 /// \return A dynamically-allocated node.
343 config::detail::base_node*
344 config::int_node::deep_copy(void) const
346 std::auto_ptr< int_node > new_node(new int_node());
347 new_node->_value = _value;
348 return new_node.release();
352 /// Pushes the node's value onto the Lua stack.
354 /// \param state The Lua state onto which to push the value.
355 void
356 config::int_node::push_lua(lutok::state& state) const
358 state.push_integer(value());
362 /// Sets the value of the node from an entry in the Lua stack.
364 /// \param state The Lua state from which to get the value.
365 /// \param value_index The stack index in which the value resides.
367 /// \throw value_error If the value in state(value_index) cannot be
368 /// processed by this node.
369 void
370 config::int_node::set_lua(lutok::state& state, const int value_index)
372 if (state.is_number(value_index))
373 set(state.to_integer(value_index));
374 else
375 throw value_error("Not an integer");
379 /// Copies the node.
381 /// \return A dynamically-allocated node.
382 config::detail::base_node*
383 config::string_node::deep_copy(void) const
385 std::auto_ptr< string_node > new_node(new string_node());
386 new_node->_value = _value;
387 return new_node.release();
391 /// Pushes the node's value onto the Lua stack.
393 /// \param state The Lua state onto which to push the value.
394 void
395 config::string_node::push_lua(lutok::state& state) const
397 state.push_string(value());
401 /// Sets the value of the node from an entry in the Lua stack.
403 /// \param state The Lua state from which to get the value.
404 /// \param value_index The stack index in which the value resides.
406 /// \throw value_error If the value in state(value_index) cannot be
407 /// processed by this node.
408 void
409 config::string_node::set_lua(lutok::state& state, const int value_index)
411 if (state.is_string(value_index))
412 set(state.to_string(value_index));
413 else
414 throw value_error("Not a string");
418 /// Copies the node.
420 /// \return A dynamically-allocated node.
421 config::detail::base_node*
422 config::strings_set_node::deep_copy(void) const
424 std::auto_ptr< strings_set_node > new_node(new strings_set_node());
425 new_node->_value = _value;
426 return new_node.release();
430 /// Converts a single word to the native type.
432 /// \param raw_value The value to parse.
434 /// \return The parsed value.
435 std::string
436 config::strings_set_node::parse_one(const std::string& raw_value) const
438 return raw_value;