xref: /netbsd-src/external/bsd/kyua-cli/dist/utils/config/nodes.cpp (revision 46b85cbbd3d745f264b248ec8702f62b162c7789)
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.
16 //
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.
28 
29 #include "utils/config/nodes.ipp"
30 
31 #include <memory>
32 
33 #include <lutok/state.ipp>
34 
35 #include "utils/config/exceptions.hpp"
36 #include "utils/config/keys.hpp"
37 #include "utils/format/macros.hpp"
38 
39 namespace config = utils::config;
40 
41 
42 /// Destructor.
~base_node(void)43 config::detail::base_node::~base_node(void)
44 {
45 }
46 
47 
48 /// Constructor.
49 ///
50 /// \param dynamic_ Whether the node is dynamic or not.
inner_node(const bool dynamic_)51 config::detail::inner_node::inner_node(const bool dynamic_) :
52     _dynamic(dynamic_)
53 {
54 }
55 
56 
57 /// Destructor.
~inner_node(void)58 config::detail::inner_node::~inner_node(void)
59 {
60     for (children_map::const_iterator iter = _children.begin();
61          iter != _children.end(); ++iter)
62         delete (*iter).second;
63 }
64 
65 
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
copy_into(inner_node * node) const71 config::detail::inner_node::copy_into(inner_node* node) const
72 {
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;
82         }
83     }
84 }
85 
86 
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*
lookup_ro(const tree_key & key,const tree_key::size_type key_pos) const101 config::detail::inner_node::lookup_ro(const tree_key& key,
102                                       const tree_key::size_type key_pos) const
103 {
104     PRE(key_pos < key.size());
105 
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);
110 
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'");
122         }
123     }
124 }
125 
126 
127 /// Finds a node and creates it if not found.
128 ///
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.
133 ///
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.
139 ///
140 /// \return A reference to the located node, if successful.
141 ///
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*
lookup_rw(const tree_key & key,const tree_key::size_type key_pos,new_node_hook new_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)
149 {
150     PRE(key_pos < key.size());
151 
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);
162         }
163     }
164 
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));
173         }
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'");
183         }
184     }
185 }
186 
187 
188 /// Converts the subtree to a collection of key/value string pairs.
189 ///
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
all_properties(properties_map & properties,const tree_key & key) const194 config::detail::inner_node::all_properties(properties_map& properties,
195                                            const tree_key& key) const
196 {
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);
208         }
209     }
210 }
211 
212 
213 /// Constructor.
static_inner_node(void)214 config::detail::static_inner_node::static_inner_node(void) :
215     inner_node(false)
216 {
217 }
218 
219 
220 /// Copies the node.
221 ///
222 /// \return A dynamically-allocated node.
223 config::detail::base_node*
deep_copy(void) const224 config::detail::static_inner_node::deep_copy(void) const
225 {
226     std::unique_ptr< inner_node > new_node(new static_inner_node());
227     copy_into(new_node.get());
228     return new_node.release();
229 }
230 
231 
232 /// Registers a key as valid and having a specific type.
233 ///
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.
238 ///
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
define(const tree_key & key,const tree_key::size_type key_pos,new_node_hook new_node)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)
247 {
248     PRE(key_pos < key.size());
249 
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]);
258 
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;
270             }
271         }
272     }
273 }
274 
275 
276 /// Constructor.
dynamic_inner_node(void)277 config::detail::dynamic_inner_node::dynamic_inner_node(void) :
278     inner_node(true)
279 {
280 }
281 
282 
283 /// Copies the node.
284 ///
285 /// \return A dynamically-allocated node.
286 config::detail::base_node*
deep_copy(void) const287 config::detail::dynamic_inner_node::deep_copy(void) const
288 {
289     std::unique_ptr< inner_node > new_node(new dynamic_inner_node());
290     copy_into(new_node.get());
291     return new_node.release();
292 }
293 
294 
295 /// Destructor.
~leaf_node(void)296 config::leaf_node::~leaf_node(void)
297 {
298 }
299 
300 
301 /// Copies the node.
302 ///
303 /// \return A dynamically-allocated node.
304 config::detail::base_node*
deep_copy(void) const305 config::bool_node::deep_copy(void) const
306 {
307     std::unique_ptr< bool_node > new_node(new bool_node());
308     new_node->_value = _value;
309     return new_node.release();
310 }
311 
312 
313 /// Pushes the node's value onto the Lua stack.
314 ///
315 /// \param state The Lua state onto which to push the value.
316 void
push_lua(lutok::state & state) const317 config::bool_node::push_lua(lutok::state& state) const
318 {
319     state.push_boolean(value());
320 }
321 
322 
323 /// Sets the value of the node from an entry in the Lua stack.
324 ///
325 /// \param state The Lua state from which to get the value.
326 /// \param value_index The stack index in which the value resides.
327 ///
328 /// \throw value_error If the value in state(value_index) cannot be
329 ///     processed by this node.
330 void
set_lua(lutok::state & state,const int value_index)331 config::bool_node::set_lua(lutok::state& state, const int value_index)
332 {
333     if (state.is_boolean(value_index))
334         set(state.to_boolean(value_index));
335     else
336         throw value_error("Not a boolean");
337 }
338 
339 
340 /// Copies the node.
341 ///
342 /// \return A dynamically-allocated node.
343 config::detail::base_node*
deep_copy(void) const344 config::int_node::deep_copy(void) const
345 {
346     std::unique_ptr< int_node > new_node(new int_node());
347     new_node->_value = _value;
348     return new_node.release();
349 }
350 
351 
352 /// Pushes the node's value onto the Lua stack.
353 ///
354 /// \param state The Lua state onto which to push the value.
355 void
push_lua(lutok::state & state) const356 config::int_node::push_lua(lutok::state& state) const
357 {
358     state.push_integer(value());
359 }
360 
361 
362 /// Sets the value of the node from an entry in the Lua stack.
363 ///
364 /// \param state The Lua state from which to get the value.
365 /// \param value_index The stack index in which the value resides.
366 ///
367 /// \throw value_error If the value in state(value_index) cannot be
368 ///     processed by this node.
369 void
set_lua(lutok::state & state,const int value_index)370 config::int_node::set_lua(lutok::state& state, const int value_index)
371 {
372     if (state.is_number(value_index))
373         set(state.to_integer(value_index));
374     else
375         throw value_error("Not an integer");
376 }
377 
378 
379 /// Copies the node.
380 ///
381 /// \return A dynamically-allocated node.
382 config::detail::base_node*
deep_copy(void) const383 config::string_node::deep_copy(void) const
384 {
385     std::unique_ptr< string_node > new_node(new string_node());
386     new_node->_value = _value;
387     return new_node.release();
388 }
389 
390 
391 /// Pushes the node's value onto the Lua stack.
392 ///
393 /// \param state The Lua state onto which to push the value.
394 void
push_lua(lutok::state & state) const395 config::string_node::push_lua(lutok::state& state) const
396 {
397     state.push_string(value());
398 }
399 
400 
401 /// Sets the value of the node from an entry in the Lua stack.
402 ///
403 /// \param state The Lua state from which to get the value.
404 /// \param value_index The stack index in which the value resides.
405 ///
406 /// \throw value_error If the value in state(value_index) cannot be
407 ///     processed by this node.
408 void
set_lua(lutok::state & state,const int value_index)409 config::string_node::set_lua(lutok::state& state, const int value_index)
410 {
411     if (state.is_string(value_index))
412         set(state.to_string(value_index));
413     else
414         throw value_error("Not a string");
415 }
416 
417 
418 /// Copies the node.
419 ///
420 /// \return A dynamically-allocated node.
421 config::detail::base_node*
deep_copy(void) const422 config::strings_set_node::deep_copy(void) const
423 {
424     std::unique_ptr< strings_set_node > new_node(new strings_set_node());
425     new_node->_value = _value;
426     return new_node.release();
427 }
428 
429 
430 /// Converts a single word to the native type.
431 ///
432 /// \param raw_value The value to parse.
433 ///
434 /// \return The parsed value.
435 std::string
parse_one(const std::string & raw_value) const436 config::strings_set_node::parse_one(const std::string& raw_value) const
437 {
438     return raw_value;
439 }
440