xref: /freebsd/contrib/libucl/include/ucl++.h (revision d0ff5773cefaf3fa41b1be3e44ca35bd9d5f68ee)
1 /*
2  * Copyright (c) 2015, Vsevolod Stakhov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *	 * Redistributions of source code must retain the above copyright
8  *	   notice, this list of conditions and the following disclaimer.
9  *	 * Redistributions in binary form must reproduce the above copyright
10  *	   notice, this list of conditions and the following disclaimer in the
11  *	   documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 
25 #pragma once
26 #include <string>
27 #include <vector>
28 #include <map>
29 #include <set>
30 #include <memory>
31 #include <iostream>
32 #include <tuple>
33 
34 #include "ucl.h"
35 
36 // C++11 API inspired by json11: https://github.com/dropbox/json11/
37 
38 namespace ucl {
39 
40 struct ucl_map_construct_t { };
41 constexpr ucl_map_construct_t ucl_map_construct = ucl_map_construct_t();
42 struct ucl_array_construct_t { };
43 constexpr ucl_array_construct_t ucl_array_construct = ucl_array_construct_t();
44 
45 class Ucl final {
46 private:
47 
48 	struct ucl_deleter {
49 		void operator() (ucl_object_t *obj) {
50 			ucl_object_unref (obj);
51 		}
52 	};
53 
54 	static int
55 	append_char (unsigned char c, size_t nchars, void *ud)
56 	{
57 		std::string *out = reinterpret_cast<std::string *>(ud);
58 
59 		out->append (nchars, (char)c);
60 
61 		return nchars;
62 	}
63 	static int
64 	append_len (unsigned const char *str, size_t len, void *ud)
65 	{
66 		std::string *out = reinterpret_cast<std::string *>(ud);
67 
68 		out->append ((const char *)str, len);
69 
70 		return len;
71 	}
72 	static int
73 	append_int (int64_t elt, void *ud)
74 	{
75 		std::string *out = reinterpret_cast<std::string *>(ud);
76 		auto nstr = std::to_string (elt);
77 
78 		out->append (nstr);
79 
80 		return nstr.size ();
81 	}
82 	static int
83 	append_double (double elt, void *ud)
84 	{
85 		std::string *out = reinterpret_cast<std::string *>(ud);
86 		auto nstr = std::to_string (elt);
87 
88 		out->append (nstr);
89 
90 		return nstr.size ();
91 	}
92 
93 	static struct ucl_emitter_functions default_emit_funcs()
94 	{
95 		struct ucl_emitter_functions func = {
96 			Ucl::append_char,
97 			Ucl::append_len,
98 			Ucl::append_int,
99 			Ucl::append_double,
100 			nullptr,
101 			nullptr
102 		};
103 
104 		return func;
105 	};
106 
107 	static bool ucl_variable_getter(const unsigned char *data, size_t len,
108 			unsigned char ** /*replace*/, size_t * /*replace_len*/, bool *need_free, void* ud)
109 	{
110 		*need_free = false;
111 
112 		auto vars = reinterpret_cast<std::set<std::string> *>(ud);
113 		if (vars && data && len != 0) {
114 			vars->emplace (data, data + len);
115 		}
116 		return false;
117 	}
118 
119 	static bool ucl_variable_replacer (const unsigned char *data, size_t len,
120 			unsigned char **replace, size_t *replace_len, bool *need_free, void* ud)
121 	{
122 		*need_free = false;
123 
124 		auto replacer = reinterpret_cast<variable_replacer *>(ud);
125 		if (!replacer) {
126 			return false;
127 		}
128 
129 		std::string var_name (data, data + len);
130 		if (!replacer->is_variable (var_name)) {
131 			return false;
132 		}
133 
134 		std::string var_value = replacer->replace (var_name);
135 		if (var_value.empty ()) {
136 			return false;
137  		}
138 
139 		*replace = (unsigned char *)UCL_ALLOC (var_value.size ());
140 		memcpy (*replace, var_value.data (), var_value.size ());
141 
142 		*replace_len = var_value.size ();
143 		*need_free = true;
144 
145 		return true;
146 	}
147 
148 	template <typename C, typename P>
149 	static Ucl parse_with_strategy_function (C config_func, P parse_func, std::string &err)
150 	{
151 		auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
152 
153 		config_func (parser);
154 
155 		if (!parse_func (parser)) {
156 			const char *error = ucl_parser_get_error (parser); //Assigning here without checking result first causes a
157 			if( error != NULL ) err.assign(error);             //	crash if ucl_parser_get_error returns NULL
158 			ucl_parser_free (parser);
159 
160 			return nullptr;
161 		}
162 
163 		auto obj = ucl_parser_get_object (parser);
164 		ucl_parser_free (parser);
165 
166 		// Obj will handle ownership
167 		return Ucl (obj);
168 	}
169 
170 	std::unique_ptr<ucl_object_t, ucl_deleter> obj;
171 
172 public:
173 	struct macro_handler_s {
174 		ucl_macro_handler         handler;
175 		ucl_context_macro_handler ctx_handler;
176 	};
177 
178 	struct macro_userdata_s {
179 		ucl_parser    *parser;
180 		void          *userdata;
181 	};
182 
183 	class const_iterator {
184 	private:
185 		struct ucl_iter_deleter {
186 			void operator() (ucl_object_iter_t it) {
187 				ucl_object_iterate_free (it);
188 			}
189 		};
190 		std::shared_ptr<void> it;
191 		std::unique_ptr<Ucl> cur;
192 	public:
193 		typedef std::forward_iterator_tag iterator_category;
194 
195 		const_iterator(const Ucl &obj) {
196 			it = std::shared_ptr<void>(ucl_object_iterate_new (obj.obj.get()),
197 				ucl_iter_deleter());
198 			cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
199 			if (!cur->obj) {
200 				it.reset ();
201 				cur.reset ();
202 			}
203 		}
204 
205 		const_iterator() {}
206 		const_iterator(const const_iterator &other) = delete;
207 		const_iterator(const_iterator &&other) = default;
208 		~const_iterator() {}
209 
210 		const_iterator& operator=(const const_iterator &other) = delete;
211 		const_iterator& operator=(const_iterator &&other) = default;
212 
213 		bool operator==(const const_iterator &other) const
214 		{
215 			if (cur && other.cur) {
216 				return cur->obj.get() == other.cur->obj.get();
217 			}
218 
219 			return !cur && !other.cur;
220 		}
221 
222 		bool operator!=(const const_iterator &other) const
223 		{
224 			return !(*this == other);
225 		}
226 
227 		const_iterator& operator++()
228 		{
229 			if (it) {
230 				cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
231 			}
232 
233 			if (cur && !cur->obj) {
234 				it.reset ();
235 				cur.reset ();
236 			}
237 
238 			return *this;
239 		}
240 
241 		const Ucl& operator*() const
242 		{
243 			return *cur;
244 		}
245 		const Ucl* operator->() const
246 		{
247 			return cur.get();
248 		}
249 	};
250 
251 	struct variable_replacer {
252 		virtual ~variable_replacer() {}
253 
254 		virtual bool is_variable (const std::string &str) const
255 		{
256 			return !str.empty ();
257 		}
258 
259 		virtual std::string replace (const std::string &var) const = 0;
260 	};
261 
262 	// We grab ownership if get non-const ucl_object_t
263 	Ucl(ucl_object_t *other) {
264 		obj.reset (other);
265 	}
266 
267 	// Shared ownership
268 	Ucl(const ucl_object_t *other) {
269 		obj.reset (ucl_object_ref (other));
270 	}
271 
272 	Ucl(const Ucl &other) {
273 		obj.reset (ucl_object_ref (other.obj.get()));
274 	}
275 
276 	Ucl(Ucl &&other) {
277 		obj.swap (other.obj);
278 	}
279 
280 	Ucl() noexcept {
281 		obj.reset (ucl_object_typed_new (UCL_NULL));
282 	}
283 	Ucl(std::nullptr_t) noexcept {
284 		obj.reset (ucl_object_typed_new (UCL_NULL));
285 	}
286 	Ucl(double value) {
287 		obj.reset (ucl_object_typed_new (UCL_FLOAT));
288 		obj->value.dv = value;
289 	}
290 	Ucl(int64_t value) {
291 		obj.reset (ucl_object_typed_new (UCL_INT));
292 		obj->value.iv = value;
293 	}
294 	Ucl(bool value) {
295 		obj.reset (ucl_object_typed_new (UCL_BOOLEAN));
296 		obj->value.iv = static_cast<int64_t>(value);
297 	}
298 	Ucl(const std::string &value) {
299 		obj.reset (ucl_object_fromstring_common (value.data (), value.size (),
300 				UCL_STRING_RAW));
301 	}
302 	Ucl(const char *value) {
303 		obj.reset (ucl_object_fromstring_common (value, 0, UCL_STRING_RAW));
304 	}
305 
306 	// Implicit constructor: anything with a to_json() function.
307 	template <class T, class = decltype(&T::to_ucl)>
308 	Ucl(const T &t) : Ucl(t.to_ucl()) {}
309 
310 	// Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
311 	template <class M, typename std::enable_if<
312 		std::is_constructible<std::string, typename M::key_type>::value
313 		&& std::is_constructible<Ucl, typename M::mapped_type>::value,
314 		int>::type = 0>
315 	Ucl(const M &m) {
316 		obj.reset (ucl_object_typed_new (UCL_OBJECT));
317 		auto cobj = obj.get ();
318 
319 		for (const auto &e : m) {
320 			ucl_object_insert_key (cobj, ucl_object_ref (e.second.obj.get()),
321 					e.first.data (), e.first.size (), true);
322 		}
323 	}
324 
325 	// Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
326 	template <class V, typename std::enable_if<
327 		std::is_constructible<Ucl, typename V::value_type>::value,
328 		int>::type = 0>
329 	Ucl(const V &v) {
330 		obj.reset (ucl_object_typed_new (UCL_ARRAY));
331 		auto cobj = obj.get ();
332 
333 		for (const auto &e : v) {
334 			ucl_array_append (cobj, ucl_object_ref (e.obj.get()));
335 		}
336 	}
337 
338 	ucl_type_t type () const {
339 		if (obj) {
340 			return ucl_object_type (obj.get ());
341 		}
342 		return UCL_NULL;
343 	}
344 
345 	std::string key () const {
346 		std::string res;
347 
348 		if (obj->key) {
349 			res.assign (obj->key, obj->keylen);
350 		}
351 
352 		return res;
353 	}
354 
355 	double number_value (const double default_val = 0.0) const
356 	{
357 		double res;
358 
359 		if (ucl_object_todouble_safe(obj.get(), &res)) {
360 			return res;
361 		}
362 
363 		return default_val;
364 	}
365 
366 	int64_t int_value (const int64_t default_val = 0) const
367 	{
368 		int64_t res;
369 
370 		if (ucl_object_toint_safe(obj.get(), &res)) {
371 			return res;
372 		}
373 
374 		return default_val;
375 	}
376 
377 	bool bool_value (const bool default_val = false) const
378 	{
379 		bool res;
380 
381 		if (ucl_object_toboolean_safe(obj.get(), &res)) {
382 			return res;
383 		}
384 
385 		return default_val;
386 	}
387 
388 	std::string string_value (const std::string& default_val = "") const
389 	{
390 		const char* res = nullptr;
391 
392 		if (ucl_object_tostring_safe(obj.get(), &res)) {
393 			return res;
394 		}
395 
396 		return default_val;
397 	}
398 
399 	std::string forced_string_value () const
400 	{
401 		return ucl_object_tostring_forced(obj.get());
402 	}
403 
404 	size_t size () const
405 	{
406 		if (type () == UCL_ARRAY) {
407 			return ucl_array_size (obj.get());
408 		}
409 
410 		return 0;
411 	}
412 
413 	Ucl at (size_t i) const
414 	{
415 		if (type () == UCL_ARRAY) {
416 			return Ucl (ucl_array_find_index (obj.get(), i));
417 		}
418 
419 		return Ucl (nullptr);
420 	}
421 
422 	Ucl lookup (const std::string &key) const
423 	{
424 		if (type () == UCL_OBJECT) {
425 			return Ucl (ucl_object_lookup_len (obj.get(),
426 					key.data (), key.size ()));
427 		}
428 
429 		return Ucl (nullptr);
430 	}
431 
432 	inline Ucl operator[] (size_t i) const
433 	{
434 		return at(i);
435 	}
436 
437 	inline Ucl operator[](const std::string &key) const
438 	{
439 		return lookup(key);
440 	}
441 	// Serialize.
442 	void dump (std::string &out, ucl_emitter_t type = UCL_EMIT_JSON) const
443 	{
444 		struct ucl_emitter_functions cbdata;
445 
446 		cbdata = Ucl::default_emit_funcs();
447 		cbdata.ud = reinterpret_cast<void *>(&out);
448 
449 		ucl_object_emit_full (obj.get(), type, &cbdata, nullptr);
450 	}
451 
452 	std::string dump (ucl_emitter_t type = UCL_EMIT_JSON) const
453 	{
454 		std::string out;
455 
456 		dump (out, type);
457 
458 		return out;
459 	}
460 
461 	static Ucl parse (const std::string &in, std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
462 	{
463 		return parse (in, std::map<std::string, std::string>(), err, duplicate_strategy);
464 	}
465 
466 	static Ucl parse (const std::string &in, const std::map<std::string, std::string> &vars,
467 			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
468 	{
469 		std::vector< std::tuple< std::string, macro_handler_s, void * > > emptyVector;
470 		return parse ( in, vars, emptyVector, err, duplicate_strategy );
471 	}
472 
473 	//Macro handler will receive a macro_userdata_s as void *ud
474 	static Ucl parse (const std::string &in,
475 			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
476 			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
477 	{
478 		return parse (in, std::map<std::string, std::string>(), macros, err, duplicate_strategy);
479 	}
480 
481 	//Macro handler will receive a macro_userdata_s as void *ud
482 	static Ucl parse (const std::string &in, const std::map<std::string, std::string> &vars,
483 			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
484 			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
485 	{
486 		//Preserve macro_userdata_s memory for later use in parse_with_strategy_function()
487 		std::vector<macro_userdata_s> userdata_list;
488 		userdata_list.reserve (macros.size());
489 		auto config_func = [&userdata_list, &vars, &macros] (ucl_parser *parser) {
490 			for (const auto & item : vars) {
491 				ucl_parser_register_variable (parser, item.first.c_str (), item.second.c_str ());
492 			}
493 			for (auto & macro : macros) {
494 				userdata_list.push_back ({parser, std::get<2>(macro)});
495 				if (std::get<1>(macro).handler != NULL) {
496 					ucl_parser_register_macro (parser,
497 								std::get<0>(macro).c_str(),
498 								std::get<1>(macro).handler,
499 								reinterpret_cast<void*>(&userdata_list.back()));
500 				}
501 				else if (std::get<1>(macro).ctx_handler != NULL) {
502 					ucl_parser_register_context_macro (parser,
503 									std::get<0>(macro).c_str(),
504 									std::get<1>(macro).ctx_handler,
505 									reinterpret_cast<void*>(&userdata_list.back()));
506 				}
507 			}
508 		};
509 
510 		auto parse_func = [&in, &duplicate_strategy] (struct ucl_parser *parser) -> bool {
511 			return ucl_parser_add_chunk_full (parser,
512 							(unsigned char *) in.data (),
513 							in.size (),
514 							(unsigned int)ucl_parser_get_default_priority (parser),
515 							duplicate_strategy,
516 							UCL_PARSE_UCL);
517 		};
518 
519 		return parse_with_strategy_function (config_func, parse_func, err);
520 	}
521 
522 	static Ucl parse (const std::string &in, const variable_replacer &replacer,
523 			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
524 	{
525 		std::vector< std::tuple< std::string, macro_handler_s, void * > > emptyVector;
526 		return parse ( in, replacer, emptyVector, err, duplicate_strategy );
527 	}
528 
529 	//Macro handler will receive a macro_userdata_s as void *ud
530 	static Ucl parse (const std::string &in, const variable_replacer &replacer,
531 			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
532 			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
533 	{
534 		//Preserve macro_userdata_s memory for later use in parse_with_strategy_function()
535 		std::vector<macro_userdata_s> userdata_list;
536 		userdata_list.reserve (macros.size());
537 		auto config_func = [&userdata_list, &replacer, &macros] (ucl_parser *parser) {
538 			ucl_parser_set_variables_handler (parser, ucl_variable_replacer, &const_cast<variable_replacer &>(replacer));
539 			for (auto & macro : macros) {
540 				userdata_list.push_back ({parser, std::get<2>(macro)});
541 				if (std::get<1>(macro).handler != NULL) {
542 					ucl_parser_register_macro (parser,
543 								std::get<0>(macro).c_str(),
544 								std::get<1>(macro).handler,
545 								reinterpret_cast<void*>(&userdata_list.back()));
546 				}
547 				else if (std::get<1>(macro).ctx_handler != NULL) {
548 					ucl_parser_register_context_macro (parser,
549 									std::get<0>(macro).c_str(),
550 									std::get<1>(macro).ctx_handler,
551 									reinterpret_cast<void*>(&userdata_list.back()));
552 				}
553 			}
554 		};
555 
556 		auto parse_func = [&in, &duplicate_strategy] (struct ucl_parser *parser) -> bool {
557 			return ucl_parser_add_chunk_full (parser,
558 							(unsigned char *) in.data (),
559 							in.size (),
560 							(unsigned int)ucl_parser_get_default_priority (parser),
561 							duplicate_strategy,
562 							UCL_PARSE_UCL);
563 		};
564 
565 		return parse_with_strategy_function (config_func, parse_func, err);
566 	}
567 
568 	static Ucl parse (const char *in, std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
569 	{
570 		return parse (in, std::map<std::string, std::string>(), err, duplicate_strategy);
571 	}
572 
573 	static Ucl parse (const char *in, const std::map<std::string, std::string> &vars, std::string &err)
574 	{
575 		if (!in) {
576 			err = "null input";
577 			return nullptr;
578 		}
579 		return parse (std::string (in), vars, err);
580 	}
581 
582 	//Macro handler will receive a macro_userdata_s as void *ud
583 	static Ucl parse (const char *in,
584 			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
585 			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
586 	{
587 		return parse (in, std::map<std::string, std::string>(), macros, err, duplicate_strategy);
588 	}
589 
590 	//Macro handler will receive a macro_userdata_s as void *ud
591 	static Ucl parse (const char *in, const std::map<std::string, std::string> &vars,
592 			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
593 			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
594 	{
595 		if (!in) {
596 			err = "null input";
597 			return nullptr;
598 		}
599 		return parse (std::string (in), vars, macros, err, duplicate_strategy);
600 	}
601 
602 	static Ucl parse (const char *in, const variable_replacer &replacer,
603 			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
604 	{
605 		if (!in) {
606 			err = "null input";
607 			return nullptr;
608 		}
609 		return parse (std::string(in), replacer, err, duplicate_strategy);
610 	}
611 
612 	//Macro handler will receive a macro_userdata_s as void *ud
613 	static Ucl parse (const char *in, const variable_replacer &replacer,
614 			std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
615 			std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
616 	{
617 		if (!in) {
618 			err = "null input";
619 			return nullptr;
620 		}
621 		return parse (std::string (in), replacer, macros, err, duplicate_strategy);
622 	}
623 
624 	static Ucl parse_from_file (const std::string &filename, std::string &err)
625 	{
626 		return parse_from_file (filename, std::map<std::string, std::string>(), err);
627 	}
628 
629 	static Ucl parse_from_file (const std::string &filename, const std::map<std::string, std::string> &vars, std::string &err)
630 	{
631 		auto config_func = [&vars] (ucl_parser *parser) {
632 			for (const auto & item : vars) {
633 				ucl_parser_register_variable (parser, item.first.c_str (), item.second.c_str ());
634             }
635 		};
636 
637 		auto parse_func = [&filename] (ucl_parser *parser) {
638 			return ucl_parser_add_file (parser, filename.c_str ());
639 		};
640 
641 		return parse_with_strategy_function (config_func, parse_func, err);
642 	}
643 
644 	static Ucl parse_from_file (const std::string &filename, const variable_replacer &replacer, std::string &err)
645 	{
646 		auto config_func = [&replacer] (ucl_parser *parser) {
647 			ucl_parser_set_variables_handler (parser, ucl_variable_replacer,
648 				&const_cast<variable_replacer &>(replacer));
649 		};
650 
651 		auto parse_func = [&filename] (ucl_parser *parser) {
652 			return ucl_parser_add_file (parser, filename.c_str ());
653 		};
654 
655 		return parse_with_strategy_function (config_func, parse_func, err);
656 	}
657 
658 	static std::vector<std::string> find_variable (const std::string &in)
659 	{
660 		auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
661 
662 		std::set<std::string> vars;
663 		ucl_parser_set_variables_handler (parser, ucl_variable_getter, &vars);
664 		ucl_parser_add_chunk (parser, (const unsigned char *)in.data (), in.size ());
665 		ucl_parser_free (parser);
666 
667 		std::vector<std::string> result;
668 		std::move (vars.begin (), vars.end (), std::back_inserter (result));
669 		return result;
670 	}
671 
672 	static std::vector<std::string> find_variable (const char *in)
673 	{
674 		if (!in) {
675 			return std::vector<std::string>();
676 		}
677 		return find_variable (std::string (in));
678 	}
679 
680 	static std::vector<std::string> find_variable_from_file (const std::string &filename)
681 	{
682 		auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
683 
684 		std::set<std::string> vars;
685 		ucl_parser_set_variables_handler (parser, ucl_variable_getter, &vars);
686 		ucl_parser_add_file (parser, filename.c_str ());
687 		ucl_parser_free (parser);
688 
689 		std::vector<std::string> result;
690 		std::move (vars.begin (), vars.end (), std::back_inserter (result));
691 		return result;
692 	}
693 
694 	Ucl& operator= (Ucl rhs)
695 	{
696 		obj.swap (rhs.obj);
697 		return *this;
698 	}
699 
700 	bool operator== (const Ucl &rhs) const
701 	{
702 		return ucl_object_compare (obj.get(), rhs.obj.get ()) == 0;
703 	}
704 	bool operator< (const Ucl &rhs) const
705 	{
706 		return ucl_object_compare (obj.get(), rhs.obj.get ()) < 0;
707 	}
708 	bool operator!= (const Ucl &rhs) const { return !(*this == rhs); }
709 	bool operator<= (const Ucl &rhs) const { return !(rhs < *this); }
710 	bool operator> (const Ucl &rhs) const { return (rhs < *this); }
711 	bool operator>= (const Ucl &rhs) const { return !(*this < rhs); }
712 
713 	explicit operator bool () const
714 	{
715 		if (!obj || type() == UCL_NULL) {
716 			return false;
717 		}
718 
719 		if (type () == UCL_BOOLEAN) {
720 			return bool_value ();
721 		}
722 
723 		return true;
724 	}
725 
726 	const_iterator begin() const
727 	{
728 		return const_iterator(*this);
729 	}
730 	const_iterator cbegin() const
731 	{
732 		return const_iterator(*this);
733 	}
734 	const_iterator end() const
735 	{
736 		return const_iterator();
737 	}
738 	const_iterator cend() const
739 	{
740 		return const_iterator();
741 	}
742 };
743 
744 };
745