xref: /minix3/external/bsd/kyua-cli/dist/utils/config/tree.cpp (revision 11be35a165022172ed3cea20f2b5df0307540b0e)
1*11be35a1SLionel Sambuc // Copyright 2012 Google Inc.
2*11be35a1SLionel Sambuc // All rights reserved.
3*11be35a1SLionel Sambuc //
4*11be35a1SLionel Sambuc // Redistribution and use in source and binary forms, with or without
5*11be35a1SLionel Sambuc // modification, are permitted provided that the following conditions are
6*11be35a1SLionel Sambuc // met:
7*11be35a1SLionel Sambuc //
8*11be35a1SLionel Sambuc // * Redistributions of source code must retain the above copyright
9*11be35a1SLionel Sambuc //   notice, this list of conditions and the following disclaimer.
10*11be35a1SLionel Sambuc // * Redistributions in binary form must reproduce the above copyright
11*11be35a1SLionel Sambuc //   notice, this list of conditions and the following disclaimer in the
12*11be35a1SLionel Sambuc //   documentation and/or other materials provided with the distribution.
13*11be35a1SLionel Sambuc // * Neither the name of Google Inc. nor the names of its contributors
14*11be35a1SLionel Sambuc //   may be used to endorse or promote products derived from this software
15*11be35a1SLionel Sambuc //   without specific prior written permission.
16*11be35a1SLionel Sambuc //
17*11be35a1SLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*11be35a1SLionel Sambuc // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*11be35a1SLionel Sambuc // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*11be35a1SLionel Sambuc // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*11be35a1SLionel Sambuc // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*11be35a1SLionel Sambuc // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*11be35a1SLionel Sambuc // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*11be35a1SLionel Sambuc // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*11be35a1SLionel Sambuc // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*11be35a1SLionel Sambuc // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*11be35a1SLionel Sambuc // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*11be35a1SLionel Sambuc 
29*11be35a1SLionel Sambuc #include "utils/config/tree.ipp"
30*11be35a1SLionel Sambuc 
31*11be35a1SLionel Sambuc #include "utils/config/exceptions.hpp"
32*11be35a1SLionel Sambuc #include "utils/config/keys.hpp"
33*11be35a1SLionel Sambuc #include "utils/config/nodes.ipp"
34*11be35a1SLionel Sambuc #include "utils/format/macros.hpp"
35*11be35a1SLionel Sambuc 
36*11be35a1SLionel Sambuc namespace config = utils::config;
37*11be35a1SLionel Sambuc 
38*11be35a1SLionel Sambuc 
39*11be35a1SLionel Sambuc /// Constructor.
tree(void)40*11be35a1SLionel Sambuc config::tree::tree(void) :
41*11be35a1SLionel Sambuc     _root(new detail::static_inner_node())
42*11be35a1SLionel Sambuc {
43*11be35a1SLionel Sambuc }
44*11be35a1SLionel Sambuc 
45*11be35a1SLionel Sambuc 
46*11be35a1SLionel Sambuc /// Constructor with a non-empty root.
47*11be35a1SLionel Sambuc ///
48*11be35a1SLionel Sambuc /// \param root The root to the tree to be owned by this instance.
tree(detail::static_inner_node * root)49*11be35a1SLionel Sambuc config::tree::tree(detail::static_inner_node* root) :
50*11be35a1SLionel Sambuc     _root(root)
51*11be35a1SLionel Sambuc {
52*11be35a1SLionel Sambuc }
53*11be35a1SLionel Sambuc 
54*11be35a1SLionel Sambuc 
55*11be35a1SLionel Sambuc /// Destructor.
~tree(void)56*11be35a1SLionel Sambuc config::tree::~tree(void)
57*11be35a1SLionel Sambuc {
58*11be35a1SLionel Sambuc }
59*11be35a1SLionel Sambuc 
60*11be35a1SLionel Sambuc 
61*11be35a1SLionel Sambuc /// Generates a deep copy of the input tree.
62*11be35a1SLionel Sambuc ///
63*11be35a1SLionel Sambuc /// \return A new tree that is an exact copy of this tree.
64*11be35a1SLionel Sambuc config::tree
deep_copy(void) const65*11be35a1SLionel Sambuc config::tree::deep_copy(void) const
66*11be35a1SLionel Sambuc {
67*11be35a1SLionel Sambuc     detail::static_inner_node* new_root =
68*11be35a1SLionel Sambuc         dynamic_cast< detail::static_inner_node* >(_root->deep_copy());
69*11be35a1SLionel Sambuc     return config::tree(new_root);
70*11be35a1SLionel Sambuc }
71*11be35a1SLionel Sambuc 
72*11be35a1SLionel Sambuc 
73*11be35a1SLionel Sambuc /// Registers a node as being dynamic.
74*11be35a1SLionel Sambuc ///
75*11be35a1SLionel Sambuc /// This operation creates the given key as an inner node.  Further set
76*11be35a1SLionel Sambuc /// operations that trespass this node will automatically create any missing
77*11be35a1SLionel Sambuc /// keys.
78*11be35a1SLionel Sambuc ///
79*11be35a1SLionel Sambuc /// This method does not raise errors on invalid/unknown keys or other
80*11be35a1SLionel Sambuc /// tree-related issues.  The reasons is that define() is a method that does not
81*11be35a1SLionel Sambuc /// depend on user input: it is intended to pre-populate the tree with a
82*11be35a1SLionel Sambuc /// specific structure, and that happens once at coding time.
83*11be35a1SLionel Sambuc ///
84*11be35a1SLionel Sambuc /// \param dotted_key The key to be registered in dotted representation.
85*11be35a1SLionel Sambuc void
define_dynamic(const std::string & dotted_key)86*11be35a1SLionel Sambuc config::tree::define_dynamic(const std::string& dotted_key)
87*11be35a1SLionel Sambuc {
88*11be35a1SLionel Sambuc     try {
89*11be35a1SLionel Sambuc         const detail::tree_key key = detail::parse_key(dotted_key);
90*11be35a1SLionel Sambuc         _root->define(key, 0, detail::new_node< detail::dynamic_inner_node >);
91*11be35a1SLionel Sambuc     } catch (const error& e) {
92*11be35a1SLionel Sambuc         UNREACHABLE_MSG("define() failing due to key errors is a programming "
93*11be35a1SLionel Sambuc                         "mistake: " + std::string(e.what()));
94*11be35a1SLionel Sambuc     }
95*11be35a1SLionel Sambuc }
96*11be35a1SLionel Sambuc 
97*11be35a1SLionel Sambuc 
98*11be35a1SLionel Sambuc /// Checks if a given node is set.
99*11be35a1SLionel Sambuc ///
100*11be35a1SLionel Sambuc /// \param dotted_key The key to be checked.
101*11be35a1SLionel Sambuc ///
102*11be35a1SLionel Sambuc /// \return True if the key is set to a specific value (not just defined).
103*11be35a1SLionel Sambuc /// False if the key is not set or if the key does not exist.
104*11be35a1SLionel Sambuc ///
105*11be35a1SLionel Sambuc /// \throw invalid_key_error If the provided key has an invalid format.
106*11be35a1SLionel Sambuc bool
is_set(const std::string & dotted_key) const107*11be35a1SLionel Sambuc config::tree::is_set(const std::string& dotted_key) const
108*11be35a1SLionel Sambuc {
109*11be35a1SLionel Sambuc     const detail::tree_key key = detail::parse_key(dotted_key);
110*11be35a1SLionel Sambuc     try {
111*11be35a1SLionel Sambuc         const detail::base_node* raw_node = _root->lookup_ro(key, 0);
112*11be35a1SLionel Sambuc         try {
113*11be35a1SLionel Sambuc             const leaf_node& child = dynamic_cast< const leaf_node& >(
114*11be35a1SLionel Sambuc                 *raw_node);
115*11be35a1SLionel Sambuc             return child.is_set();
116*11be35a1SLionel Sambuc         } catch (const std::bad_cast& unused_error) {
117*11be35a1SLionel Sambuc             return false;
118*11be35a1SLionel Sambuc         }
119*11be35a1SLionel Sambuc     } catch (const unknown_key_error& unused_error) {
120*11be35a1SLionel Sambuc         return false;
121*11be35a1SLionel Sambuc     }
122*11be35a1SLionel Sambuc }
123*11be35a1SLionel Sambuc 
124*11be35a1SLionel Sambuc 
125*11be35a1SLionel Sambuc /// Pushes a leaf node's value onto the Lua stack.
126*11be35a1SLionel Sambuc ///
127*11be35a1SLionel Sambuc /// \param dotted_key The key to be pushed.
128*11be35a1SLionel Sambuc /// \param state The Lua state into which to push the key's value.
129*11be35a1SLionel Sambuc ///
130*11be35a1SLionel Sambuc /// \throw invalid_key_error If the provided key has an invalid format.
131*11be35a1SLionel Sambuc /// \throw unknown_key_error If the provided key is unknown.
132*11be35a1SLionel Sambuc void
push_lua(const std::string & dotted_key,lutok::state & state) const133*11be35a1SLionel Sambuc config::tree::push_lua(const std::string& dotted_key, lutok::state& state) const
134*11be35a1SLionel Sambuc {
135*11be35a1SLionel Sambuc     const detail::tree_key key = detail::parse_key(dotted_key);
136*11be35a1SLionel Sambuc     const detail::base_node* raw_node = _root->lookup_ro(key, 0);
137*11be35a1SLionel Sambuc     try {
138*11be35a1SLionel Sambuc         const leaf_node& child = dynamic_cast< const leaf_node& >(*raw_node);
139*11be35a1SLionel Sambuc         child.push_lua(state);
140*11be35a1SLionel Sambuc     } catch (const std::bad_cast& unused_error) {
141*11be35a1SLionel Sambuc         throw unknown_key_error(key);
142*11be35a1SLionel Sambuc     }
143*11be35a1SLionel Sambuc }
144*11be35a1SLionel Sambuc 
145*11be35a1SLionel Sambuc 
146*11be35a1SLionel Sambuc /// Sets a leaf node's value from a value in the Lua stack.
147*11be35a1SLionel Sambuc ///
148*11be35a1SLionel Sambuc /// \param dotted_key The key to be set.
149*11be35a1SLionel Sambuc /// \param state The Lua state from which to retrieve the value.
150*11be35a1SLionel Sambuc /// \param value_index The position in the Lua stack holding the value.
151*11be35a1SLionel Sambuc ///
152*11be35a1SLionel Sambuc /// \throw invalid_key_error If the provided key has an invalid format.
153*11be35a1SLionel Sambuc /// \throw unknown_key_error If the provided key is unknown.
154*11be35a1SLionel Sambuc /// \throw value_error If the value mismatches the node type.
155*11be35a1SLionel Sambuc void
set_lua(const std::string & dotted_key,lutok::state & state,const int value_index)156*11be35a1SLionel Sambuc config::tree::set_lua(const std::string& dotted_key, lutok::state& state,
157*11be35a1SLionel Sambuc                       const int value_index)
158*11be35a1SLionel Sambuc {
159*11be35a1SLionel Sambuc     const detail::tree_key key = detail::parse_key(dotted_key);
160*11be35a1SLionel Sambuc     detail::base_node* raw_node = _root->lookup_rw(
161*11be35a1SLionel Sambuc         key, 0, detail::new_node< string_node >);
162*11be35a1SLionel Sambuc     try {
163*11be35a1SLionel Sambuc         leaf_node& child = dynamic_cast< leaf_node& >(*raw_node);
164*11be35a1SLionel Sambuc         child.set_lua(state, value_index);
165*11be35a1SLionel Sambuc     } catch (const std::bad_cast& unused_error) {
166*11be35a1SLionel Sambuc         throw value_error(F("Invalid value for key '%s'") %
167*11be35a1SLionel Sambuc                           detail::flatten_key(key));
168*11be35a1SLionel Sambuc     }
169*11be35a1SLionel Sambuc }
170*11be35a1SLionel Sambuc 
171*11be35a1SLionel Sambuc 
172*11be35a1SLionel Sambuc /// Gets the value of a node as a plain string.
173*11be35a1SLionel Sambuc ///
174*11be35a1SLionel Sambuc /// \param dotted_key The key to be looked up.
175*11be35a1SLionel Sambuc ///
176*11be35a1SLionel Sambuc /// \return The value of the located node as a string.
177*11be35a1SLionel Sambuc ///
178*11be35a1SLionel Sambuc /// \throw invalid_key_error If the provided key has an invalid format.
179*11be35a1SLionel Sambuc /// \throw unknown_key_error If the provided key is unknown.
180*11be35a1SLionel Sambuc std::string
lookup_string(const std::string & dotted_key) const181*11be35a1SLionel Sambuc config::tree::lookup_string(const std::string& dotted_key) const
182*11be35a1SLionel Sambuc {
183*11be35a1SLionel Sambuc     const detail::tree_key key = detail::parse_key(dotted_key);
184*11be35a1SLionel Sambuc     const detail::base_node* raw_node = _root->lookup_ro(key, 0);
185*11be35a1SLionel Sambuc     try {
186*11be35a1SLionel Sambuc         const leaf_node& child = dynamic_cast< const leaf_node& >(*raw_node);
187*11be35a1SLionel Sambuc         return child.to_string();
188*11be35a1SLionel Sambuc     } catch (const std::bad_cast& unused_error) {
189*11be35a1SLionel Sambuc         throw unknown_key_error(key);
190*11be35a1SLionel Sambuc     }
191*11be35a1SLionel Sambuc }
192*11be35a1SLionel Sambuc 
193*11be35a1SLionel Sambuc 
194*11be35a1SLionel Sambuc /// Sets the value of a leaf addressed by its key from a string value.
195*11be35a1SLionel Sambuc ///
196*11be35a1SLionel Sambuc /// This respects the native types of all the nodes that have been predefined.
197*11be35a1SLionel Sambuc /// For new nodes under a dynamic subtree, this has no mechanism of determining
198*11be35a1SLionel Sambuc /// what type they need to have, so they are created as plain string nodes.
199*11be35a1SLionel Sambuc ///
200*11be35a1SLionel Sambuc /// \param dotted_key The key to be registered in dotted representation.
201*11be35a1SLionel Sambuc /// \param raw_value The string representation of the value to set the node to.
202*11be35a1SLionel Sambuc ///
203*11be35a1SLionel Sambuc /// \throw invalid_key_error If the provided key has an invalid format.
204*11be35a1SLionel Sambuc /// \throw unknown_key_error If the provided key is unknown.
205*11be35a1SLionel Sambuc /// \throw value_error If the value mismatches the node type.
206*11be35a1SLionel Sambuc void
set_string(const std::string & dotted_key,const std::string & raw_value)207*11be35a1SLionel Sambuc config::tree::set_string(const std::string& dotted_key,
208*11be35a1SLionel Sambuc                          const std::string& raw_value)
209*11be35a1SLionel Sambuc {
210*11be35a1SLionel Sambuc     const detail::tree_key key = detail::parse_key(dotted_key);
211*11be35a1SLionel Sambuc     detail::base_node* raw_node = _root->lookup_rw(
212*11be35a1SLionel Sambuc         key, 0, detail::new_node< string_node >);
213*11be35a1SLionel Sambuc     try {
214*11be35a1SLionel Sambuc         leaf_node& child = dynamic_cast< leaf_node& >(*raw_node);
215*11be35a1SLionel Sambuc         child.set_string(raw_value);
216*11be35a1SLionel Sambuc     } catch (const std::bad_cast& unused_error) {
217*11be35a1SLionel Sambuc         throw value_error(F("Invalid value for key '%s'") %
218*11be35a1SLionel Sambuc                           detail::flatten_key(key));
219*11be35a1SLionel Sambuc     }
220*11be35a1SLionel Sambuc }
221*11be35a1SLionel Sambuc 
222*11be35a1SLionel Sambuc 
223*11be35a1SLionel Sambuc /// Converts the tree to a collection of key/value string pairs.
224*11be35a1SLionel Sambuc ///
225*11be35a1SLionel Sambuc /// \param dotted_key Subtree from which to start the export.
226*11be35a1SLionel Sambuc /// \param strip_key If true, remove the dotted_key prefix from the resulting
227*11be35a1SLionel Sambuc ///     properties.
228*11be35a1SLionel Sambuc ///
229*11be35a1SLionel Sambuc /// \return A map of keys to values in their textual representation.
230*11be35a1SLionel Sambuc ///
231*11be35a1SLionel Sambuc /// \throw invalid_key_error If the provided key has an invalid format.
232*11be35a1SLionel Sambuc /// \throw unknown_key_error If the provided key is unknown.
233*11be35a1SLionel Sambuc /// \throw value_error If the provided key points to a leaf.
234*11be35a1SLionel Sambuc config::properties_map
all_properties(const std::string & dotted_key,const bool strip_key) const235*11be35a1SLionel Sambuc config::tree::all_properties(const std::string& dotted_key,
236*11be35a1SLionel Sambuc                              const bool strip_key) const
237*11be35a1SLionel Sambuc {
238*11be35a1SLionel Sambuc     PRE(!strip_key || !dotted_key.empty());
239*11be35a1SLionel Sambuc 
240*11be35a1SLionel Sambuc     properties_map properties;
241*11be35a1SLionel Sambuc 
242*11be35a1SLionel Sambuc     detail::tree_key key;
243*11be35a1SLionel Sambuc     const detail::base_node* raw_node;
244*11be35a1SLionel Sambuc     if (dotted_key.empty()) {
245*11be35a1SLionel Sambuc         raw_node = _root.get();
246*11be35a1SLionel Sambuc     } else {
247*11be35a1SLionel Sambuc         key = detail::parse_key(dotted_key);
248*11be35a1SLionel Sambuc         raw_node = _root->lookup_ro(key, 0);
249*11be35a1SLionel Sambuc     }
250*11be35a1SLionel Sambuc     try {
251*11be35a1SLionel Sambuc         const detail::inner_node& child =
252*11be35a1SLionel Sambuc             dynamic_cast< const detail::inner_node& >(*raw_node);
253*11be35a1SLionel Sambuc         child.all_properties(properties, key);
254*11be35a1SLionel Sambuc     } catch (const std::bad_cast& unused_error) {
255*11be35a1SLionel Sambuc         INV(!dotted_key.empty());
256*11be35a1SLionel Sambuc         throw value_error(F("Cannot export properties from a leaf node; "
257*11be35a1SLionel Sambuc                             "'%s' given") % dotted_key);
258*11be35a1SLionel Sambuc     }
259*11be35a1SLionel Sambuc 
260*11be35a1SLionel Sambuc     if (strip_key) {
261*11be35a1SLionel Sambuc         properties_map stripped;
262*11be35a1SLionel Sambuc         for (properties_map::const_iterator iter = properties.begin();
263*11be35a1SLionel Sambuc              iter != properties.end(); ++iter) {
264*11be35a1SLionel Sambuc             stripped[(*iter).first.substr(dotted_key.length() + 1)] =
265*11be35a1SLionel Sambuc                 (*iter).second;
266*11be35a1SLionel Sambuc         }
267*11be35a1SLionel Sambuc         properties = stripped;
268*11be35a1SLionel Sambuc     }
269*11be35a1SLionel Sambuc 
270*11be35a1SLionel Sambuc     return properties;
271*11be35a1SLionel Sambuc }
272*11be35a1SLionel Sambuc 
273*11be35a1SLionel Sambuc 
274*11be35a1SLionel Sambuc /// Equality comparator.
275*11be35a1SLionel Sambuc ///
276*11be35a1SLionel Sambuc /// \param other The other object to compare this one to.
277*11be35a1SLionel Sambuc ///
278*11be35a1SLionel Sambuc /// \return True if this object and other are equal; false otherwise.
279*11be35a1SLionel Sambuc bool
operator ==(const tree & other) const280*11be35a1SLionel Sambuc config::tree::operator==(const tree& other) const
281*11be35a1SLionel Sambuc {
282*11be35a1SLionel Sambuc     // TODO(jmmv): Would be nicer to perform the comparison directly on the
283*11be35a1SLionel Sambuc     // nodes, instead of exporting the values to strings first.
284*11be35a1SLionel Sambuc     return _root == other._root || all_properties() == other.all_properties();
285*11be35a1SLionel Sambuc }
286*11be35a1SLionel Sambuc 
287*11be35a1SLionel Sambuc 
288*11be35a1SLionel Sambuc /// Inequality comparator.
289*11be35a1SLionel Sambuc ///
290*11be35a1SLionel Sambuc /// \param other The other object to compare this one to.
291*11be35a1SLionel Sambuc ///
292*11be35a1SLionel Sambuc /// \return True if this object and other are different; false otherwise.
293*11be35a1SLionel Sambuc bool
operator !=(const tree & other) const294*11be35a1SLionel Sambuc config::tree::operator!=(const tree& other) const
295*11be35a1SLionel Sambuc {
296*11be35a1SLionel Sambuc     return !(*this == other);
297*11be35a1SLionel Sambuc }
298