1 /* Copyright (c) 2014, Vsevolod Stakhov 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 met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution. 11 * 12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 */ 23 24 /** 25 * @file lua ucl bindings 26 */ 27 28 #include "ucl.h" 29 #include "ucl_internal.h" 30 #include "lua_ucl.h" 31 #include <strings.h> 32 #include <zconf.h> 33 34 /*** 35 * @module ucl 36 * This lua module allows to parse objects from strings and to store data into 37 * ucl objects. It uses `libucl` C library to parse and manipulate with ucl objects. 38 * @example 39 local ucl = require("ucl") 40 41 local parser = ucl.parser() 42 local res,err = parser:parse_string('{key=value}') 43 44 if not res then 45 print('parser error: ' .. err) 46 else 47 local obj = parser:get_object() 48 local got = ucl.to_format(obj, 'json') 49 endif 50 51 local table = { 52 str = 'value', 53 num = 100500, 54 null = ucl.null, 55 func = function () 56 return 'huh' 57 end 58 } 59 60 print(ucl.to_format(table, 'ucl')) 61 -- Output: 62 --[[ 63 num = 100500; 64 str = "value"; 65 null = null; 66 func = "huh"; 67 --]] 68 */ 69 70 #define PARSER_META "ucl.parser.meta" 71 #define EMITTER_META "ucl.emitter.meta" 72 #define NULL_META "null.emitter.meta" 73 #define OBJECT_META "ucl.object.meta" 74 75 static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj); 76 static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, bool allow_array); 77 static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx); 78 static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx); 79 80 static void *ucl_null; 81 82 /** 83 * Push a single element of an object to lua 84 * @param L 85 * @param key 86 * @param obj 87 */ 88 static void 89 ucl_object_lua_push_element (lua_State *L, const char *key, 90 const ucl_object_t *obj) 91 { 92 lua_pushstring (L, key); 93 ucl_object_push_lua (L, obj, true); 94 lua_settable (L, -3); 95 } 96 97 static void 98 lua_ucl_userdata_dtor (void *ud) 99 { 100 struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud; 101 102 luaL_unref (fd->L, LUA_REGISTRYINDEX, fd->idx); 103 if (fd->ret != NULL) { 104 free (fd->ret); 105 } 106 free (fd); 107 } 108 109 static const char * 110 lua_ucl_userdata_emitter (void *ud) 111 { 112 struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud; 113 const char *out = ""; 114 115 lua_rawgeti (fd->L, LUA_REGISTRYINDEX, fd->idx); 116 117 lua_pcall (fd->L, 0, 1, 0); 118 out = lua_tostring (fd->L, -1); 119 120 if (out != NULL) { 121 /* We need to store temporary string in a more appropriate place */ 122 if (fd->ret) { 123 free (fd->ret); 124 } 125 fd->ret = strdup (out); 126 } 127 128 lua_settop (fd->L, 0); 129 130 return fd->ret; 131 } 132 133 /** 134 * Push a single object to lua 135 * @param L 136 * @param obj 137 * @return 138 */ 139 static int 140 ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj, 141 bool allow_array) 142 { 143 const ucl_object_t *cur; 144 ucl_object_iter_t it = NULL; 145 int nelt = 0; 146 147 if (allow_array && obj->next != NULL) { 148 /* Actually we need to push this as an array */ 149 return ucl_object_lua_push_array (L, obj); 150 } 151 152 /* Optimize allocation by preallocation of table */ 153 while (ucl_object_iterate (obj, &it, true) != NULL) { 154 nelt ++; 155 } 156 157 lua_createtable (L, 0, nelt); 158 it = NULL; 159 160 while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) { 161 ucl_object_lua_push_element (L, ucl_object_key (cur), cur); 162 } 163 164 return 1; 165 } 166 167 /** 168 * Push an array to lua as table indexed by integers 169 * @param L 170 * @param obj 171 * @return 172 */ 173 static int 174 ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj) 175 { 176 const ucl_object_t *cur; 177 ucl_object_iter_t it; 178 int i = 1, nelt = 0; 179 180 if (obj->type == UCL_ARRAY) { 181 nelt = obj->len; 182 it = ucl_object_iterate_new (obj); 183 lua_createtable (L, nelt, 0); 184 185 while ((cur = ucl_object_iterate_safe (it, true))) { 186 ucl_object_push_lua (L, cur, false); 187 lua_rawseti (L, -2, i); 188 i ++; 189 } 190 } 191 else { 192 /* Optimize allocation by preallocation of table */ 193 LL_FOREACH (obj, cur) { 194 nelt ++; 195 } 196 197 lua_createtable (L, nelt, 0); 198 199 LL_FOREACH (obj, cur) { 200 ucl_object_push_lua (L, cur, false); 201 lua_rawseti (L, -2, i); 202 i ++; 203 } 204 } 205 206 return 1; 207 } 208 209 /** 210 * Push a simple object to lua depending on its actual type 211 */ 212 static int 213 ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, 214 bool allow_array) 215 { 216 struct ucl_lua_funcdata *fd; 217 218 if (allow_array && obj->next != NULL) { 219 /* Actually we need to push this as an array */ 220 return ucl_object_lua_push_array (L, obj); 221 } 222 223 switch (obj->type) { 224 case UCL_BOOLEAN: 225 lua_pushboolean (L, ucl_obj_toboolean (obj)); 226 break; 227 case UCL_STRING: 228 lua_pushstring (L, ucl_obj_tostring (obj)); 229 break; 230 case UCL_INT: 231 #if LUA_VERSION_NUM >= 501 232 lua_pushinteger (L, ucl_obj_toint (obj)); 233 #else 234 lua_pushnumber (L, ucl_obj_toint (obj)); 235 #endif 236 break; 237 case UCL_FLOAT: 238 case UCL_TIME: 239 lua_pushnumber (L, ucl_obj_todouble (obj)); 240 break; 241 case UCL_NULL: 242 lua_getfield (L, LUA_REGISTRYINDEX, "ucl.null"); 243 break; 244 case UCL_USERDATA: 245 fd = (struct ucl_lua_funcdata *)obj->value.ud; 246 lua_rawgeti (L, LUA_REGISTRYINDEX, fd->idx); 247 break; 248 default: 249 lua_pushnil (L); 250 break; 251 } 252 253 return 1; 254 } 255 256 /*** 257 * @function ucl_object_push_lua(L, obj, allow_array) 258 * This is a `C` function to push `UCL` object as lua variable. This function 259 * converts `obj` to lua representation using the following conversions: 260 * 261 * - *scalar* values are directly presented by lua objects 262 * - *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`, 263 * this can be used to pass functions from lua to c and vice-versa 264 * - *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations 265 * - *objects* are converted to lua tables with string indicies 266 * @param {lua_State} L lua state pointer 267 * @param {ucl_object_t} obj object to push 268 * @param {bool} allow_array expand implicit arrays (should be true for all but partial arrays) 269 * @return {int} `1` if an object is pushed to lua 270 */ 271 int 272 ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array) 273 { 274 switch (obj->type) { 275 case UCL_OBJECT: 276 return ucl_object_lua_push_object (L, obj, allow_array); 277 case UCL_ARRAY: 278 return ucl_object_lua_push_array (L, obj); 279 default: 280 return ucl_object_lua_push_scalar (L, obj, allow_array); 281 } 282 } 283 284 /** 285 * Parse lua table into object top 286 * @param L 287 * @param top 288 * @param idx 289 */ 290 static ucl_object_t * 291 ucl_object_lua_fromtable (lua_State *L, int idx) 292 { 293 ucl_object_t *obj, *top = NULL; 294 size_t keylen; 295 const char *k; 296 bool is_array = true; 297 int max = INT_MIN; 298 299 if (idx < 0) { 300 /* For negative indicies we want to invert them */ 301 idx = lua_gettop (L) + idx + 1; 302 } 303 /* Check for array */ 304 lua_pushnil (L); 305 while (lua_next (L, idx) != 0) { 306 if (lua_type (L, -2) == LUA_TNUMBER) { 307 double num = lua_tonumber (L, -2); 308 if (num == (int)num) { 309 if (num > max) { 310 max = num; 311 } 312 } 313 else { 314 /* Keys are not integer */ 315 lua_pop (L, 2); 316 is_array = false; 317 break; 318 } 319 } 320 else { 321 /* Keys are not numeric */ 322 lua_pop (L, 2); 323 is_array = false; 324 break; 325 } 326 lua_pop (L, 1); 327 } 328 329 /* Table iterate */ 330 if (is_array) { 331 int i; 332 333 top = ucl_object_typed_new (UCL_ARRAY); 334 for (i = 1; i <= max; i ++) { 335 lua_pushinteger (L, i); 336 lua_gettable (L, idx); 337 obj = ucl_object_lua_fromelt (L, lua_gettop (L)); 338 if (obj != NULL) { 339 ucl_array_append (top, obj); 340 } 341 lua_pop (L, 1); 342 } 343 } 344 else { 345 lua_pushnil (L); 346 top = ucl_object_typed_new (UCL_OBJECT); 347 while (lua_next (L, idx) != 0) { 348 /* copy key to avoid modifications */ 349 k = lua_tolstring (L, -2, &keylen); 350 obj = ucl_object_lua_fromelt (L, lua_gettop (L)); 351 352 if (obj != NULL) { 353 ucl_object_insert_key (top, obj, k, keylen, true); 354 } 355 lua_pop (L, 1); 356 } 357 } 358 359 return top; 360 } 361 362 /** 363 * Get a single element from lua to object obj 364 * @param L 365 * @param obj 366 * @param idx 367 */ 368 static ucl_object_t * 369 ucl_object_lua_fromelt (lua_State *L, int idx) 370 { 371 int type; 372 double num; 373 ucl_object_t *obj = NULL; 374 struct ucl_lua_funcdata *fd; 375 376 type = lua_type (L, idx); 377 378 switch (type) { 379 case LUA_TSTRING: 380 obj = ucl_object_fromstring_common (lua_tostring (L, idx), 0, 0); 381 break; 382 case LUA_TNUMBER: 383 num = lua_tonumber (L, idx); 384 if (num == (int64_t)num) { 385 obj = ucl_object_fromint (num); 386 } 387 else { 388 obj = ucl_object_fromdouble (num); 389 } 390 break; 391 case LUA_TBOOLEAN: 392 obj = ucl_object_frombool (lua_toboolean (L, idx)); 393 break; 394 case LUA_TUSERDATA: 395 if (lua_topointer (L, idx) == ucl_null) { 396 obj = ucl_object_typed_new (UCL_NULL); 397 } 398 break; 399 case LUA_TTABLE: 400 case LUA_TFUNCTION: 401 case LUA_TTHREAD: 402 if (luaL_getmetafield (L, idx, "__gen_ucl")) { 403 if (lua_isfunction (L, -1)) { 404 lua_settop (L, 3); /* gen, obj, func */ 405 lua_insert (L, 1); /* func, gen, obj */ 406 lua_insert (L, 2); /* func, obj, gen */ 407 lua_call(L, 2, 1); 408 obj = ucl_object_lua_fromelt (L, 1); 409 } 410 lua_pop (L, 2); 411 } 412 else { 413 if (type == LUA_TTABLE) { 414 obj = ucl_object_lua_fromtable (L, idx); 415 } 416 else if (type == LUA_TFUNCTION) { 417 fd = malloc (sizeof (*fd)); 418 if (fd != NULL) { 419 lua_pushvalue (L, idx); 420 fd->L = L; 421 fd->ret = NULL; 422 fd->idx = luaL_ref (L, LUA_REGISTRYINDEX); 423 424 obj = ucl_object_new_userdata (lua_ucl_userdata_dtor, 425 lua_ucl_userdata_emitter, (void *)fd); 426 } 427 } 428 } 429 break; 430 } 431 432 return obj; 433 } 434 435 /** 436 * @function ucl_object_lua_import(L, idx) 437 * Extracts ucl object from lua variable at `idx` position, 438 * @see ucl_object_push_lua for conversion definitions 439 * @param {lua_state} L lua state machine pointer 440 * @param {int} idx index where the source variable is placed 441 * @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1, 442 * this object thus needs to be unref'ed after usage. 443 */ 444 ucl_object_t * 445 ucl_object_lua_import (lua_State *L, int idx) 446 { 447 ucl_object_t *obj; 448 int t; 449 450 t = lua_type (L, idx); 451 switch (t) { 452 case LUA_TTABLE: 453 obj = ucl_object_lua_fromtable (L, idx); 454 break; 455 default: 456 obj = ucl_object_lua_fromelt (L, idx); 457 break; 458 } 459 460 return obj; 461 } 462 463 static int 464 lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type) 465 { 466 unsigned char *result; 467 468 result = ucl_object_emit (obj, type); 469 470 if (result != NULL) { 471 lua_pushstring (L, (const char *)result); 472 free (result); 473 } 474 else { 475 lua_pushnil (L); 476 } 477 478 return 1; 479 } 480 481 static int 482 lua_ucl_parser_init (lua_State *L) 483 { 484 struct ucl_parser *parser, **pparser; 485 int flags = 0; 486 487 if (lua_gettop (L) >= 1) { 488 flags = lua_tonumber (L, 1); 489 } 490 491 parser = ucl_parser_new (flags); 492 if (parser == NULL) { 493 lua_pushnil (L); 494 } 495 496 pparser = lua_newuserdata (L, sizeof (parser)); 497 *pparser = parser; 498 luaL_getmetatable (L, PARSER_META); 499 lua_setmetatable (L, -2); 500 501 return 1; 502 } 503 504 static struct ucl_parser * 505 lua_ucl_parser_get (lua_State *L, int index) 506 { 507 return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META)); 508 } 509 510 static ucl_object_t * 511 lua_ucl_object_get (lua_State *L, int index) 512 { 513 return *((ucl_object_t **) luaL_checkudata(L, index, OBJECT_META)); 514 } 515 516 static void 517 lua_ucl_push_opaque (lua_State *L, ucl_object_t *obj) 518 { 519 ucl_object_t **pobj; 520 521 pobj = lua_newuserdata (L, sizeof (*pobj)); 522 *pobj = obj; 523 luaL_getmetatable (L, OBJECT_META); 524 lua_setmetatable (L, -2); 525 } 526 527 /*** 528 * @method parser:parse_file(name) 529 * Parse UCL object from file. 530 * @param {string} name filename to parse 531 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned 532 @example 533 local parser = ucl.parser() 534 local res,err = parser:parse_file('/some/file.conf') 535 536 if not res then 537 print('parser error: ' .. err) 538 else 539 -- Do something with object 540 end 541 */ 542 static int 543 lua_ucl_parser_parse_file (lua_State *L) 544 { 545 struct ucl_parser *parser; 546 const char *file; 547 int ret = 2; 548 549 parser = lua_ucl_parser_get (L, 1); 550 file = luaL_checkstring (L, 2); 551 552 if (parser != NULL && file != NULL) { 553 if (ucl_parser_add_file (parser, file)) { 554 lua_pushboolean (L, true); 555 ret = 1; 556 } 557 else { 558 lua_pushboolean (L, false); 559 lua_pushstring (L, ucl_parser_get_error (parser)); 560 } 561 } 562 else { 563 lua_pushboolean (L, false); 564 lua_pushstring (L, "invalid arguments"); 565 } 566 567 return ret; 568 } 569 570 /*** 571 * @method parser:parse_string(input) 572 * Parse UCL object from file. 573 * @param {string} input string to parse 574 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned 575 */ 576 static int 577 lua_ucl_parser_parse_string (lua_State *L) 578 { 579 struct ucl_parser *parser; 580 const char *string; 581 size_t llen; 582 int ret = 2; 583 584 parser = lua_ucl_parser_get (L, 1); 585 string = luaL_checklstring (L, 2, &llen); 586 587 if (parser != NULL && string != NULL) { 588 if (ucl_parser_add_chunk (parser, (const unsigned char *)string, llen)) { 589 lua_pushboolean (L, true); 590 ret = 1; 591 } 592 else { 593 lua_pushboolean (L, false); 594 lua_pushstring (L, ucl_parser_get_error (parser)); 595 } 596 } 597 else { 598 lua_pushboolean (L, false); 599 lua_pushstring (L, "invalid arguments"); 600 } 601 602 return ret; 603 } 604 605 /*** 606 * @method parser:get_object() 607 * Get top object from parser and export it to lua representation. 608 * @return {variant or nil} ucl object as lua native variable 609 */ 610 static int 611 lua_ucl_parser_get_object (lua_State *L) 612 { 613 struct ucl_parser *parser; 614 ucl_object_t *obj; 615 int ret = 1; 616 617 parser = lua_ucl_parser_get (L, 1); 618 obj = ucl_parser_get_object (parser); 619 620 if (obj != NULL) { 621 ret = ucl_object_push_lua (L, obj, false); 622 /* no need to keep reference */ 623 ucl_object_unref (obj); 624 } 625 else { 626 lua_pushnil (L); 627 } 628 629 return ret; 630 } 631 632 /*** 633 * @method parser:get_object_wrapped() 634 * Get top object from parser and export it to userdata object without 635 * unwrapping to lua. 636 * @return {ucl.object or nil} ucl object wrapped variable 637 */ 638 static int 639 lua_ucl_parser_get_object_wrapped (lua_State *L) 640 { 641 struct ucl_parser *parser; 642 ucl_object_t *obj; 643 int ret = 1; 644 645 parser = lua_ucl_parser_get (L, 1); 646 obj = ucl_parser_get_object (parser); 647 648 if (obj != NULL) { 649 lua_ucl_push_opaque (L, obj); 650 } 651 else { 652 lua_pushnil (L); 653 } 654 655 return ret; 656 } 657 658 /*** 659 * @method parser:validate(schema) 660 * Validates the top object in the parser against schema. Schema might be 661 * another object or a string that represents file to load schema from. 662 * 663 * @param {string/table} schema input schema 664 * @return {result,err} two values: boolean result and the corresponding error 665 * 666 */ 667 static int 668 lua_ucl_parser_validate (lua_State *L) 669 { 670 struct ucl_parser *parser, *schema_parser; 671 ucl_object_t *schema; 672 const char *schema_file; 673 struct ucl_schema_error err; 674 675 parser = lua_ucl_parser_get (L, 1); 676 677 if (parser && parser->top_obj) { 678 if (lua_type (L, 2) == LUA_TTABLE) { 679 schema = ucl_object_lua_import (L, 2); 680 681 if (schema == NULL) { 682 lua_pushboolean (L, false); 683 lua_pushstring (L, "cannot load schema from lua table"); 684 685 return 2; 686 } 687 } 688 else if (lua_type (L, 2) == LUA_TSTRING) { 689 schema_parser = ucl_parser_new (0); 690 schema_file = luaL_checkstring (L, 2); 691 692 if (!ucl_parser_add_file (schema_parser, schema_file)) { 693 lua_pushboolean (L, false); 694 lua_pushfstring (L, "cannot parse schema file \"%s\": " 695 "%s", schema_file, ucl_parser_get_error (parser)); 696 ucl_parser_free (schema_parser); 697 698 return 2; 699 } 700 701 schema = ucl_parser_get_object (schema_parser); 702 ucl_parser_free (schema_parser); 703 } 704 else { 705 lua_pushboolean (L, false); 706 lua_pushstring (L, "invalid schema argument"); 707 708 return 2; 709 } 710 711 if (!ucl_object_validate (schema, parser->top_obj, &err)) { 712 lua_pushboolean (L, false); 713 lua_pushfstring (L, "validation error: " 714 "%s", err.msg); 715 } 716 else { 717 lua_pushboolean (L, true); 718 lua_pushnil (L); 719 } 720 721 ucl_object_unref (schema); 722 } 723 else { 724 lua_pushboolean (L, false); 725 lua_pushstring (L, "invalid parser or empty top object"); 726 } 727 728 return 2; 729 } 730 731 static int 732 lua_ucl_parser_gc (lua_State *L) 733 { 734 struct ucl_parser *parser; 735 736 parser = lua_ucl_parser_get (L, 1); 737 ucl_parser_free (parser); 738 739 return 0; 740 } 741 742 /*** 743 * @method object:unwrap() 744 * Unwraps opaque ucl object to the native lua object (performing copying) 745 * @return {variant} any lua object 746 */ 747 static int 748 lua_ucl_object_unwrap (lua_State *L) 749 { 750 ucl_object_t *obj; 751 752 obj = lua_ucl_object_get (L, 1); 753 754 if (obj) { 755 ucl_object_push_lua (L, obj, true); 756 } 757 else { 758 lua_pushnil (L); 759 } 760 761 return 1; 762 } 763 764 /*** 765 * @method object:tostring(type) 766 * Unwraps opaque ucl object to string (json by default). Optionally you can 767 * specify output format: 768 * 769 * - `json` - fine printed json 770 * - `json-compact` - compacted json 771 * - `config` - fine printed configuration 772 * - `ucl` - same as `config` 773 * - `yaml` - embedded yaml 774 * @param {string} type optional 775 * @return {string} string representation of the opaque ucl object 776 */ 777 static int 778 lua_ucl_object_tostring (lua_State *L) 779 { 780 ucl_object_t *obj; 781 enum ucl_emitter format = UCL_EMIT_JSON_COMPACT; 782 783 obj = lua_ucl_object_get (L, 1); 784 785 if (obj) { 786 if (lua_gettop (L) > 1) { 787 if (lua_type (L, 2) == LUA_TSTRING) { 788 const char *strtype = lua_tostring (L, 2); 789 790 if (strcasecmp (strtype, "json") == 0) { 791 format = UCL_EMIT_JSON; 792 } 793 else if (strcasecmp (strtype, "json-compact") == 0) { 794 format = UCL_EMIT_JSON_COMPACT; 795 } 796 else if (strcasecmp (strtype, "yaml") == 0) { 797 format = UCL_EMIT_YAML; 798 } 799 else if (strcasecmp (strtype, "config") == 0 || 800 strcasecmp (strtype, "ucl") == 0) { 801 format = UCL_EMIT_CONFIG; 802 } 803 } 804 } 805 806 return lua_ucl_to_string (L, obj, format); 807 } 808 else { 809 lua_pushnil (L); 810 } 811 812 return 1; 813 } 814 815 /*** 816 * @method object:validate(schema[, path[, ext_refs]]) 817 * Validates the given ucl object using schema object represented as another 818 * opaque ucl object. You can also specify path in the form `#/path/def` to 819 * specify the specific schema element to perform validation. 820 * 821 * @param {ucl.object} schema schema object 822 * @param {string} path optional path for validation procedure 823 * @return {result,err} two values: boolean result and the corresponding 824 * error, if `ext_refs` are also specified, then they are returned as opaque 825 * ucl object as {result,err,ext_refs} 826 */ 827 static int 828 lua_ucl_object_validate (lua_State *L) 829 { 830 ucl_object_t *obj, *schema, *ext_refs = NULL; 831 const ucl_object_t *schema_elt; 832 bool res = false; 833 struct ucl_schema_error err; 834 const char *path = NULL; 835 836 obj = lua_ucl_object_get (L, 1); 837 schema = lua_ucl_object_get (L, 2); 838 839 if (schema && obj && ucl_object_type (schema) == UCL_OBJECT) { 840 if (lua_gettop (L) > 2) { 841 if (lua_type (L, 3) == LUA_TSTRING) { 842 path = lua_tostring (L, 3); 843 if (path[0] == '#') { 844 path++; 845 } 846 } 847 else if (lua_type (L, 3) == LUA_TUSERDATA || lua_type (L, 3) == 848 LUA_TTABLE) { 849 /* External refs */ 850 ext_refs = lua_ucl_object_get (L, 3); 851 } 852 853 if (lua_gettop (L) > 3) { 854 if (lua_type (L, 4) == LUA_TUSERDATA || lua_type (L, 4) == 855 LUA_TTABLE) { 856 /* External refs */ 857 ext_refs = lua_ucl_object_get (L, 4); 858 } 859 } 860 } 861 862 if (path) { 863 schema_elt = ucl_object_lookup_path_char (schema, path, '/'); 864 } 865 else { 866 /* Use the top object */ 867 schema_elt = schema; 868 } 869 870 if (schema_elt) { 871 res = ucl_object_validate_root_ext (schema_elt, obj, schema, 872 ext_refs, &err); 873 874 if (res) { 875 lua_pushboolean (L, res); 876 lua_pushnil (L); 877 878 if (ext_refs) { 879 lua_ucl_push_opaque (L, ext_refs); 880 } 881 } 882 else { 883 lua_pushboolean (L, res); 884 lua_pushfstring (L, "validation error: %s", err.msg); 885 886 if (ext_refs) { 887 lua_ucl_push_opaque (L, ext_refs); 888 } 889 } 890 } 891 else { 892 lua_pushboolean (L, res); 893 894 lua_pushfstring (L, "cannot find the requested path: %s", path); 895 896 if (ext_refs) { 897 lua_ucl_push_opaque (L, ext_refs); 898 } 899 } 900 } 901 else { 902 lua_pushboolean (L, res); 903 lua_pushstring (L, "invalid object or schema"); 904 } 905 906 if (ext_refs) { 907 return 3; 908 } 909 910 return 2; 911 } 912 913 static int 914 lua_ucl_object_gc (lua_State *L) 915 { 916 ucl_object_t *obj; 917 918 obj = lua_ucl_object_get (L, 1); 919 920 ucl_object_unref (obj); 921 922 return 0; 923 } 924 925 static void 926 lua_ucl_parser_mt (lua_State *L) 927 { 928 luaL_newmetatable (L, PARSER_META); 929 930 lua_pushvalue(L, -1); 931 lua_setfield(L, -2, "__index"); 932 933 lua_pushcfunction (L, lua_ucl_parser_gc); 934 lua_setfield (L, -2, "__gc"); 935 936 lua_pushcfunction (L, lua_ucl_parser_parse_file); 937 lua_setfield (L, -2, "parse_file"); 938 939 lua_pushcfunction (L, lua_ucl_parser_parse_string); 940 lua_setfield (L, -2, "parse_string"); 941 942 lua_pushcfunction (L, lua_ucl_parser_get_object); 943 lua_setfield (L, -2, "get_object"); 944 945 lua_pushcfunction (L, lua_ucl_parser_get_object_wrapped); 946 lua_setfield (L, -2, "get_object_wrapped"); 947 948 lua_pushcfunction (L, lua_ucl_parser_validate); 949 lua_setfield (L, -2, "validate"); 950 951 lua_pop (L, 1); 952 } 953 954 static void 955 lua_ucl_object_mt (lua_State *L) 956 { 957 luaL_newmetatable (L, OBJECT_META); 958 959 lua_pushvalue(L, -1); 960 lua_setfield(L, -2, "__index"); 961 962 lua_pushcfunction (L, lua_ucl_object_gc); 963 lua_setfield (L, -2, "__gc"); 964 965 lua_pushcfunction (L, lua_ucl_object_tostring); 966 lua_setfield (L, -2, "__tostring"); 967 968 lua_pushcfunction (L, lua_ucl_object_tostring); 969 lua_setfield (L, -2, "tostring"); 970 971 lua_pushcfunction (L, lua_ucl_object_unwrap); 972 lua_setfield (L, -2, "unwrap"); 973 974 lua_pushcfunction (L, lua_ucl_object_unwrap); 975 lua_setfield (L, -2, "tolua"); 976 977 lua_pushcfunction (L, lua_ucl_object_validate); 978 lua_setfield (L, -2, "validate"); 979 980 lua_pushstring (L, OBJECT_META); 981 lua_setfield (L, -2, "class"); 982 983 lua_pop (L, 1); 984 } 985 986 static int 987 lua_ucl_to_json (lua_State *L) 988 { 989 ucl_object_t *obj; 990 int format = UCL_EMIT_JSON; 991 992 if (lua_gettop (L) > 1) { 993 if (lua_toboolean (L, 2)) { 994 format = UCL_EMIT_JSON_COMPACT; 995 } 996 } 997 998 obj = ucl_object_lua_import (L, 1); 999 if (obj != NULL) { 1000 lua_ucl_to_string (L, obj, format); 1001 ucl_object_unref (obj); 1002 } 1003 else { 1004 lua_pushnil (L); 1005 } 1006 1007 return 1; 1008 } 1009 1010 static int 1011 lua_ucl_to_config (lua_State *L) 1012 { 1013 ucl_object_t *obj; 1014 1015 obj = ucl_object_lua_import (L, 1); 1016 if (obj != NULL) { 1017 lua_ucl_to_string (L, obj, UCL_EMIT_CONFIG); 1018 ucl_object_unref (obj); 1019 } 1020 else { 1021 lua_pushnil (L); 1022 } 1023 1024 return 1; 1025 } 1026 1027 /*** 1028 * @function ucl.to_format(var, format) 1029 * Converts lua variable `var` to the specified `format`. Formats supported are: 1030 * 1031 * - `json` - fine printed json 1032 * - `json-compact` - compacted json 1033 * - `config` - fine printed configuration 1034 * - `ucl` - same as `config` 1035 * - `yaml` - embedded yaml 1036 * 1037 * If `var` contains function, they are called during output formatting and if 1038 * they return string value, then this value is used for ouptut. 1039 * @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output) 1040 * @param {string} format any available format 1041 * @return {string} string representation of `var` in the specific `format`. 1042 * @example 1043 local table = { 1044 str = 'value', 1045 num = 100500, 1046 null = ucl.null, 1047 func = function () 1048 return 'huh' 1049 end 1050 } 1051 1052 print(ucl.to_format(table, 'ucl')) 1053 -- Output: 1054 --[[ 1055 num = 100500; 1056 str = "value"; 1057 null = null; 1058 func = "huh"; 1059 --]] 1060 */ 1061 static int 1062 lua_ucl_to_format (lua_State *L) 1063 { 1064 ucl_object_t *obj; 1065 int format = UCL_EMIT_JSON; 1066 1067 if (lua_gettop (L) > 1) { 1068 if (lua_type (L, 2) == LUA_TNUMBER) { 1069 format = lua_tonumber (L, 2); 1070 if (format < 0 || format >= UCL_EMIT_YAML) { 1071 lua_pushnil (L); 1072 return 1; 1073 } 1074 } 1075 else if (lua_type (L, 2) == LUA_TSTRING) { 1076 const char *strtype = lua_tostring (L, 2); 1077 1078 if (strcasecmp (strtype, "json") == 0) { 1079 format = UCL_EMIT_JSON; 1080 } 1081 else if (strcasecmp (strtype, "json-compact") == 0) { 1082 format = UCL_EMIT_JSON_COMPACT; 1083 } 1084 else if (strcasecmp (strtype, "yaml") == 0) { 1085 format = UCL_EMIT_YAML; 1086 } 1087 else if (strcasecmp (strtype, "config") == 0 || 1088 strcasecmp (strtype, "ucl") == 0) { 1089 format = UCL_EMIT_CONFIG; 1090 } 1091 } 1092 } 1093 1094 obj = ucl_object_lua_import (L, 1); 1095 if (obj != NULL) { 1096 lua_ucl_to_string (L, obj, format); 1097 ucl_object_unref (obj); 1098 } 1099 else { 1100 lua_pushnil (L); 1101 } 1102 1103 return 1; 1104 } 1105 1106 static int 1107 lua_ucl_null_tostring (lua_State* L) 1108 { 1109 lua_pushstring (L, "null"); 1110 return 1; 1111 } 1112 1113 static void 1114 lua_ucl_null_mt (lua_State *L) 1115 { 1116 luaL_newmetatable (L, NULL_META); 1117 1118 lua_pushcfunction (L, lua_ucl_null_tostring); 1119 lua_setfield (L, -2, "__tostring"); 1120 1121 lua_pop (L, 1); 1122 } 1123 1124 int 1125 luaopen_ucl (lua_State *L) 1126 { 1127 lua_ucl_parser_mt (L); 1128 lua_ucl_null_mt (L); 1129 lua_ucl_object_mt (L); 1130 1131 /* Create the refs weak table: */ 1132 lua_createtable (L, 0, 2); 1133 lua_pushliteral (L, "v"); /* tbl, "v" */ 1134 lua_setfield (L, -2, "__mode"); 1135 lua_pushvalue (L, -1); /* tbl, tbl */ 1136 lua_setmetatable (L, -2); /* tbl */ 1137 lua_setfield (L, LUA_REGISTRYINDEX, "ucl.refs"); 1138 1139 lua_newtable (L); 1140 1141 lua_pushcfunction (L, lua_ucl_parser_init); 1142 lua_setfield (L, -2, "parser"); 1143 1144 lua_pushcfunction (L, lua_ucl_to_json); 1145 lua_setfield (L, -2, "to_json"); 1146 1147 lua_pushcfunction (L, lua_ucl_to_config); 1148 lua_setfield (L, -2, "to_config"); 1149 1150 lua_pushcfunction (L, lua_ucl_to_format); 1151 lua_setfield (L, -2, "to_format"); 1152 1153 ucl_null = lua_newuserdata (L, 0); 1154 luaL_getmetatable (L, NULL_META); 1155 lua_setmetatable (L, -2); 1156 1157 lua_pushvalue (L, -1); 1158 lua_setfield (L, LUA_REGISTRYINDEX, "ucl.null"); 1159 1160 lua_setfield (L, -2, "null"); 1161 1162 return 1; 1163 } 1164 1165 struct ucl_lua_funcdata* 1166 ucl_object_toclosure (const ucl_object_t *obj) 1167 { 1168 if (obj == NULL || obj->type != UCL_USERDATA) { 1169 return NULL; 1170 } 1171 1172 return (struct ucl_lua_funcdata*)obj->value.ud; 1173 } 1174