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