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 /* 654 * We disable file variables and macros by default, as 655 * the most use cases are parsing of JSON and not of the real 656 * files. Macros in the parser are very dangerous and should be used 657 * for trusted data only. 658 */ 659 int flags = UCL_PARSER_NO_FILEVARS|UCL_PARSER_DISABLE_MACRO; 660 661 if (lua_gettop (L) >= 1) { 662 flags = lua_tonumber (L, 1); 663 } 664 665 parser = ucl_parser_new (flags); 666 if (parser == NULL) { 667 lua_pushnil (L); 668 } 669 670 pparser = lua_newuserdata (L, sizeof (parser)); 671 *pparser = parser; 672 luaL_getmetatable (L, PARSER_META); 673 lua_setmetatable (L, -2); 674 675 return 1; 676 } 677 678 static struct ucl_parser * 679 lua_ucl_parser_get (lua_State *L, int index) 680 { 681 return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META)); 682 } 683 684 static ucl_object_t * 685 lua_ucl_object_get (lua_State *L, int index) 686 { 687 return *((ucl_object_t **) luaL_checkudata(L, index, OBJECT_META)); 688 } 689 690 static void 691 lua_ucl_push_opaque (lua_State *L, ucl_object_t *obj) 692 { 693 ucl_object_t **pobj; 694 695 pobj = lua_newuserdata (L, sizeof (*pobj)); 696 *pobj = obj; 697 luaL_getmetatable (L, OBJECT_META); 698 lua_setmetatable (L, -2); 699 } 700 701 static inline enum ucl_parse_type 702 lua_ucl_str_to_parse_type (const char *str) 703 { 704 enum ucl_parse_type type = UCL_PARSE_UCL; 705 706 if (str != NULL) { 707 if (strcasecmp (str, "msgpack") == 0) { 708 type = UCL_PARSE_MSGPACK; 709 } 710 else if (strcasecmp (str, "sexp") == 0 || 711 strcasecmp (str, "csexp") == 0) { 712 type = UCL_PARSE_CSEXP; 713 } 714 else if (strcasecmp (str, "auto") == 0) { 715 type = UCL_PARSE_AUTO; 716 } 717 } 718 719 return type; 720 } 721 722 /*** 723 * @method parser:parse_file(name) 724 * Parse UCL object from file. 725 * @param {string} name filename to parse 726 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned 727 @example 728 local parser = ucl.parser() 729 local res,err = parser:parse_file('/some/file.conf') 730 731 if not res then 732 print('parser error: ' .. err) 733 else 734 -- Do something with object 735 end 736 */ 737 static int 738 lua_ucl_parser_parse_file (lua_State *L) 739 { 740 struct ucl_parser *parser; 741 const char *file; 742 int ret = 2; 743 744 parser = lua_ucl_parser_get (L, 1); 745 file = luaL_checkstring (L, 2); 746 747 if (parser != NULL && file != NULL) { 748 if (ucl_parser_add_file (parser, file)) { 749 lua_pushboolean (L, true); 750 ret = 1; 751 } 752 else { 753 lua_pushboolean (L, false); 754 lua_pushstring (L, ucl_parser_get_error (parser)); 755 } 756 } 757 else { 758 lua_pushboolean (L, false); 759 lua_pushstring (L, "invalid arguments"); 760 } 761 762 return ret; 763 } 764 765 /*** 766 * @method parser:register_variable(name, value) 767 * Register parser variable 768 * @param {string} name name of variable 769 * @param {string} value value of variable 770 * @return {bool} success 771 @example 772 local parser = ucl.parser() 773 local res = parser:register_variable('CONFDIR', '/etc/foo') 774 */ 775 static int 776 lua_ucl_parser_register_variable (lua_State *L) 777 { 778 struct ucl_parser *parser; 779 const char *name, *value; 780 int ret = 2; 781 782 parser = lua_ucl_parser_get (L, 1); 783 name = luaL_checkstring (L, 2); 784 value = luaL_checkstring (L, 3); 785 786 if (parser != NULL && name != NULL && value != NULL) { 787 ucl_parser_register_variable (parser, name, value); 788 lua_pushboolean (L, true); 789 ret = 1; 790 } 791 else { 792 return luaL_error (L, "invalid arguments"); 793 } 794 795 return ret; 796 } 797 798 /*** 799 * @method parser:register_variables(vars) 800 * Register parser variables 801 * @param {table} vars names/values of variables 802 * @return {bool} success 803 @example 804 local parser = ucl.parser() 805 local res = parser:register_variables({CONFDIR = '/etc/foo', VARDIR = '/var'}) 806 */ 807 static int 808 lua_ucl_parser_register_variables (lua_State *L) 809 { 810 struct ucl_parser *parser; 811 const char *name, *value; 812 int ret = 2; 813 814 parser = lua_ucl_parser_get (L, 1); 815 816 if (parser != NULL && lua_type (L, 2) == LUA_TTABLE) { 817 for (lua_pushnil (L); lua_next (L, 2); lua_pop (L, 1)) { 818 lua_pushvalue (L, -2); 819 name = luaL_checkstring (L, -1); 820 value = luaL_checkstring (L, -2); 821 ucl_parser_register_variable (parser, name, value); 822 lua_pop (L, 1); 823 } 824 825 lua_pushboolean (L, true); 826 ret = 1; 827 } 828 else { 829 return luaL_error (L, "invalid arguments"); 830 } 831 832 return ret; 833 } 834 835 /*** 836 * @method parser:parse_string(input) 837 * Parse UCL object from file. 838 * @param {string} input string to parse 839 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned 840 */ 841 static int 842 lua_ucl_parser_parse_string (lua_State *L) 843 { 844 struct ucl_parser *parser; 845 const char *string; 846 size_t llen; 847 enum ucl_parse_type type = UCL_PARSE_UCL; 848 int ret = 2; 849 850 parser = lua_ucl_parser_get (L, 1); 851 string = luaL_checklstring (L, 2, &llen); 852 853 if (lua_type (L, 3) == LUA_TSTRING) { 854 type = lua_ucl_str_to_parse_type (lua_tostring (L, 3)); 855 } 856 857 if (parser != NULL && string != NULL) { 858 if (ucl_parser_add_chunk_full (parser, (const unsigned char *)string, 859 llen, 0, UCL_DUPLICATE_APPEND, type)) { 860 lua_pushboolean (L, true); 861 ret = 1; 862 } 863 else { 864 lua_pushboolean (L, false); 865 lua_pushstring (L, ucl_parser_get_error (parser)); 866 } 867 } 868 else { 869 lua_pushboolean (L, false); 870 lua_pushstring (L, "invalid arguments"); 871 } 872 873 return ret; 874 } 875 876 /*** 877 * @method parser:parse_text(input) 878 * Parse UCL object from text object (Rspamd specific). 879 * @param {rspamd_text} input text to parse 880 * @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned 881 */ 882 static int 883 lua_ucl_parser_parse_text (lua_State *L) 884 { 885 struct ucl_parser *parser; 886 struct _rspamd_lua_text *t; 887 enum ucl_parse_type type = UCL_PARSE_UCL; 888 int ret = 2; 889 890 parser = lua_ucl_parser_get (L, 1); 891 892 if (lua_type (L, 2) == LUA_TUSERDATA) { 893 t = lua_touserdata (L, 2); 894 } 895 else if (lua_type (L, 2) == LUA_TSTRING) { 896 const char *s; 897 size_t len; 898 static struct _rspamd_lua_text st_t; 899 900 s = lua_tolstring (L, 2, &len); 901 st_t.start = s; 902 st_t.len = len; 903 904 t = &st_t; 905 } 906 else { 907 return luaL_error(L, "invalid argument as input, expected userdata or a string"); 908 } 909 910 if (lua_type (L, 3) == LUA_TSTRING) { 911 type = lua_ucl_str_to_parse_type (lua_tostring (L, 3)); 912 } 913 914 if (parser != NULL && t != NULL) { 915 if (ucl_parser_add_chunk_full (parser, (const unsigned char *)t->start, 916 t->len, 0, UCL_DUPLICATE_APPEND, type)) { 917 lua_pushboolean (L, true); 918 ret = 1; 919 } 920 else { 921 lua_pushboolean (L, false); 922 lua_pushstring (L, ucl_parser_get_error (parser)); 923 } 924 } 925 else { 926 lua_pushboolean (L, false); 927 lua_pushstring (L, "invalid arguments"); 928 } 929 930 return ret; 931 } 932 933 /*** 934 * @method parser:get_object() 935 * Get top object from parser and export it to lua representation. 936 * @return {variant or nil} ucl object as lua native variable 937 */ 938 static int 939 lua_ucl_parser_get_object (lua_State *L) 940 { 941 struct ucl_parser *parser; 942 ucl_object_t *obj; 943 int ret = 1; 944 945 parser = lua_ucl_parser_get (L, 1); 946 obj = ucl_parser_get_object (parser); 947 948 if (obj != NULL) { 949 ret = ucl_object_push_lua (L, obj, false); 950 /* no need to keep reference */ 951 ucl_object_unref (obj); 952 } 953 else { 954 lua_pushnil (L); 955 } 956 957 return ret; 958 } 959 960 /*** 961 * @method parser:get_object_wrapped() 962 * Get top object from parser and export it to userdata object without 963 * unwrapping to lua. 964 * @return {ucl.object or nil} ucl object wrapped variable 965 */ 966 static int 967 lua_ucl_parser_get_object_wrapped (lua_State *L) 968 { 969 struct ucl_parser *parser; 970 ucl_object_t *obj; 971 int ret = 1; 972 973 parser = lua_ucl_parser_get (L, 1); 974 obj = ucl_parser_get_object (parser); 975 976 if (obj != NULL) { 977 lua_ucl_push_opaque (L, obj); 978 } 979 else { 980 lua_pushnil (L); 981 } 982 983 return ret; 984 } 985 986 /*** 987 * @method parser:validate(schema) 988 * Validates the top object in the parser against schema. Schema might be 989 * another object or a string that represents file to load schema from. 990 * 991 * @param {string/table} schema input schema 992 * @return {result,err} two values: boolean result and the corresponding error 993 * 994 */ 995 static int 996 lua_ucl_parser_validate (lua_State *L) 997 { 998 struct ucl_parser *parser, *schema_parser; 999 ucl_object_t *schema; 1000 const char *schema_file; 1001 struct ucl_schema_error err; 1002 1003 parser = lua_ucl_parser_get (L, 1); 1004 1005 if (parser && parser->top_obj) { 1006 if (lua_type (L, 2) == LUA_TTABLE) { 1007 schema = ucl_object_lua_import (L, 2); 1008 1009 if (schema == NULL) { 1010 lua_pushboolean (L, false); 1011 lua_pushstring (L, "cannot load schema from lua table"); 1012 1013 return 2; 1014 } 1015 } 1016 else if (lua_type (L, 2) == LUA_TSTRING) { 1017 schema_parser = ucl_parser_new (0); 1018 schema_file = luaL_checkstring (L, 2); 1019 1020 if (!ucl_parser_add_file (schema_parser, schema_file)) { 1021 lua_pushboolean (L, false); 1022 lua_pushfstring (L, "cannot parse schema file \"%s\": " 1023 "%s", schema_file, ucl_parser_get_error (parser)); 1024 ucl_parser_free (schema_parser); 1025 1026 return 2; 1027 } 1028 1029 schema = ucl_parser_get_object (schema_parser); 1030 ucl_parser_free (schema_parser); 1031 } 1032 else { 1033 lua_pushboolean (L, false); 1034 lua_pushstring (L, "invalid schema argument"); 1035 1036 return 2; 1037 } 1038 1039 if (!ucl_object_validate (schema, parser->top_obj, &err)) { 1040 lua_pushboolean (L, false); 1041 lua_pushfstring (L, "validation error: " 1042 "%s", err.msg); 1043 } 1044 else { 1045 lua_pushboolean (L, true); 1046 lua_pushnil (L); 1047 } 1048 1049 ucl_object_unref (schema); 1050 } 1051 else { 1052 lua_pushboolean (L, false); 1053 lua_pushstring (L, "invalid parser or empty top object"); 1054 } 1055 1056 return 2; 1057 } 1058 1059 static int 1060 lua_ucl_parser_gc (lua_State *L) 1061 { 1062 struct ucl_parser *parser; 1063 1064 parser = lua_ucl_parser_get (L, 1); 1065 ucl_parser_free (parser); 1066 1067 return 0; 1068 } 1069 1070 /*** 1071 * @method object:unwrap() 1072 * Unwraps opaque ucl object to the native lua object (performing copying) 1073 * @return {variant} any lua object 1074 */ 1075 static int 1076 lua_ucl_object_unwrap (lua_State *L) 1077 { 1078 ucl_object_t *obj; 1079 1080 obj = lua_ucl_object_get (L, 1); 1081 1082 if (obj) { 1083 ucl_object_push_lua (L, obj, true); 1084 } 1085 else { 1086 lua_pushnil (L); 1087 } 1088 1089 return 1; 1090 } 1091 1092 static inline enum ucl_emitter 1093 lua_ucl_str_to_emit_type (const char *strtype) 1094 { 1095 enum ucl_emitter format = UCL_EMIT_JSON_COMPACT; 1096 1097 if (strcasecmp (strtype, "json") == 0) { 1098 format = UCL_EMIT_JSON; 1099 } 1100 else if (strcasecmp (strtype, "json-compact") == 0) { 1101 format = UCL_EMIT_JSON_COMPACT; 1102 } 1103 else if (strcasecmp (strtype, "yaml") == 0) { 1104 format = UCL_EMIT_YAML; 1105 } 1106 else if (strcasecmp (strtype, "config") == 0 || 1107 strcasecmp (strtype, "ucl") == 0) { 1108 format = UCL_EMIT_CONFIG; 1109 } 1110 1111 return format; 1112 } 1113 1114 /*** 1115 * @method object:tostring(type) 1116 * Unwraps opaque ucl object to string (json by default). Optionally you can 1117 * specify output format: 1118 * 1119 * - `json` - fine printed json 1120 * - `json-compact` - compacted json 1121 * - `config` - fine printed configuration 1122 * - `ucl` - same as `config` 1123 * - `yaml` - embedded yaml 1124 * @param {string} type optional 1125 * @return {string} string representation of the opaque ucl object 1126 */ 1127 static int 1128 lua_ucl_object_tostring (lua_State *L) 1129 { 1130 ucl_object_t *obj; 1131 enum ucl_emitter format = UCL_EMIT_JSON_COMPACT; 1132 1133 obj = lua_ucl_object_get (L, 1); 1134 1135 if (obj) { 1136 if (lua_gettop (L) > 1) { 1137 if (lua_type (L, 2) == LUA_TSTRING) { 1138 const char *strtype = lua_tostring (L, 2); 1139 1140 format = lua_ucl_str_to_emit_type (strtype); 1141 } 1142 } 1143 1144 return lua_ucl_to_string (L, obj, format); 1145 } 1146 else { 1147 lua_pushnil (L); 1148 } 1149 1150 return 1; 1151 } 1152 1153 /*** 1154 * @method object:validate(schema[, path[, ext_refs]]) 1155 * Validates the given ucl object using schema object represented as another 1156 * opaque ucl object. You can also specify path in the form `#/path/def` to 1157 * specify the specific schema element to perform validation. 1158 * 1159 * @param {ucl.object} schema schema object 1160 * @param {string} path optional path for validation procedure 1161 * @return {result,err} two values: boolean result and the corresponding 1162 * error, if `ext_refs` are also specified, then they are returned as opaque 1163 * ucl object as {result,err,ext_refs} 1164 */ 1165 static int 1166 lua_ucl_object_validate (lua_State *L) 1167 { 1168 ucl_object_t *obj, *schema, *ext_refs = NULL; 1169 const ucl_object_t *schema_elt; 1170 bool res = false; 1171 struct ucl_schema_error err; 1172 const char *path = NULL; 1173 1174 obj = lua_ucl_object_get (L, 1); 1175 schema = lua_ucl_object_get (L, 2); 1176 1177 if (schema && obj && ucl_object_type (schema) == UCL_OBJECT) { 1178 if (lua_gettop (L) > 2) { 1179 if (lua_type (L, 3) == LUA_TSTRING) { 1180 path = lua_tostring (L, 3); 1181 if (path[0] == '#') { 1182 path++; 1183 } 1184 } 1185 else if (lua_type (L, 3) == LUA_TUSERDATA || lua_type (L, 3) == 1186 LUA_TTABLE) { 1187 /* External refs */ 1188 ext_refs = lua_ucl_object_get (L, 3); 1189 } 1190 1191 if (lua_gettop (L) > 3) { 1192 if (lua_type (L, 4) == LUA_TUSERDATA || lua_type (L, 4) == 1193 LUA_TTABLE) { 1194 /* External refs */ 1195 ext_refs = lua_ucl_object_get (L, 4); 1196 } 1197 } 1198 } 1199 1200 if (path) { 1201 schema_elt = ucl_object_lookup_path_char (schema, path, '/'); 1202 } 1203 else { 1204 /* Use the top object */ 1205 schema_elt = schema; 1206 } 1207 1208 if (schema_elt) { 1209 res = ucl_object_validate_root_ext (schema_elt, obj, schema, 1210 ext_refs, &err); 1211 1212 if (res) { 1213 lua_pushboolean (L, res); 1214 lua_pushnil (L); 1215 1216 if (ext_refs) { 1217 lua_ucl_push_opaque (L, ext_refs); 1218 } 1219 } 1220 else { 1221 lua_pushboolean (L, res); 1222 lua_pushfstring (L, "validation error: %s", err.msg); 1223 1224 if (ext_refs) { 1225 lua_ucl_push_opaque (L, ext_refs); 1226 } 1227 } 1228 } 1229 else { 1230 lua_pushboolean (L, res); 1231 1232 lua_pushfstring (L, "cannot find the requested path: %s", path); 1233 1234 if (ext_refs) { 1235 lua_ucl_push_opaque (L, ext_refs); 1236 } 1237 } 1238 } 1239 else { 1240 lua_pushboolean (L, res); 1241 lua_pushstring (L, "invalid object or schema"); 1242 } 1243 1244 if (ext_refs) { 1245 return 3; 1246 } 1247 1248 return 2; 1249 } 1250 1251 static int 1252 lua_ucl_object_gc (lua_State *L) 1253 { 1254 ucl_object_t *obj; 1255 1256 obj = lua_ucl_object_get (L, 1); 1257 1258 ucl_object_unref (obj); 1259 1260 return 0; 1261 } 1262 1263 static void 1264 lua_ucl_parser_mt (lua_State *L) 1265 { 1266 luaL_newmetatable (L, PARSER_META); 1267 1268 lua_pushvalue(L, -1); 1269 lua_setfield(L, -2, "__index"); 1270 1271 lua_pushcfunction (L, lua_ucl_parser_gc); 1272 lua_setfield (L, -2, "__gc"); 1273 1274 lua_pushcfunction (L, lua_ucl_parser_parse_file); 1275 lua_setfield (L, -2, "parse_file"); 1276 1277 lua_pushcfunction (L, lua_ucl_parser_parse_string); 1278 lua_setfield (L, -2, "parse_string"); 1279 1280 lua_pushcfunction (L, lua_ucl_parser_parse_text); 1281 lua_setfield (L, -2, "parse_text"); 1282 1283 lua_pushcfunction (L, lua_ucl_parser_register_variable); 1284 lua_setfield (L, -2, "register_variable"); 1285 1286 lua_pushcfunction (L, lua_ucl_parser_register_variables); 1287 lua_setfield (L, -2, "register_variables"); 1288 1289 lua_pushcfunction (L, lua_ucl_parser_get_object); 1290 lua_setfield (L, -2, "get_object"); 1291 1292 lua_pushcfunction (L, lua_ucl_parser_get_object_wrapped); 1293 lua_setfield (L, -2, "get_object_wrapped"); 1294 1295 lua_pushcfunction (L, lua_ucl_parser_validate); 1296 lua_setfield (L, -2, "validate"); 1297 1298 lua_pop (L, 1); 1299 } 1300 1301 static void 1302 lua_ucl_object_mt (lua_State *L) 1303 { 1304 luaL_newmetatable (L, OBJECT_META); 1305 1306 lua_pushvalue(L, -1); 1307 lua_setfield(L, -2, "__index"); 1308 1309 lua_pushcfunction (L, lua_ucl_object_gc); 1310 lua_setfield (L, -2, "__gc"); 1311 1312 lua_pushcfunction (L, lua_ucl_object_tostring); 1313 lua_setfield (L, -2, "__tostring"); 1314 1315 lua_pushcfunction (L, lua_ucl_object_tostring); 1316 lua_setfield (L, -2, "tostring"); 1317 1318 lua_pushcfunction (L, lua_ucl_object_unwrap); 1319 lua_setfield (L, -2, "unwrap"); 1320 1321 lua_pushcfunction (L, lua_ucl_object_unwrap); 1322 lua_setfield (L, -2, "tolua"); 1323 1324 lua_pushcfunction (L, lua_ucl_object_validate); 1325 lua_setfield (L, -2, "validate"); 1326 1327 lua_pushstring (L, OBJECT_META); 1328 lua_setfield (L, -2, "class"); 1329 1330 lua_pop (L, 1); 1331 } 1332 1333 static void 1334 lua_ucl_types_mt (lua_State *L) 1335 { 1336 luaL_newmetatable (L, UCL_OBJECT_TYPE_META); 1337 1338 lua_pushcfunction (L, lua_ucl_object_tostring); 1339 lua_setfield (L, -2, "__tostring"); 1340 1341 lua_pushcfunction (L, lua_ucl_object_tostring); 1342 lua_setfield (L, -2, "tostring"); 1343 1344 lua_pushstring (L, UCL_OBJECT_TYPE_META); 1345 lua_setfield (L, -2, "class"); 1346 1347 lua_pop (L, 1); 1348 1349 luaL_newmetatable (L, UCL_ARRAY_TYPE_META); 1350 1351 lua_pushcfunction (L, lua_ucl_object_tostring); 1352 lua_setfield (L, -2, "__tostring"); 1353 1354 lua_pushcfunction (L, lua_ucl_object_tostring); 1355 lua_setfield (L, -2, "tostring"); 1356 1357 lua_pushstring (L, UCL_ARRAY_TYPE_META); 1358 lua_setfield (L, -2, "class"); 1359 1360 lua_pop (L, 1); 1361 1362 luaL_newmetatable (L, UCL_IMPL_ARRAY_TYPE_META); 1363 1364 lua_pushcfunction (L, lua_ucl_object_tostring); 1365 lua_setfield (L, -2, "__tostring"); 1366 1367 lua_pushcfunction (L, lua_ucl_object_tostring); 1368 lua_setfield (L, -2, "tostring"); 1369 1370 lua_pushstring (L, UCL_IMPL_ARRAY_TYPE_META); 1371 lua_setfield (L, -2, "class"); 1372 1373 lua_pop (L, 1); 1374 } 1375 1376 static int 1377 lua_ucl_to_json (lua_State *L) 1378 { 1379 ucl_object_t *obj; 1380 int format = UCL_EMIT_JSON; 1381 1382 if (lua_gettop (L) > 1) { 1383 if (lua_toboolean (L, 2)) { 1384 format = UCL_EMIT_JSON_COMPACT; 1385 } 1386 } 1387 1388 obj = ucl_object_lua_import (L, 1); 1389 if (obj != NULL) { 1390 lua_ucl_to_string (L, obj, format); 1391 ucl_object_unref (obj); 1392 } 1393 else { 1394 lua_pushnil (L); 1395 } 1396 1397 return 1; 1398 } 1399 1400 static int 1401 lua_ucl_to_config (lua_State *L) 1402 { 1403 ucl_object_t *obj; 1404 1405 obj = ucl_object_lua_import (L, 1); 1406 if (obj != NULL) { 1407 lua_ucl_to_string (L, obj, UCL_EMIT_CONFIG); 1408 ucl_object_unref (obj); 1409 } 1410 else { 1411 lua_pushnil (L); 1412 } 1413 1414 return 1; 1415 } 1416 1417 /*** 1418 * @function ucl.to_format(var, format) 1419 * Converts lua variable `var` to the specified `format`. Formats supported are: 1420 * 1421 * - `json` - fine printed json 1422 * - `json-compact` - compacted json 1423 * - `config` - fine printed configuration 1424 * - `ucl` - same as `config` 1425 * - `yaml` - embedded yaml 1426 * 1427 * If `var` contains function, they are called during output formatting and if 1428 * they return string value, then this value is used for output. 1429 * @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output) 1430 * @param {string} format any available format 1431 * @return {string} string representation of `var` in the specific `format`. 1432 * @example 1433 local table = { 1434 str = 'value', 1435 num = 100500, 1436 null = ucl.null, 1437 func = function () 1438 return 'huh' 1439 end 1440 } 1441 1442 print(ucl.to_format(table, 'ucl')) 1443 -- Output: 1444 --[[ 1445 num = 100500; 1446 str = "value"; 1447 null = null; 1448 func = "huh"; 1449 --]] 1450 */ 1451 static int 1452 lua_ucl_to_format (lua_State *L) 1453 { 1454 ucl_object_t *obj; 1455 int format = UCL_EMIT_JSON; 1456 bool sort = false; 1457 1458 if (lua_gettop (L) > 1) { 1459 if (lua_type (L, 2) == LUA_TNUMBER) { 1460 format = lua_tonumber (L, 2); 1461 if (format < 0 || format >= UCL_EMIT_YAML) { 1462 lua_pushnil (L); 1463 return 1; 1464 } 1465 } 1466 else if (lua_type (L, 2) == LUA_TSTRING) { 1467 const char *strtype = lua_tostring (L, 2); 1468 1469 if (strcasecmp (strtype, "json") == 0) { 1470 format = UCL_EMIT_JSON; 1471 } 1472 else if (strcasecmp (strtype, "json-compact") == 0) { 1473 format = UCL_EMIT_JSON_COMPACT; 1474 } 1475 else if (strcasecmp (strtype, "yaml") == 0) { 1476 format = UCL_EMIT_YAML; 1477 } 1478 else if (strcasecmp (strtype, "config") == 0 || 1479 strcasecmp (strtype, "ucl") == 0) { 1480 format = UCL_EMIT_CONFIG; 1481 } 1482 else if (strcasecmp (strtype, "msgpack") == 0 || 1483 strcasecmp (strtype, "messagepack") == 0) { 1484 format = UCL_EMIT_MSGPACK; 1485 } 1486 } 1487 1488 if (lua_isboolean (L, 3)) { 1489 sort = lua_toboolean (L, 3); 1490 } 1491 } 1492 1493 obj = ucl_object_lua_import (L, 1); 1494 1495 if (obj != NULL) { 1496 1497 if (sort) { 1498 if (ucl_object_type (obj) == UCL_OBJECT) { 1499 ucl_object_sort_keys (obj, UCL_SORT_KEYS_RECURSIVE); 1500 } 1501 } 1502 1503 lua_ucl_to_string (L, obj, format); 1504 ucl_object_unref (obj); 1505 } 1506 else { 1507 lua_pushnil (L); 1508 } 1509 1510 return 1; 1511 } 1512 1513 static int 1514 lua_ucl_null_tostring (lua_State* L) 1515 { 1516 lua_pushstring (L, "null"); 1517 return 1; 1518 } 1519 1520 static void 1521 lua_ucl_null_mt (lua_State *L) 1522 { 1523 luaL_newmetatable (L, NULL_META); 1524 1525 lua_pushcfunction (L, lua_ucl_null_tostring); 1526 lua_setfield (L, -2, "__tostring"); 1527 1528 lua_pop (L, 1); 1529 } 1530 1531 int 1532 luaopen_ucl (lua_State *L) 1533 { 1534 lua_ucl_parser_mt (L); 1535 lua_ucl_null_mt (L); 1536 lua_ucl_object_mt (L); 1537 lua_ucl_types_mt (L); 1538 1539 /* Create the refs weak table: */ 1540 lua_createtable (L, 0, 2); 1541 lua_pushliteral (L, "v"); /* tbl, "v" */ 1542 lua_setfield (L, -2, "__mode"); 1543 lua_pushvalue (L, -1); /* tbl, tbl */ 1544 lua_setmetatable (L, -2); /* tbl */ 1545 lua_setfield (L, LUA_REGISTRYINDEX, "ucl.refs"); 1546 1547 lua_newtable (L); 1548 1549 lua_pushcfunction (L, lua_ucl_parser_init); 1550 lua_setfield (L, -2, "parser"); 1551 1552 lua_pushcfunction (L, lua_ucl_to_json); 1553 lua_setfield (L, -2, "to_json"); 1554 1555 lua_pushcfunction (L, lua_ucl_to_config); 1556 lua_setfield (L, -2, "to_config"); 1557 1558 lua_pushcfunction (L, lua_ucl_to_format); 1559 lua_setfield (L, -2, "to_format"); 1560 1561 ucl_null = lua_newuserdata (L, 0); 1562 luaL_getmetatable (L, NULL_META); 1563 lua_setmetatable (L, -2); 1564 1565 lua_pushvalue (L, -1); 1566 lua_setfield (L, LUA_REGISTRYINDEX, "ucl.null"); 1567 1568 lua_setfield (L, -2, "null"); 1569 1570 return 1; 1571 } 1572 1573 struct ucl_lua_funcdata* 1574 ucl_object_toclosure (const ucl_object_t *obj) 1575 { 1576 if (obj == NULL || obj->type != UCL_USERDATA) { 1577 return NULL; 1578 } 1579 1580 return (struct ucl_lua_funcdata*)obj->value.ud; 1581 } 1582 1583 FLUA_MODULE(ucl); 1584