1// Copyright 2012 The Kyua Authors.
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
39namespace config = utils::config;
40
41
42/// Destructor.
43config::detail::base_node::~base_node(void)
44{
45}
46
47
48/// Constructor.
49///
50/// \param dynamic_ Whether the node is dynamic or not.
51config::detail::inner_node::inner_node(const bool dynamic_) :
52    _dynamic(dynamic_)
53{
54}
55
56
57/// Destructor.
58config::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.
70void
71config::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/// Combines two children sets, preferring the keys in the first set only.
88///
89/// This operation is not symmetrical on c1 and c2.  The caller is responsible
90/// for invoking this twice so that the two key sets are combined if they happen
91/// to differ.
92///
93/// \param key Key to this node.
94/// \param c1 First children set.
95/// \param c2 First children set.
96/// \param [in,out] node The node to combine into.
97///
98/// \throw bad_combination_error If the two nodes cannot be combined.
99void
100config::detail::inner_node::combine_children_into(
101    const tree_key& key,
102    const children_map& c1, const children_map& c2,
103    inner_node* node) const
104{
105    for (children_map::const_iterator iter1 = c1.begin();
106         iter1 != c1.end(); ++iter1) {
107        const std::string& name = (*iter1).first;
108
109        if (node->_children.find(name) != node->_children.end()) {
110            continue;
111        }
112
113        std::auto_ptr< base_node > new_node;
114
115        children_map::const_iterator iter2 = c2.find(name);
116        if (iter2 == c2.end()) {
117            new_node.reset((*iter1).second->deep_copy());
118        } else {
119            tree_key child_key = key;
120            child_key.push_back(name);
121            new_node.reset((*iter1).second->combine(child_key,
122                                                    (*iter2).second));
123        }
124
125        node->_children[name] = new_node.release();
126    }
127}
128
129
130/// Combines this inner node with another inner node onto a new node.
131///
132/// The "dynamic" property is inherited by the new node if either of the two
133/// nodes are dynamic.
134///
135/// \param key Key to this node.
136/// \param other_base The node to combine with.
137/// \param [in,out] node The node to combine into.
138///
139/// \throw bad_combination_error If the two nodes cannot be combined.
140void
141config::detail::inner_node::combine_into(const tree_key& key,
142                                         const base_node* other_base,
143                                         inner_node* node) const
144{
145    try {
146        const inner_node& other = dynamic_cast< const inner_node& >(
147            *other_base);
148
149        node->_dynamic = _dynamic || other._dynamic;
150
151        combine_children_into(key, _children, other._children, node);
152        combine_children_into(key, other._children, _children, node);
153    } catch (const std::bad_cast& unused_e) {
154        throw config::bad_combination_error(
155            key, "'%s' is an inner node in the base tree but a leaf node in "
156            "the overrides treee");
157    }
158}
159
160
161/// Finds a node without creating it if not found.
162///
163/// This recursive algorithm traverses the tree searching for a particular key.
164/// The returned node is constant, so this can only be used for querying
165/// purposes.  For this reason, this algorithm does not create intermediate
166/// nodes if they don't exist (as would be necessary to set a new node).
167///
168/// \param key The key to be queried.
169/// \param key_pos The current level within the key to be examined.
170///
171/// \return A reference to the located node, if successful.
172///
173/// \throw unknown_key_error If the provided key is unknown.
174const config::detail::base_node*
175config::detail::inner_node::lookup_ro(const tree_key& key,
176                                      const tree_key::size_type key_pos) const
177{
178    PRE(key_pos < key.size());
179
180    const children_map::const_iterator child_iter = _children.find(
181        key[key_pos]);
182    if (child_iter == _children.end())
183        throw unknown_key_error(key);
184
185    if (key_pos == key.size() - 1) {
186        return (*child_iter).second;
187    } else {
188        PRE(key_pos < key.size() - 1);
189        try {
190            const inner_node& child = dynamic_cast< const inner_node& >(
191                *(*child_iter).second);
192            return child.lookup_ro(key, key_pos + 1);
193        } catch (const std::bad_cast& e) {
194            throw unknown_key_error(
195                key, "Cannot address incomplete configuration property '%s'");
196        }
197    }
198}
199
200
201/// Finds a node and creates it if not found.
202///
203/// This recursive algorithm traverses the tree searching for a particular key,
204/// creating any intermediate nodes if they do not already exist (for the case
205/// of dynamic inner nodes).  The returned node is non-constant, so this can be
206/// used by the algorithms that set key values.
207///
208/// \param key The key to be queried.
209/// \param key_pos The current level within the key to be examined.
210/// \param new_node A function that returns a new leaf node of the desired
211///     type.  This is only called if the leaf cannot be found, but it has
212///     already been defined.
213///
214/// \return A reference to the located node, if successful.
215///
216/// \throw invalid_key_value If the resulting node of the search would be an
217///     inner node.
218/// \throw unknown_key_error If the provided key is unknown.
219config::leaf_node*
220config::detail::inner_node::lookup_rw(const tree_key& key,
221                                      const tree_key::size_type key_pos,
222                                      new_node_hook new_node)
223{
224    PRE(key_pos < key.size());
225
226    children_map::const_iterator child_iter = _children.find(key[key_pos]);
227    if (child_iter == _children.end()) {
228        if (_dynamic) {
229            base_node* const child = (key_pos == key.size() - 1) ?
230                static_cast< base_node* >(new_node()) :
231                static_cast< base_node* >(new dynamic_inner_node());
232            _children.insert(children_map::value_type(key[key_pos], child));
233            child_iter = _children.find(key[key_pos]);
234        } else {
235            throw unknown_key_error(key);
236        }
237    }
238
239    if (key_pos == key.size() - 1) {
240        try {
241            leaf_node& child = dynamic_cast< leaf_node& >(
242                *(*child_iter).second);
243            return &child;
244        } catch (const std::bad_cast& unused_error) {
245            throw invalid_key_value(key, "Type mismatch");
246        }
247    } else {
248        PRE(key_pos < key.size() - 1);
249        try {
250            inner_node& child = dynamic_cast< inner_node& >(
251                *(*child_iter).second);
252            return child.lookup_rw(key, key_pos + 1, new_node);
253        } catch (const std::bad_cast& e) {
254            throw unknown_key_error(
255                key, "Cannot address incomplete configuration property '%s'");
256        }
257    }
258}
259
260
261/// Converts the subtree to a collection of key/value string pairs.
262///
263/// \param [out] properties The accumulator for the generated properties.  The
264///     contents of the map are only extended.
265/// \param key The path to the current node.
266void
267config::detail::inner_node::all_properties(properties_map& properties,
268                                           const tree_key& key) const
269{
270    for (children_map::const_iterator iter = _children.begin();
271         iter != _children.end(); ++iter) {
272        tree_key child_key = key;
273        child_key.push_back((*iter).first);
274        try {
275            leaf_node& child = dynamic_cast< leaf_node& >(*(*iter).second);
276            if (child.is_set())
277                properties[flatten_key(child_key)] = child.to_string();
278        } catch (const std::bad_cast& unused_error) {
279            inner_node& child = dynamic_cast< inner_node& >(*(*iter).second);
280            child.all_properties(properties, child_key);
281        }
282    }
283}
284
285
286/// Constructor.
287config::detail::static_inner_node::static_inner_node(void) :
288    inner_node(false)
289{
290}
291
292
293/// Copies the node.
294///
295/// \return A dynamically-allocated node.
296config::detail::base_node*
297config::detail::static_inner_node::deep_copy(void) const
298{
299    std::auto_ptr< inner_node > new_node(new static_inner_node());
300    copy_into(new_node.get());
301    return new_node.release();
302}
303
304
305/// Combines this node with another one.
306///
307/// \param key Key to this node.
308/// \param other The node to combine with.
309///
310/// \return A new node representing the combination.
311///
312/// \throw bad_combination_error If the two nodes cannot be combined.
313config::detail::base_node*
314config::detail::static_inner_node::combine(const tree_key& key,
315                                           const base_node* other) const
316{
317    std::auto_ptr< inner_node > new_node(new static_inner_node());
318    combine_into(key, other, new_node.get());
319    return new_node.release();
320}
321
322
323/// Registers a key as valid and having a specific type.
324///
325/// This method does not raise errors on invalid/unknown keys or other
326/// tree-related issues.  The reasons is that define() is a method that does not
327/// depend on user input: it is intended to pre-populate the tree with a
328/// specific structure, and that happens once at coding time.
329///
330/// \param key The key to be registered.
331/// \param key_pos The current level within the key to be examined.
332/// \param new_node A function that returns a new leaf node of the desired
333///     type.
334void
335config::detail::static_inner_node::define(const tree_key& key,
336                                          const tree_key::size_type key_pos,
337                                          new_node_hook new_node)
338{
339    PRE(key_pos < key.size());
340
341    if (key_pos == key.size() - 1) {
342        PRE_MSG(_children.find(key[key_pos]) == _children.end(),
343                "Key already defined");
344        _children.insert(children_map::value_type(key[key_pos], new_node()));
345    } else {
346        PRE(key_pos < key.size() - 1);
347        const children_map::const_iterator child_iter = _children.find(
348            key[key_pos]);
349
350        if (child_iter == _children.end()) {
351            static_inner_node* const child_ptr = new static_inner_node();
352            _children.insert(children_map::value_type(key[key_pos], child_ptr));
353            child_ptr->define(key, key_pos + 1, new_node);
354        } else {
355            try {
356                static_inner_node& child = dynamic_cast< static_inner_node& >(
357                    *(*child_iter).second);
358                child.define(key, key_pos + 1, new_node);
359            } catch (const std::bad_cast& e) {
360                UNREACHABLE;
361            }
362        }
363    }
364}
365
366
367/// Constructor.
368config::detail::dynamic_inner_node::dynamic_inner_node(void) :
369    inner_node(true)
370{
371}
372
373
374/// Copies the node.
375///
376/// \return A dynamically-allocated node.
377config::detail::base_node*
378config::detail::dynamic_inner_node::deep_copy(void) const
379{
380    std::auto_ptr< inner_node > new_node(new dynamic_inner_node());
381    copy_into(new_node.get());
382    return new_node.release();
383}
384
385
386/// Combines this node with another one.
387///
388/// \param key Key to this node.
389/// \param other The node to combine with.
390///
391/// \return A new node representing the combination.
392///
393/// \throw bad_combination_error If the two nodes cannot be combined.
394config::detail::base_node*
395config::detail::dynamic_inner_node::combine(const tree_key& key,
396                                            const base_node* other) const
397{
398    std::auto_ptr< inner_node > new_node(new dynamic_inner_node());
399    combine_into(key, other, new_node.get());
400    return new_node.release();
401}
402
403
404/// Destructor.
405config::leaf_node::~leaf_node(void)
406{
407}
408
409
410/// Combines this node with another one.
411///
412/// \param key Key to this node.
413/// \param other_base The node to combine with.
414///
415/// \return A new node representing the combination.
416///
417/// \throw bad_combination_error If the two nodes cannot be combined.
418config::detail::base_node*
419config::leaf_node::combine(const detail::tree_key& key,
420                           const base_node* other_base) const
421{
422    try {
423        const leaf_node& other = dynamic_cast< const leaf_node& >(*other_base);
424
425        if (other.is_set()) {
426            return other.deep_copy();
427        } else {
428            return deep_copy();
429        }
430    } catch (const std::bad_cast& unused_e) {
431        throw config::bad_combination_error(
432            key, "'%s' is a leaf node in the base tree but an inner node in "
433            "the overrides treee");
434    }
435}
436
437
438/// Copies the node.
439///
440/// \return A dynamically-allocated node.
441config::detail::base_node*
442config::bool_node::deep_copy(void) const
443{
444    std::auto_ptr< bool_node > new_node(new bool_node());
445    new_node->_value = _value;
446    return new_node.release();
447}
448
449
450/// Pushes the node's value onto the Lua stack.
451///
452/// \param state The Lua state onto which to push the value.
453void
454config::bool_node::push_lua(lutok::state& state) const
455{
456    state.push_boolean(value());
457}
458
459
460/// Sets the value of the node from an entry in the Lua stack.
461///
462/// \param state The Lua state from which to get the value.
463/// \param value_index The stack index in which the value resides.
464///
465/// \throw value_error If the value in state(value_index) cannot be
466///     processed by this node.
467void
468config::bool_node::set_lua(lutok::state& state, const int value_index)
469{
470    if (state.is_boolean(value_index))
471        set(state.to_boolean(value_index));
472    else
473        throw value_error("Not a boolean");
474}
475
476
477/// Copies the node.
478///
479/// \return A dynamically-allocated node.
480config::detail::base_node*
481config::int_node::deep_copy(void) const
482{
483    std::auto_ptr< int_node > new_node(new int_node());
484    new_node->_value = _value;
485    return new_node.release();
486}
487
488
489/// Pushes the node's value onto the Lua stack.
490///
491/// \param state The Lua state onto which to push the value.
492void
493config::int_node::push_lua(lutok::state& state) const
494{
495    state.push_integer(value());
496}
497
498
499/// Sets the value of the node from an entry in the Lua stack.
500///
501/// \param state The Lua state from which to get the value.
502/// \param value_index The stack index in which the value resides.
503///
504/// \throw value_error If the value in state(value_index) cannot be
505///     processed by this node.
506void
507config::int_node::set_lua(lutok::state& state, const int value_index)
508{
509    if (state.is_number(value_index))
510        set(state.to_integer(value_index));
511    else
512        throw value_error("Not an integer");
513}
514
515
516/// Checks a given value for validity.
517///
518/// \param new_value The value to validate.
519///
520/// \throw value_error If the value is not valid.
521void
522config::positive_int_node::validate(const value_type& new_value) const
523{
524    if (new_value <= 0)
525        throw value_error("Must be a positive integer");
526}
527
528
529/// Copies the node.
530///
531/// \return A dynamically-allocated node.
532config::detail::base_node*
533config::string_node::deep_copy(void) const
534{
535    std::auto_ptr< string_node > new_node(new string_node());
536    new_node->_value = _value;
537    return new_node.release();
538}
539
540
541/// Pushes the node's value onto the Lua stack.
542///
543/// \param state The Lua state onto which to push the value.
544void
545config::string_node::push_lua(lutok::state& state) const
546{
547    state.push_string(value());
548}
549
550
551/// Sets the value of the node from an entry in the Lua stack.
552///
553/// \param state The Lua state from which to get the value.
554/// \param value_index The stack index in which the value resides.
555///
556/// \throw value_error If the value in state(value_index) cannot be
557///     processed by this node.
558void
559config::string_node::set_lua(lutok::state& state, const int value_index)
560{
561    if (state.is_string(value_index))
562        set(state.to_string(value_index));
563    else
564        throw value_error("Not a string");
565}
566
567
568/// Copies the node.
569///
570/// \return A dynamically-allocated node.
571config::detail::base_node*
572config::strings_set_node::deep_copy(void) const
573{
574    std::auto_ptr< strings_set_node > new_node(new strings_set_node());
575    new_node->_value = _value;
576    return new_node.release();
577}
578
579
580/// Converts a single word to the native type.
581///
582/// \param raw_value The value to parse.
583///
584/// \return The parsed value.
585std::string
586config::strings_set_node::parse_one(const std::string& raw_value) const
587{
588    return raw_value;
589}
590