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 33 /*** 34 * @module ucl 35 * This lua module allows to parse objects from strings and to store data into 36 * ucl objects. It uses `libucl` C library to parse and manipulate with ucl objects. 37 * @example 38 local ucl = require("ucl") 39 40 local parser = ucl.parser() 41 local res,err = parser:parse_string('{key=value}') 42 43 if not res then 44 print('parser error: ' .. err) 45 else 46 local obj = parser:get_object() 47 local got = ucl.to_format(obj, 'json') 48 endif 49 50 local table = { 51 str = 'value', 52 num = 100500, 53 null = ucl.null, 54 func = function () 55 return 'huh' 56 end 57 } 58 59 print(ucl.to_format(table, 'ucl')) 60 -- Output: 61 --[[ 62 num = 100500; 63 str = "value"; 64 null = null; 65 func = "huh"; 66 --]] 67 */ 68 69 #define PARSER_META "ucl.parser.meta" 70 #define EMITTER_META "ucl.emitter.meta" 71 #define NULL_META "ucl.null.meta" 72 #define OBJECT_META "ucl.object.meta" 73 #define UCL_OBJECT_TYPE_META "ucl.type.object" 74 #define UCL_ARRAY_TYPE_META "ucl.type.array" 75 #define UCL_IMPL_ARRAY_TYPE_META "ucl.type.impl_array" 76 77 static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj, int flags); 78 static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, int flags); 79 static int ucl_object_push_lua_common (lua_State *L, const ucl_object_t *obj, int flags); 80 static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags); 81 static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags); 82 83 static void *ucl_null; 84 85 86 enum lua_ucl_push_flags { 87 LUA_UCL_DEFAULT_FLAGS = 0, 88 LUA_UCL_ALLOW_ARRAY = (1u << 0u), 89 LUA_UCL_CONVERT_NIL = (1u << 1u), 90 }; 91 92 /** 93 * Push a single element of an object to lua 94 * @param L 95 * @param key 96 * @param obj 97 */ 98 static void 99 ucl_object_lua_push_element (lua_State *L, const char *key, 100 const ucl_object_t *obj, int flags) 101 { 102 lua_pushstring (L, key); 103 ucl_object_push_lua_common (L, obj, flags|LUA_UCL_ALLOW_ARRAY); 104 lua_settable (L, -3); 105 } 106 107 static void 108 lua_ucl_userdata_dtor (void *ud) 109 { 110 struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud; 111 112 luaL_unref (fd->L, LUA_REGISTRYINDEX, fd->idx); 113 if (fd->ret != NULL) { 114 free (fd->ret); 115 } 116 free (fd); 117 } 118 119 static const char * 120 lua_ucl_userdata_emitter (void *ud) 121 { 122 struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud; 123 const char *out = ""; 124 125 lua_rawgeti (fd->L, LUA_REGISTRYINDEX, fd->idx); 126 127 lua_pcall (fd->L, 0, 1, 0); 128 out = lua_tostring (fd->L, -1); 129 130 if (out != NULL) { 131 /* We need to store temporary string in a more appropriate place */ 132 if (fd->ret) { 133 free (fd->ret); 134 } 135 fd->ret = strdup (out); 136 } 137 138 lua_settop (fd->L, 0); 139 140 return fd->ret; 141 } 142 143 /** 144 * Push a single object to lua 145 * @param L 146 * @param obj 147 * @return 148 */ 149 static int 150 ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj, 151 int flags) 152 { 153 const ucl_object_t *cur; 154 ucl_object_iter_t it = NULL; 155 156 if ((flags & LUA_UCL_ALLOW_ARRAY) && obj->next != NULL) { 157 /* Actually we need to push this as an array */ 158 return ucl_object_lua_push_array (L, obj, flags); 159 } 160 161 lua_createtable (L, 0, obj->len); 162 it = NULL; 163 164 while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) { 165 ucl_object_lua_push_element (L, ucl_object_key (cur), cur, flags); 166 } 167 168 luaL_getmetatable (L, UCL_OBJECT_TYPE_META); 169 lua_setmetatable (L, -2); 170 171 return 1; 172 } 173 174 /** 175 * Push an array to lua as table indexed by integers 176 * @param L 177 * @param obj 178 * @return 179 */ 180 static int 181 ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj, int flags) 182 { 183 const ucl_object_t *cur; 184 ucl_object_iter_t it; 185 int i = 1, nelt = 0; 186 187 if (obj->type == UCL_ARRAY) { 188 nelt = obj->len; 189 it = ucl_object_iterate_new (obj); 190 lua_createtable (L, nelt, 0); 191 192 while ((cur = ucl_object_iterate_safe (it, true))) { 193 ucl_object_push_lua (L, cur, (flags & ~LUA_UCL_ALLOW_ARRAY)); 194 lua_rawseti (L, -2, i); 195 i ++; 196 } 197 198 luaL_getmetatable (L, UCL_ARRAY_TYPE_META); 199 lua_setmetatable (L, -2); 200 201 ucl_object_iterate_free (it); 202 } 203 else { 204 /* Optimize allocation by preallocation of table */ 205 LL_FOREACH (obj, cur) { 206 nelt ++; 207 } 208 209 lua_createtable (L, nelt, 0); 210 211 LL_FOREACH (obj, cur) { 212 ucl_object_push_lua (L, cur, (flags & ~LUA_UCL_ALLOW_ARRAY)); 213 lua_rawseti (L, -2, i); 214 i ++; 215 } 216 217 luaL_getmetatable (L, UCL_IMPL_ARRAY_TYPE_META); 218 lua_setmetatable (L, -2); 219 } 220 221 return 1; 222 } 223 224 /** 225 * Push a simple object to lua depending on its actual type 226 */ 227 static int 228 ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, 229 int flags) 230 { 231 struct ucl_lua_funcdata *fd; 232 233 if ((flags & LUA_UCL_ALLOW_ARRAY) && obj->next != NULL) { 234 /* Actually we need to push this as an array */ 235 return ucl_object_lua_push_array (L, obj, flags); 236 } 237 238 switch (obj->type) { 239 case UCL_BOOLEAN: 240 lua_pushboolean (L, ucl_obj_toboolean (obj)); 241 break; 242 case UCL_STRING: 243 lua_pushstring (L, ucl_obj_tostring (obj)); 244 break; 245 case UCL_INT: 246 #if LUA_VERSION_NUM >= 501 247 lua_pushinteger (L, ucl_obj_toint (obj)); 248 #else 249 lua_pushnumber (L, ucl_obj_toint (obj)); 250 #endif 251 break; 252 case UCL_FLOAT: 253 case UCL_TIME: 254 lua_pushnumber (L, ucl_obj_todouble (obj)); 255 break; 256 case UCL_NULL: 257 if (flags & LUA_UCL_CONVERT_NIL) { 258 lua_pushboolean (L, false); 259 } 260 else { 261 lua_getfield (L, LUA_REGISTRYINDEX, "ucl.null"); 262 } 263 break; 264 case UCL_USERDATA: 265 fd = (struct ucl_lua_funcdata *)obj->value.ud; 266 lua_rawgeti (L, LUA_REGISTRYINDEX, fd->idx); 267 break; 268 default: 269 lua_pushnil (L); 270 break; 271 } 272 273 return 1; 274 } 275 276 static int 277 ucl_object_push_lua_common (lua_State *L, const ucl_object_t *obj, int flags) 278 { 279 switch (obj->type) { 280 case UCL_OBJECT: 281 return ucl_object_lua_push_object (L, obj, flags); 282 case UCL_ARRAY: 283 return ucl_object_lua_push_array (L, obj, flags); 284 default: 285 return ucl_object_lua_push_scalar (L, obj, flags); 286 } 287 } 288 289 /*** 290 * @function ucl_object_push_lua(L, obj, allow_array) 291 * This is a `C` function to push `UCL` object as lua variable. This function 292 * converts `obj` to lua representation using the following conversions: 293 * 294 * - *scalar* values are directly presented by lua objects 295 * - *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`, 296 * this can be used to pass functions from lua to c and vice-versa 297 * - *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations 298 * - *objects* are converted to lua tables with string indicies 299 * @param {lua_State} L lua state pointer 300 * @param {ucl_object_t} obj object to push 301 * @param {bool} allow_array expand implicit arrays (should be true for all but partial arrays) 302 * @return {int} `1` if an object is pushed to lua 303 */ 304 int 305 ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array) 306 { 307 return ucl_object_push_lua_common (L, obj, 308 allow_array ? LUA_UCL_ALLOW_ARRAY : LUA_UCL_DEFAULT_FLAGS); 309 } 310 311 int 312 ucl_object_push_lua_filter_nil (lua_State *L, const ucl_object_t *obj, bool allow_array) 313 { 314 return ucl_object_push_lua_common (L, obj, 315 allow_array ? (LUA_UCL_ALLOW_ARRAY|LUA_UCL_CONVERT_NIL) : 316 (LUA_UCL_DEFAULT_FLAGS|LUA_UCL_CONVERT_NIL)); 317 } 318 319 /** 320 * Parse lua table into object top 321 * @param L 322 * @param top 323 * @param idx 324 */ 325 static ucl_object_t * 326 ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags) 327 { 328 ucl_object_t *obj, *top = NULL, *cur; 329 size_t keylen; 330 const char *k; 331 bool is_array = true, is_implicit = false, found_mt = false; 332 size_t max = 0, nelts = 0; 333 334 if (idx < 0) { 335 /* For negative indicies we want to invert them */ 336 idx = lua_gettop (L) + idx + 1; 337 } 338 339 /* First, we check from metatable */ 340 if (luaL_getmetafield (L, idx, "class") != 0) { 341 342 if (lua_type (L, -1) == LUA_TSTRING) { 343 const char *classname = lua_tostring (L, -1); 344 345 if (strcmp (classname, UCL_OBJECT_TYPE_META) == 0) { 346 is_array = false; 347 found_mt = true; 348 } else if (strcmp (classname, UCL_ARRAY_TYPE_META) == 0) { 349 is_array = true; 350 found_mt = true; 351 #if LUA_VERSION_NUM >= 502 352 max = lua_rawlen (L, idx); 353 #else 354 max = lua_objlen (L, idx); 355 #endif 356 nelts = max; 357 } else if (strcmp (classname, UCL_IMPL_ARRAY_TYPE_META) == 0) { 358 is_array = true; 359 is_implicit = true; 360 found_mt = true; 361 #if LUA_VERSION_NUM >= 502 362 max = lua_rawlen (L, idx); 363 #else 364 max = lua_objlen (L, idx); 365 #endif 366 nelts = max; 367 } 368 } 369 370 lua_pop (L, 1); 371 } 372 373 if (!found_mt) { 374 /* Check for array (it is all inefficient) */ 375 lua_pushnil (L); 376 377 while (lua_next (L, idx) != 0) { 378 lua_pushvalue (L, -2); 379 380 if (lua_type (L, -1) == LUA_TNUMBER) { 381 double num = lua_tonumber (L, -1); 382 if (num == (int) num) { 383 if (num > max) { 384 max = num; 385 } 386 } 387 else { 388 /* Keys are not integer */ 389 is_array = false; 390 } 391 } 392 else { 393 /* Keys are not numeric */ 394 is_array = false; 395 } 396 397 lua_pop (L, 2); 398 nelts ++; 399 } 400 } 401 402 /* Table iterate */ 403 if (is_array) { 404 int i; 405 406 if (!is_implicit) { 407 top = ucl_object_typed_new (UCL_ARRAY); 408 ucl_object_reserve (top, nelts); 409 } 410 else { 411 top = NULL; 412 } 413 414 for (i = 1; i <= max; i ++) { 415 lua_pushinteger (L, i); 416 lua_gettable (L, idx); 417 418 obj = ucl_object_lua_fromelt (L, lua_gettop (L), flags); 419 420 if (obj != NULL) { 421 if (is_implicit) { 422 DL_APPEND (top, obj); 423 } 424 else { 425 ucl_array_append (top, obj); 426 } 427 } 428 lua_pop (L, 1); 429 } 430 } 431 else { 432 lua_pushnil (L); 433 top = ucl_object_typed_new (UCL_OBJECT); 434 ucl_object_reserve (top, nelts); 435 436 while (lua_next (L, idx) != 0) { 437 /* copy key to avoid modifications */ 438 lua_pushvalue (L, -2); 439 k = lua_tolstring (L, -1, &keylen); 440 obj = ucl_object_lua_fromelt (L, lua_gettop (L) - 1, flags); 441 442 if (obj != NULL) { 443 ucl_object_insert_key (top, obj, k, keylen, true); 444 445 DL_FOREACH (obj, cur) { 446 if (cur->keylen == 0) { 447 cur->keylen = obj->keylen; 448 cur->key = obj->key; 449 } 450 } 451 } 452 lua_pop (L, 2); 453 } 454 } 455 456 return top; 457 } 458 459 /** 460 * Get a single element from lua to object obj 461 * @param L 462 * @param obj 463 * @param idx 464 */ 465 static ucl_object_t * 466 ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags) 467 { 468 int type; 469 double num; 470 ucl_object_t *obj = NULL; 471 struct ucl_lua_funcdata *fd; 472 const char *str; 473 size_t sz; 474 475 type = lua_type (L, idx); 476 477 switch (type) { 478 case LUA_TSTRING: 479 str = lua_tolstring (L, idx, &sz); 480 481 if (str) { 482 obj = ucl_object_fromstring_common (str, sz, flags); 483 } 484 else { 485 obj = ucl_object_typed_new (UCL_NULL); 486 } 487 break; 488 case LUA_TNUMBER: 489 num = lua_tonumber (L, idx); 490 if (num == (int64_t)num) { 491 obj = ucl_object_fromint (num); 492 } 493 else { 494 obj = ucl_object_fromdouble (num); 495 } 496 break; 497 case LUA_TBOOLEAN: 498 obj = ucl_object_frombool (lua_toboolean (L, idx)); 499 break; 500 case LUA_TUSERDATA: 501 if (lua_topointer (L, idx) == ucl_null) { 502 obj = ucl_object_typed_new (UCL_NULL); 503 } 504 break; 505 case LUA_TTABLE: 506 case LUA_TFUNCTION: 507 case LUA_TTHREAD: 508 if (luaL_getmetafield (L, idx, "__gen_ucl")) { 509 if (lua_isfunction (L, -1)) { 510 lua_settop (L, 3); /* gen, obj, func */ 511 lua_insert (L, 1); /* func, gen, obj */ 512 lua_insert (L, 2); /* func, obj, gen */ 513 lua_call(L, 2, 1); 514 obj = ucl_object_lua_fromelt (L, 1, flags); 515 } 516 lua_pop (L, 2); 517 } 518 else { 519 if (type == LUA_TTABLE) { 520 obj = ucl_object_lua_fromtable (L, idx, flags); 521 } 522 else if (type == LUA_TFUNCTION) { 523 fd = malloc (sizeof (*fd)); 524 if (fd != NULL) { 525 lua_pushvalue (L, idx); 526 fd->L = L; 527 fd->ret = NULL; 528 fd->idx = luaL_ref (L, LUA_REGISTRYINDEX); 529 530 obj = ucl_object_new_userdata (lua_ucl_userdata_dtor, 531 lua_ucl_userdata_emitter, (void *)fd); 532 } 533 } 534 } 535 break; 536 } 537 538 return obj; 539 } 540 541 /** 542 * @function ucl_object_lua_import(L, idx) 543 * Extracts ucl object from lua variable at `idx` position, 544 * @see ucl_object_push_lua for conversion definitions 545 * @param {lua_state} L lua state machine pointer 546 * @param {int} idx index where the source variable is placed 547 * @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1, 548 * this object thus needs to be unref'ed after usage. 549 */ 550 ucl_object_t * 551 ucl_object_lua_import (lua_State *L, int idx) 552 { 553 ucl_object_t *obj; 554 int t; 555 556 t = lua_type (L, idx); 557 switch (t) { 558 case LUA_TTABLE: 559 obj = ucl_object_lua_fromtable (L, idx, 0); 560 break; 561 default: 562 obj = ucl_object_lua_fromelt (L, idx, 0); 563 break; 564 } 565 566 return obj; 567 } 568 569 /** 570 * @function ucl_object_lua_import_escape(L, idx) 571 * Extracts ucl object from lua variable at `idx` position escaping JSON strings 572 * @see ucl_object_push_lua for conversion definitions 573 * @param {lua_state} L lua state machine pointer 574 * @param {int} idx index where the source variable is placed 575 * @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1, 576 * this object thus needs to be unref'ed after usage. 577 */ 578 ucl_object_t * 579 ucl_object_lua_import_escape (lua_State *L, int idx) 580 { 581 ucl_object_t *obj; 582 int t; 583 584 t = lua_type (L, idx); 585 switch (t) { 586 case LUA_TTABLE: 587 obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_RAW); 588 break; 589 default: 590 obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_RAW); 591 break; 592 } 593 594 return obj; 595 } 596 597 static int 598 lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type) 599 { 600 unsigned char *result; 601 602 result = ucl_object_emit (obj, type); 603 604 if (result != NULL) { 605 lua_pushstring (L, (const char *)result); 606 free (result); 607 } 608 else { 609 lua_pushnil (L); 610 } 611 612 return 1; 613 } 614 615 static int 616 lua_ucl_parser_init (lua_State *L) 617 { 618 struct ucl_parser *parser, **pparser; 619 int flags = UCL_PARSER_NO_FILEVARS; 620 621 if (lua_gettop (L) >= 1) { 622 flags = lua_tonumber (L, 1); 623 } 624 625 parser = ucl_parser_new (flags); 626 if (parser == NULL) { 627 lua_pushnil (L); 628 return 1; 629 } 630 631 pparser = lua_newuserdata (L, sizeof (parser)); 632 *pparser = parser; 633 luaL_getmetatable (L, PARSER_META); 634 lua_setmetatable (L, -2); 635 636 return 1; 637 } 638 639 static struct ucl_parser * 640 lua_ucl_parser_get (lua_State *L, int index) 641 { 642 return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META)); 643 } 644 645 static ucl_object_t * 646 lua_ucl_object_get (lua_State *L, int index) 647 { 648 return *((ucl_object_t **) luaL_checkudata(L, index, OBJECT_META)); 649 } 650 651 static void 652 lua_ucl_push_opaque (lua_State *L, ucl_object_t *obj) 653 { 654 ucl_object_t **pobj; 655 656 pobj = lua_newuserdata (L, sizeof (*pobj)); 657 *pobj = obj; 658 luaL_getmetatable (L, OBJECT_META); 659 lua_setmetatable (L, -2); 660 } 661 662 static inline enum ucl_parse_type 663 lua_ucl_str_to_parse_type (const char *str) 664 { 665 enum ucl_parse_type type = UCL_PARSE_UCL; 666 667 if (str != NULL) { 668 if (strcasecmp (str, "msgpack") == 0) { 669 type = UCL_PARSE_MSGPACK; 670 } 671 else if (strcasecmp (str, "sexp") == 0 || 672 strcasecmp (str, "csexp") == 0) { 673 type = UCL_PARSE_CSEXP; 674 } 675 else if (strcasecmp (str, "auto") == 0) { 676 type = UCL_PARSE_AUTO; 677 } 678 } 679 680 return type; 681 } 682 683 /*** 684 * @method parser:parse_file(name) 685 * Parse UCL object from file. 686 * @param {string} name filename to parse 687 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned 688 @example 689 local parser = ucl.parser() 690 local res,err = parser:parse_file('/some/file.conf') 691 692 if not res then 693 print('parser error: ' .. err) 694 else 695 -- Do something with object 696 end 697 */ 698 static int 699 lua_ucl_parser_parse_file (lua_State *L) 700 { 701 struct ucl_parser *parser; 702 const char *file; 703 int ret = 2; 704 705 parser = lua_ucl_parser_get (L, 1); 706 file = luaL_checkstring (L, 2); 707 708 if (parser != NULL && file != NULL) { 709 if (ucl_parser_add_file (parser, file)) { 710 lua_pushboolean (L, true); 711 ret = 1; 712 } 713 else { 714 lua_pushboolean (L, false); 715 lua_pushstring (L, ucl_parser_get_error (parser)); 716 } 717 } 718 else { 719 lua_pushboolean (L, false); 720 lua_pushstring (L, "invalid arguments"); 721 } 722 723 return ret; 724 } 725 726 /*** 727 * @method parser:register_variable(name, value) 728 * Register parser variable 729 * @param {string} name name of variable 730 * @param {string} value value of variable 731 * @return {bool} success 732 @example 733 local parser = ucl.parser() 734 local res = parser:register_variable('CONFDIR', '/etc/foo') 735 */ 736 static int 737 lua_ucl_parser_register_variable (lua_State *L) 738 { 739 struct ucl_parser *parser; 740 const char *name, *value; 741 int ret = 2; 742 743 parser = lua_ucl_parser_get (L, 1); 744 name = luaL_checkstring (L, 2); 745 value = luaL_checkstring (L, 3); 746 747 if (parser != NULL && name != NULL && value != NULL) { 748 ucl_parser_register_variable (parser, name, value); 749 lua_pushboolean (L, true); 750 ret = 1; 751 } 752 else { 753 return luaL_error (L, "invalid arguments"); 754 } 755 756 return ret; 757 } 758 759 /*** 760 * @method parser:register_variables(vars) 761 * Register parser variables 762 * @param {table} vars names/values of variables 763 * @return {bool} success 764 @example 765 local parser = ucl.parser() 766 local res = parser:register_variables({CONFDIR = '/etc/foo', VARDIR = '/var'}) 767 */ 768 static int 769 lua_ucl_parser_register_variables (lua_State *L) 770 { 771 struct ucl_parser *parser; 772 const char *name, *value; 773 int ret = 2; 774 775 parser = lua_ucl_parser_get (L, 1); 776 777 if (parser != NULL && lua_type (L, 2) == LUA_TTABLE) { 778 for (lua_pushnil (L); lua_next (L, 2); lua_pop (L, 1)) { 779 lua_pushvalue (L, -2); 780 name = luaL_checkstring (L, -1); 781 value = luaL_checkstring (L, -2); 782 ucl_parser_register_variable (parser, name, value); 783 lua_pop (L, 1); 784 } 785 786 lua_pushboolean (L, true); 787 ret = 1; 788 } 789 else { 790 return luaL_error (L, "invalid arguments"); 791 } 792 793 return ret; 794 } 795 796 /*** 797 * @method parser:parse_string(input) 798 * Parse UCL object from file. 799 * @param {string} input string to parse 800 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned 801 */ 802 static int 803 lua_ucl_parser_parse_string (lua_State *L) 804 { 805 struct ucl_parser *parser; 806 const char *string; 807 size_t llen; 808 enum ucl_parse_type type = UCL_PARSE_UCL; 809 int ret = 2; 810 811 parser = lua_ucl_parser_get (L, 1); 812 string = luaL_checklstring (L, 2, &llen); 813 814 if (lua_type (L, 3) == LUA_TSTRING) { 815 type = lua_ucl_str_to_parse_type (lua_tostring (L, 3)); 816 } 817 818 if (parser != NULL && string != NULL) { 819 if (ucl_parser_add_chunk_full (parser, (const unsigned char *)string, 820 llen, 0, UCL_DUPLICATE_APPEND, type)) { 821 lua_pushboolean (L, true); 822 ret = 1; 823 } 824 else { 825 lua_pushboolean (L, false); 826 lua_pushstring (L, ucl_parser_get_error (parser)); 827 } 828 } 829 else { 830 lua_pushboolean (L, false); 831 lua_pushstring (L, "invalid arguments"); 832 } 833 834 return ret; 835 } 836 837 struct _rspamd_lua_text { 838 const char *start; 839 unsigned int len; 840 unsigned int flags; 841 }; 842 843 /*** 844 * @method parser:parse_text(input) 845 * Parse UCL object from text object (Rspamd specific). 846 * @param {rspamd_text} input text to parse 847 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned 848 */ 849 static int 850 lua_ucl_parser_parse_text (lua_State *L) 851 { 852 struct ucl_parser *parser; 853 struct _rspamd_lua_text *t; 854 enum ucl_parse_type type = UCL_PARSE_UCL; 855 int ret = 2; 856 857 parser = lua_ucl_parser_get (L, 1); 858 t = lua_touserdata (L, 2); 859 860 if (lua_type (L, 3) == LUA_TSTRING) { 861 type = lua_ucl_str_to_parse_type (lua_tostring (L, 3)); 862 } 863 864 if (parser != NULL && t != NULL) { 865 if (ucl_parser_add_chunk_full (parser, (const unsigned char *)t->start, 866 t->len, 0, UCL_DUPLICATE_APPEND, type)) { 867 lua_pushboolean (L, true); 868 ret = 1; 869 } 870 else { 871 lua_pushboolean (L, false); 872 lua_pushstring (L, ucl_parser_get_error (parser)); 873 } 874 } 875 else { 876 lua_pushboolean (L, false); 877 lua_pushstring (L, "invalid arguments"); 878 } 879 880 return ret; 881 } 882 883 /*** 884 * @method parser:get_object() 885 * Get top object from parser and export it to lua representation. 886 * @return {variant or nil} ucl object as lua native variable 887 */ 888 static int 889 lua_ucl_parser_get_object (lua_State *L) 890 { 891 struct ucl_parser *parser; 892 ucl_object_t *obj; 893 int ret = 1; 894 895 parser = lua_ucl_parser_get (L, 1); 896 obj = ucl_parser_get_object (parser); 897 898 if (obj != NULL) { 899 ret = ucl_object_push_lua (L, obj, false); 900 /* no need to keep reference */ 901 ucl_object_unref (obj); 902 } 903 else { 904 lua_pushnil (L); 905 } 906 907 return ret; 908 } 909 910 /*** 911 * @method parser:get_object_wrapped() 912 * Get top object from parser and export it to userdata object without 913 * unwrapping to lua. 914 * @return {ucl.object or nil} ucl object wrapped variable 915 */ 916 static int 917 lua_ucl_parser_get_object_wrapped (lua_State *L) 918 { 919 struct ucl_parser *parser; 920 ucl_object_t *obj; 921 int ret = 1; 922 923 parser = lua_ucl_parser_get (L, 1); 924 obj = ucl_parser_get_object (parser); 925 926 if (obj != NULL) { 927 lua_ucl_push_opaque (L, obj); 928 } 929 else { 930 lua_pushnil (L); 931 } 932 933 return ret; 934 } 935 936 /*** 937 * @method parser:validate(schema) 938 * Validates the top object in the parser against schema. Schema might be 939 * another object or a string that represents file to load schema from. 940 * 941 * @param {string/table} schema input schema 942 * @return {result,err} two values: boolean result and the corresponding error 943 * 944 */ 945 static int 946 lua_ucl_parser_validate (lua_State *L) 947 { 948 struct ucl_parser *parser, *schema_parser; 949 ucl_object_t *schema; 950 const char *schema_file; 951 struct ucl_schema_error err; 952 953 parser = lua_ucl_parser_get (L, 1); 954 955 if (parser && parser->top_obj) { 956 if (lua_type (L, 2) == LUA_TTABLE) { 957 schema = ucl_object_lua_import (L, 2); 958 959 if (schema == NULL) { 960 lua_pushboolean (L, false); 961 lua_pushstring (L, "cannot load schema from lua table"); 962 963 return 2; 964 } 965 } 966 else if (lua_type (L, 2) == LUA_TSTRING) { 967 schema_parser = ucl_parser_new (0); 968 schema_file = luaL_checkstring (L, 2); 969 970 if (!ucl_parser_add_file (schema_parser, schema_file)) { 971 lua_pushboolean (L, false); 972 lua_pushfstring (L, "cannot parse schema file \"%s\": " 973 "%s", schema_file, ucl_parser_get_error (parser)); 974 ucl_parser_free (schema_parser); 975 976 return 2; 977 } 978 979 schema = ucl_parser_get_object (schema_parser); 980 ucl_parser_free (schema_parser); 981 } 982 else { 983 lua_pushboolean (L, false); 984 lua_pushstring (L, "invalid schema argument"); 985 986 return 2; 987 } 988 989 if (!ucl_object_validate (schema, parser->top_obj, &err)) { 990 lua_pushboolean (L, false); 991 lua_pushfstring (L, "validation error: " 992 "%s", err.msg); 993 } 994 else { 995 lua_pushboolean (L, true); 996 lua_pushnil (L); 997 } 998 999 ucl_object_unref (schema); 1000 } 1001 else { 1002 lua_pushboolean (L, false); 1003 lua_pushstring (L, "invalid parser or empty top object"); 1004 } 1005 1006 return 2; 1007 } 1008 1009 static int 1010 lua_ucl_parser_gc (lua_State *L) 1011 { 1012 struct ucl_parser *parser; 1013 1014 parser = lua_ucl_parser_get (L, 1); 1015 ucl_parser_free (parser); 1016 1017 return 0; 1018 } 1019 1020 /*** 1021 * @method object:unwrap() 1022 * Unwraps opaque ucl object to the native lua object (performing copying) 1023 * @return {variant} any lua object 1024 */ 1025 static int 1026 lua_ucl_object_unwrap (lua_State *L) 1027 { 1028 ucl_object_t *obj; 1029 1030 obj = lua_ucl_object_get (L, 1); 1031 1032 if (obj) { 1033 ucl_object_push_lua (L, obj, true); 1034 } 1035 else { 1036 lua_pushnil (L); 1037 } 1038 1039 return 1; 1040 } 1041 1042 static inline enum ucl_emitter 1043 lua_ucl_str_to_emit_type (const char *strtype) 1044 { 1045 enum ucl_emitter format = UCL_EMIT_JSON_COMPACT; 1046 1047 if (strcasecmp (strtype, "json") == 0) { 1048 format = UCL_EMIT_JSON; 1049 } 1050 else if (strcasecmp (strtype, "json-compact") == 0) { 1051 format = UCL_EMIT_JSON_COMPACT; 1052 } 1053 else if (strcasecmp (strtype, "yaml") == 0) { 1054 format = UCL_EMIT_YAML; 1055 } 1056 else if (strcasecmp (strtype, "config") == 0 || 1057 strcasecmp (strtype, "ucl") == 0) { 1058 format = UCL_EMIT_CONFIG; 1059 } 1060 1061 return format; 1062 } 1063 1064 /*** 1065 * @method object:tostring(type) 1066 * Unwraps opaque ucl object to string (json by default). Optionally you can 1067 * specify output format: 1068 * 1069 * - `json` - fine printed json 1070 * - `json-compact` - compacted json 1071 * - `config` - fine printed configuration 1072 * - `ucl` - same as `config` 1073 * - `yaml` - embedded yaml 1074 * @param {string} type optional 1075 * @return {string} string representation of the opaque ucl object 1076 */ 1077 static int 1078 lua_ucl_object_tostring (lua_State *L) 1079 { 1080 ucl_object_t *obj; 1081 enum ucl_emitter format = UCL_EMIT_JSON_COMPACT; 1082 1083 obj = lua_ucl_object_get (L, 1); 1084 1085 if (obj) { 1086 if (lua_gettop (L) > 1) { 1087 if (lua_type (L, 2) == LUA_TSTRING) { 1088 const char *strtype = lua_tostring (L, 2); 1089 1090 format = lua_ucl_str_to_emit_type (strtype); 1091 } 1092 } 1093 1094 return lua_ucl_to_string (L, obj, format); 1095 } 1096 else { 1097 lua_pushnil (L); 1098 } 1099 1100 return 1; 1101 } 1102 1103 /*** 1104 * @method object:validate(schema[, path[, ext_refs]]) 1105 * Validates the given ucl object using schema object represented as another 1106 * opaque ucl object. You can also specify path in the form `#/path/def` to 1107 * specify the specific schema element to perform validation. 1108 * 1109 * @param {ucl.object} schema schema object 1110 * @param {string} path optional path for validation procedure 1111 * @return {result,err} two values: boolean result and the corresponding 1112 * error, if `ext_refs` are also specified, then they are returned as opaque 1113 * ucl object as {result,err,ext_refs} 1114 */ 1115 static int 1116 lua_ucl_object_validate (lua_State *L) 1117 { 1118 ucl_object_t *obj, *schema, *ext_refs = NULL; 1119 const ucl_object_t *schema_elt; 1120 bool res = false; 1121 struct ucl_schema_error err; 1122 const char *path = NULL; 1123 1124 obj = lua_ucl_object_get (L, 1); 1125 schema = lua_ucl_object_get (L, 2); 1126 1127 if (schema && obj && ucl_object_type (schema) == UCL_OBJECT) { 1128 if (lua_gettop (L) > 2) { 1129 if (lua_type (L, 3) == LUA_TSTRING) { 1130 path = lua_tostring (L, 3); 1131 if (path[0] == '#') { 1132 path++; 1133 } 1134 } 1135 else if (lua_type (L, 3) == LUA_TUSERDATA || lua_type (L, 3) == 1136 LUA_TTABLE) { 1137 /* External refs */ 1138 ext_refs = lua_ucl_object_get (L, 3); 1139 } 1140 1141 if (lua_gettop (L) > 3) { 1142 if (lua_type (L, 4) == LUA_TUSERDATA || lua_type (L, 4) == 1143 LUA_TTABLE) { 1144 /* External refs */ 1145 ext_refs = lua_ucl_object_get (L, 4); 1146 } 1147 } 1148 } 1149 1150 if (path) { 1151 schema_elt = ucl_object_lookup_path_char (schema, path, '/'); 1152 } 1153 else { 1154 /* Use the top object */ 1155 schema_elt = schema; 1156 } 1157 1158 if (schema_elt) { 1159 res = ucl_object_validate_root_ext (schema_elt, obj, schema, 1160 ext_refs, &err); 1161 1162 if (res) { 1163 lua_pushboolean (L, res); 1164 lua_pushnil (L); 1165 1166 if (ext_refs) { 1167 lua_ucl_push_opaque (L, ext_refs); 1168 } 1169 } 1170 else { 1171 lua_pushboolean (L, res); 1172 lua_pushfstring (L, "validation error: %s", err.msg); 1173 1174 if (ext_refs) { 1175 lua_ucl_push_opaque (L, ext_refs); 1176 } 1177 } 1178 } 1179 else { 1180 lua_pushboolean (L, res); 1181 1182 lua_pushfstring (L, "cannot find the requested path: %s", path); 1183 1184 if (ext_refs) { 1185 lua_ucl_push_opaque (L, ext_refs); 1186 } 1187 } 1188 } 1189 else { 1190 lua_pushboolean (L, res); 1191 lua_pushstring (L, "invalid object or schema"); 1192 } 1193 1194 if (ext_refs) { 1195 return 3; 1196 } 1197 1198 return 2; 1199 } 1200 1201 static int 1202 lua_ucl_object_gc (lua_State *L) 1203 { 1204 ucl_object_t *obj; 1205 1206 obj = lua_ucl_object_get (L, 1); 1207 1208 ucl_object_unref (obj); 1209 1210 return 0; 1211 } 1212 1213 static void 1214 lua_ucl_parser_mt (lua_State *L) 1215 { 1216 luaL_newmetatable (L, PARSER_META); 1217 1218 lua_pushvalue(L, -1); 1219 lua_setfield(L, -2, "__index"); 1220 1221 lua_pushcfunction (L, lua_ucl_parser_gc); 1222 lua_setfield (L, -2, "__gc"); 1223 1224 lua_pushcfunction (L, lua_ucl_parser_parse_file); 1225 lua_setfield (L, -2, "parse_file"); 1226 1227 lua_pushcfunction (L, lua_ucl_parser_parse_string); 1228 lua_setfield (L, -2, "parse_string"); 1229 1230 lua_pushcfunction (L, lua_ucl_parser_parse_text); 1231 lua_setfield (L, -2, "parse_text"); 1232 1233 lua_pushcfunction (L, lua_ucl_parser_register_variable); 1234 lua_setfield (L, -2, "register_variable"); 1235 1236 lua_pushcfunction (L, lua_ucl_parser_register_variables); 1237 lua_setfield (L, -2, "register_variables"); 1238 1239 lua_pushcfunction (L, lua_ucl_parser_get_object); 1240 lua_setfield (L, -2, "get_object"); 1241 1242 lua_pushcfunction (L, lua_ucl_parser_get_object_wrapped); 1243 lua_setfield (L, -2, "get_object_wrapped"); 1244 1245 lua_pushcfunction (L, lua_ucl_parser_validate); 1246 lua_setfield (L, -2, "validate"); 1247 1248 lua_pop (L, 1); 1249 } 1250 1251 static void 1252 lua_ucl_object_mt (lua_State *L) 1253 { 1254 luaL_newmetatable (L, OBJECT_META); 1255 1256 lua_pushvalue(L, -1); 1257 lua_setfield(L, -2, "__index"); 1258 1259 lua_pushcfunction (L, lua_ucl_object_gc); 1260 lua_setfield (L, -2, "__gc"); 1261 1262 lua_pushcfunction (L, lua_ucl_object_tostring); 1263 lua_setfield (L, -2, "__tostring"); 1264 1265 lua_pushcfunction (L, lua_ucl_object_tostring); 1266 lua_setfield (L, -2, "tostring"); 1267 1268 lua_pushcfunction (L, lua_ucl_object_unwrap); 1269 lua_setfield (L, -2, "unwrap"); 1270 1271 lua_pushcfunction (L, lua_ucl_object_unwrap); 1272 lua_setfield (L, -2, "tolua"); 1273 1274 lua_pushcfunction (L, lua_ucl_object_validate); 1275 lua_setfield (L, -2, "validate"); 1276 1277 lua_pushstring (L, OBJECT_META); 1278 lua_setfield (L, -2, "class"); 1279 1280 lua_pop (L, 1); 1281 } 1282 1283 static void 1284 lua_ucl_types_mt (lua_State *L) 1285 { 1286 luaL_newmetatable (L, UCL_OBJECT_TYPE_META); 1287 1288 lua_pushcfunction (L, lua_ucl_object_tostring); 1289 lua_setfield (L, -2, "__tostring"); 1290 1291 lua_pushcfunction (L, lua_ucl_object_tostring); 1292 lua_setfield (L, -2, "tostring"); 1293 1294 lua_pushstring (L, UCL_OBJECT_TYPE_META); 1295 lua_setfield (L, -2, "class"); 1296 1297 lua_pop (L, 1); 1298 1299 luaL_newmetatable (L, UCL_ARRAY_TYPE_META); 1300 1301 lua_pushcfunction (L, lua_ucl_object_tostring); 1302 lua_setfield (L, -2, "__tostring"); 1303 1304 lua_pushcfunction (L, lua_ucl_object_tostring); 1305 lua_setfield (L, -2, "tostring"); 1306 1307 lua_pushstring (L, UCL_ARRAY_TYPE_META); 1308 lua_setfield (L, -2, "class"); 1309 1310 lua_pop (L, 1); 1311 1312 luaL_newmetatable (L, UCL_IMPL_ARRAY_TYPE_META); 1313 1314 lua_pushcfunction (L, lua_ucl_object_tostring); 1315 lua_setfield (L, -2, "__tostring"); 1316 1317 lua_pushcfunction (L, lua_ucl_object_tostring); 1318 lua_setfield (L, -2, "tostring"); 1319 1320 lua_pushstring (L, UCL_IMPL_ARRAY_TYPE_META); 1321 lua_setfield (L, -2, "class"); 1322 1323 lua_pop (L, 1); 1324 } 1325 1326 static int 1327 lua_ucl_to_json (lua_State *L) 1328 { 1329 ucl_object_t *obj; 1330 int format = UCL_EMIT_JSON; 1331 1332 if (lua_gettop (L) > 1) { 1333 if (lua_toboolean (L, 2)) { 1334 format = UCL_EMIT_JSON_COMPACT; 1335 } 1336 } 1337 1338 obj = ucl_object_lua_import (L, 1); 1339 if (obj != NULL) { 1340 lua_ucl_to_string (L, obj, format); 1341 ucl_object_unref (obj); 1342 } 1343 else { 1344 lua_pushnil (L); 1345 } 1346 1347 return 1; 1348 } 1349 1350 static int 1351 lua_ucl_to_config (lua_State *L) 1352 { 1353 ucl_object_t *obj; 1354 1355 obj = ucl_object_lua_import (L, 1); 1356 if (obj != NULL) { 1357 lua_ucl_to_string (L, obj, UCL_EMIT_CONFIG); 1358 ucl_object_unref (obj); 1359 } 1360 else { 1361 lua_pushnil (L); 1362 } 1363 1364 return 1; 1365 } 1366 1367 /*** 1368 * @function ucl.to_format(var, format) 1369 * Converts lua variable `var` to the specified `format`. Formats supported are: 1370 * 1371 * - `json` - fine printed json 1372 * - `json-compact` - compacted json 1373 * - `config` - fine printed configuration 1374 * - `ucl` - same as `config` 1375 * - `yaml` - embedded yaml 1376 * 1377 * If `var` contains function, they are called during output formatting and if 1378 * they return string value, then this value is used for output. 1379 * @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output) 1380 * @param {string} format any available format 1381 * @return {string} string representation of `var` in the specific `format`. 1382 * @example 1383 local table = { 1384 str = 'value', 1385 num = 100500, 1386 null = ucl.null, 1387 func = function () 1388 return 'huh' 1389 end 1390 } 1391 1392 print(ucl.to_format(table, 'ucl')) 1393 -- Output: 1394 --[[ 1395 num = 100500; 1396 str = "value"; 1397 null = null; 1398 func = "huh"; 1399 --]] 1400 */ 1401 static int 1402 lua_ucl_to_format (lua_State *L) 1403 { 1404 ucl_object_t *obj; 1405 int format = UCL_EMIT_JSON; 1406 bool sort = false; 1407 1408 if (lua_gettop (L) > 1) { 1409 if (lua_type (L, 2) == LUA_TNUMBER) { 1410 format = lua_tonumber (L, 2); 1411 if (format < 0 || format >= UCL_EMIT_YAML) { 1412 lua_pushnil (L); 1413 return 1; 1414 } 1415 } 1416 else if (lua_type (L, 2) == LUA_TSTRING) { 1417 const char *strtype = lua_tostring (L, 2); 1418 1419 if (strcasecmp (strtype, "json") == 0) { 1420 format = UCL_EMIT_JSON; 1421 } 1422 else if (strcasecmp (strtype, "json-compact") == 0) { 1423 format = UCL_EMIT_JSON_COMPACT; 1424 } 1425 else if (strcasecmp (strtype, "yaml") == 0) { 1426 format = UCL_EMIT_YAML; 1427 } 1428 else if (strcasecmp (strtype, "config") == 0 || 1429 strcasecmp (strtype, "ucl") == 0) { 1430 format = UCL_EMIT_CONFIG; 1431 } 1432 else if (strcasecmp (strtype, "msgpack") == 0) { 1433 format = UCL_EMIT_MSGPACK; 1434 } 1435 } 1436 1437 if (lua_isboolean (L, 3)) { 1438 sort = lua_toboolean (L, 3); 1439 } 1440 } 1441 1442 obj = ucl_object_lua_import (L, 1); 1443 1444 if (obj != NULL) { 1445 1446 if (sort) { 1447 if (ucl_object_type (obj) == UCL_OBJECT) { 1448 ucl_object_sort_keys (obj, UCL_SORT_KEYS_RECURSIVE); 1449 } 1450 } 1451 1452 lua_ucl_to_string (L, obj, format); 1453 ucl_object_unref (obj); 1454 } 1455 else { 1456 lua_pushnil (L); 1457 } 1458 1459 return 1; 1460 } 1461 1462 static int 1463 lua_ucl_null_tostring (lua_State* L) 1464 { 1465 lua_pushstring (L, "null"); 1466 return 1; 1467 } 1468 1469 static void 1470 lua_ucl_null_mt (lua_State *L) 1471 { 1472 luaL_newmetatable (L, NULL_META); 1473 1474 lua_pushcfunction (L, lua_ucl_null_tostring); 1475 lua_setfield (L, -2, "__tostring"); 1476 1477 lua_pop (L, 1); 1478 } 1479 1480 int 1481 luaopen_ucl (lua_State *L) 1482 { 1483 lua_ucl_parser_mt (L); 1484 lua_ucl_null_mt (L); 1485 lua_ucl_object_mt (L); 1486 lua_ucl_types_mt (L); 1487 1488 /* Create the refs weak table: */ 1489 lua_createtable (L, 0, 2); 1490 lua_pushliteral (L, "v"); /* tbl, "v" */ 1491 lua_setfield (L, -2, "__mode"); 1492 lua_pushvalue (L, -1); /* tbl, tbl */ 1493 lua_setmetatable (L, -2); /* tbl */ 1494 lua_setfield (L, LUA_REGISTRYINDEX, "ucl.refs"); 1495 1496 lua_newtable (L); 1497 1498 lua_pushcfunction (L, lua_ucl_parser_init); 1499 lua_setfield (L, -2, "parser"); 1500 1501 lua_pushcfunction (L, lua_ucl_to_json); 1502 lua_setfield (L, -2, "to_json"); 1503 1504 lua_pushcfunction (L, lua_ucl_to_config); 1505 lua_setfield (L, -2, "to_config"); 1506 1507 lua_pushcfunction (L, lua_ucl_to_format); 1508 lua_setfield (L, -2, "to_format"); 1509 1510 ucl_null = lua_newuserdata (L, 0); 1511 luaL_getmetatable (L, NULL_META); 1512 lua_setmetatable (L, -2); 1513 1514 lua_pushvalue (L, -1); 1515 lua_setfield (L, LUA_REGISTRYINDEX, "ucl.null"); 1516 1517 lua_setfield (L, -2, "null"); 1518 1519 return 1; 1520 } 1521 1522 struct ucl_lua_funcdata* 1523 ucl_object_toclosure (const ucl_object_t *obj) 1524 { 1525 if (obj == NULL || obj->type != UCL_USERDATA) { 1526 return NULL; 1527 } 1528 1529 return (struct ucl_lua_funcdata*)obj->value.ud; 1530 } 1531