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 { operatorucl_deleter49 void operator() (ucl_object_t *obj) { 50 ucl_object_unref (obj); 51 } 52 }; 53 54 static int append_char(unsigned char c,size_t nchars,void * ud)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 append_len(unsigned const char * str,size_t len,void * ud)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 append_int(int64_t elt,void * ud)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 append_double(double elt,void * ud)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 default_emit_funcs()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 ucl_variable_getter(const unsigned char * data,size_t len,unsigned char **,size_t *,bool * need_free,void * ud)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 ucl_variable_replacer(const unsigned char * data,size_t len,unsigned char ** replace,size_t * replace_len,bool * need_free,void * ud)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> parse_with_strategy_function(C config_func,P parse_func,std::string & err)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 { operatorucl_iter_deleter186 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 const_iterator(const Ucl & obj)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 const_iterator()205 const_iterator() {} 206 const_iterator(const const_iterator &other) = delete; 207 const_iterator(const_iterator &&other) = default; ~const_iterator()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 { ~variable_replacervariable_replacer252 virtual ~variable_replacer() {} 253 is_variablevariable_replacer254 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 Ucl(ucl_object_t * other)263 Ucl(ucl_object_t *other) { 264 obj.reset (other); 265 } 266 267 // Shared ownership Ucl(const ucl_object_t * other)268 Ucl(const ucl_object_t *other) { 269 obj.reset (ucl_object_ref (other)); 270 } 271 Ucl(const Ucl & other)272 Ucl(const Ucl &other) { 273 obj.reset (ucl_object_ref (other.obj.get())); 274 } 275 Ucl(Ucl && other)276 Ucl(Ucl &&other) { 277 obj.swap (other.obj); 278 } 279 Ucl()280 Ucl() noexcept { 281 obj.reset (ucl_object_typed_new (UCL_NULL)); 282 } Ucl(std::nullptr_t)283 Ucl(std::nullptr_t) noexcept { 284 obj.reset (ucl_object_typed_new (UCL_NULL)); 285 } Ucl(double value)286 Ucl(double value) { 287 obj.reset (ucl_object_typed_new (UCL_FLOAT)); 288 obj->value.dv = value; 289 } Ucl(int64_t value)290 Ucl(int64_t value) { 291 obj.reset (ucl_object_typed_new (UCL_INT)); 292 obj->value.iv = value; 293 } Ucl(bool value)294 Ucl(bool value) { 295 obj.reset (ucl_object_typed_new (UCL_BOOLEAN)); 296 obj->value.iv = static_cast<int64_t>(value); 297 } Ucl(const std::string & value)298 Ucl(const std::string &value) { 299 obj.reset (ucl_object_fromstring_common (value.data (), value.size (), 300 UCL_STRING_RAW)); 301 } Ucl(const char * value)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)> Ucl(const T & t)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> Ucl(const M & m)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> Ucl(const V & v)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 type()338 ucl_type_t type () const { 339 if (obj) { 340 return ucl_object_type (obj.get ()); 341 } 342 return UCL_NULL; 343 } 344 key()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 forced_string_value()399 std::string forced_string_value () const 400 { 401 return ucl_object_tostring_forced(obj.get()); 402 } 403 size()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 at(size_t i)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 lookup(const std::string & key)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*/ > > ¯os, 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*/ > > ¯os, 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, ¯os] (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*/ > > ¯os, 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, ¯os] (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 parse(const char * in,const std::map<std::string,std::string> & vars,std::string & err)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*/ > > ¯os, 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*/ > > ¯os, 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*/ > > ¯os, 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 parse_from_file(const std::string & filename,std::string & err)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 parse_from_file(const std::string & filename,const std::map<std::string,std::string> & vars,std::string & err)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 parse_from_file(const std::string & filename,const variable_replacer & replacer,std::string & err)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 find_variable(const std::string & in)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 find_variable(const char * in)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 find_variable_from_file(const std::string & filename)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 begin()726 const_iterator begin() const 727 { 728 return const_iterator(*this); 729 } cbegin()730 const_iterator cbegin() const 731 { 732 return const_iterator(*this); 733 } end()734 const_iterator end() const 735 { 736 return const_iterator(); 737 } cend()738 const_iterator cend() const 739 { 740 return const_iterator(); 741 } 742 }; 743 744 }; 745