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