Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/external/libucl/lua/lua_ucl.c
2066 views
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
int i;
410
411
if (!is_implicit) {
412
top = ucl_object_typed_new (UCL_ARRAY);
413
ucl_object_reserve (top, nelts);
414
}
415
else {
416
top = NULL;
417
}
418
419
for (i = 1; i <= max; i ++) {
420
lua_pushinteger (L, i);
421
lua_gettable (L, idx);
422
423
obj = ucl_object_lua_fromelt (L, lua_gettop (L), flags);
424
425
if (obj != NULL) {
426
if (is_implicit) {
427
DL_APPEND (top, obj);
428
}
429
else {
430
ucl_array_append (top, obj);
431
}
432
}
433
lua_pop (L, 1);
434
}
435
}
436
else {
437
lua_pushnil (L);
438
top = ucl_object_typed_new (UCL_OBJECT);
439
ucl_object_reserve (top, nelts);
440
441
while (lua_next (L, idx) != 0) {
442
/* copy key to avoid modifications */
443
lua_pushvalue (L, -2);
444
k = lua_tolstring (L, -1, &keylen);
445
obj = ucl_object_lua_fromelt (L, lua_gettop (L) - 1, flags);
446
447
if (obj != NULL) {
448
ucl_object_insert_key (top, obj, k, keylen, true);
449
450
DL_FOREACH (obj, cur) {
451
if (cur->keylen == 0) {
452
cur->keylen = obj->keylen;
453
cur->key = obj->key;
454
}
455
}
456
}
457
lua_pop (L, 2);
458
}
459
}
460
461
return top;
462
}
463
464
/**
465
* Get a single element from lua to object obj
466
* @param L
467
* @param obj
468
* @param idx
469
*/
470
static ucl_object_t *
471
ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags)
472
{
473
int type;
474
double num;
475
ucl_object_t *obj = NULL;
476
struct ucl_lua_funcdata *fd;
477
const char *str;
478
size_t sz;
479
480
type = lua_type (L, idx);
481
482
switch (type) {
483
case LUA_TSTRING:
484
str = lua_tolstring (L, idx, &sz);
485
486
if (str) {
487
/*
488
* ucl_object_fromstring_common has a `logic` to use strlen if sz is zero
489
* which is totally broken...
490
*/
491
if (sz > 0) {
492
obj = ucl_object_fromstring_common(str, sz, flags);
493
}
494
else {
495
obj = ucl_object_fromstring_common("", sz, flags);
496
}
497
}
498
else {
499
obj = ucl_object_typed_new (UCL_NULL);
500
}
501
break;
502
case LUA_TNUMBER:
503
num = lua_tonumber (L, idx);
504
if (num == (int64_t)num) {
505
obj = ucl_object_fromint (num);
506
}
507
else {
508
obj = ucl_object_fromdouble (num);
509
}
510
break;
511
case LUA_TBOOLEAN:
512
obj = ucl_object_frombool (lua_toboolean (L, idx));
513
break;
514
case LUA_TUSERDATA:
515
if (lua_topointer (L, idx) == ucl_null) {
516
obj = ucl_object_typed_new (UCL_NULL);
517
}
518
else {
519
/* Assume it is a text like object */
520
struct _rspamd_lua_text *t = lua_touserdata (L, idx);
521
522
if (t) {
523
if (t->len >0) {
524
obj = ucl_object_fromstring_common(t->start, t->len, 0);
525
}
526
else {
527
obj = ucl_object_fromstring_common("", 0, 0);
528
}
529
530
/* Binary text */
531
if (t->flags & (1u << 5u)) {
532
obj->flags |= UCL_OBJECT_BINARY;
533
}
534
}
535
}
536
break;
537
case LUA_TTABLE:
538
case LUA_TFUNCTION:
539
case LUA_TTHREAD:
540
if (luaL_getmetafield (L, idx, "__gen_ucl")) {
541
if (lua_isfunction (L, -1)) {
542
lua_settop (L, 3); /* gen, obj, func */
543
lua_insert (L, 1); /* func, gen, obj */
544
lua_insert (L, 2); /* func, obj, gen */
545
lua_call(L, 2, 1);
546
obj = ucl_object_lua_fromelt (L, 1, flags);
547
}
548
lua_pop (L, 2);
549
}
550
else {
551
if (type == LUA_TTABLE) {
552
obj = ucl_object_lua_fromtable (L, idx, flags);
553
}
554
else if (type == LUA_TFUNCTION) {
555
fd = malloc (sizeof (*fd));
556
if (fd != NULL) {
557
lua_pushvalue (L, idx);
558
fd->L = L;
559
fd->ret = NULL;
560
fd->idx = luaL_ref (L, LUA_REGISTRYINDEX);
561
562
obj = ucl_object_new_userdata (lua_ucl_userdata_dtor,
563
lua_ucl_userdata_emitter, (void *)fd);
564
}
565
}
566
}
567
break;
568
}
569
570
return obj;
571
}
572
573
/**
574
* @function ucl_object_lua_import(L, idx)
575
* Extracts ucl object from lua variable at `idx` position,
576
* @see ucl_object_push_lua for conversion definitions
577
* @param {lua_state} L lua state machine pointer
578
* @param {int} idx index where the source variable is placed
579
* @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
580
* this object thus needs to be unref'ed after usage.
581
*/
582
ucl_object_t *
583
ucl_object_lua_import (lua_State *L, int idx)
584
{
585
ucl_object_t *obj;
586
int t;
587
588
t = lua_type (L, idx);
589
switch (t) {
590
case LUA_TTABLE:
591
obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_RAW);
592
break;
593
default:
594
obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_RAW);
595
break;
596
}
597
598
return obj;
599
}
600
601
/**
602
* @function ucl_object_lua_import_escape(L, idx)
603
* Extracts ucl object from lua variable at `idx` position escaping JSON strings
604
* @see ucl_object_push_lua for conversion definitions
605
* @param {lua_state} L lua state machine pointer
606
* @param {int} idx index where the source variable is placed
607
* @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
608
* this object thus needs to be unref'ed after usage.
609
*/
610
ucl_object_t *
611
ucl_object_lua_import_escape (lua_State *L, int idx)
612
{
613
ucl_object_t *obj;
614
int t;
615
616
t = lua_type (L, idx);
617
switch (t) {
618
case LUA_TTABLE:
619
obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_ESCAPE);
620
break;
621
default:
622
obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_ESCAPE);
623
break;
624
}
625
626
return obj;
627
}
628
629
static int
630
lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type)
631
{
632
unsigned char *result;
633
size_t outlen;
634
635
result = ucl_object_emit_len (obj, type, &outlen);
636
637
if (result != NULL) {
638
lua_pushlstring (L, (const char *)result, outlen);
639
free (result);
640
}
641
else {
642
lua_pushnil (L);
643
}
644
645
return 1;
646
}
647
648
static int
649
lua_ucl_parser_init (lua_State *L)
650
{
651
struct ucl_parser *parser, **pparser;
652
int flags = UCL_PARSER_NO_FILEVARS;
653
654
if (lua_gettop (L) >= 1) {
655
flags = lua_tonumber (L, 1);
656
}
657
658
parser = ucl_parser_new (flags);
659
if (parser == NULL) {
660
lua_pushnil (L);
661
}
662
663
pparser = lua_newuserdata (L, sizeof (parser));
664
*pparser = parser;
665
luaL_getmetatable (L, PARSER_META);
666
lua_setmetatable (L, -2);
667
668
return 1;
669
}
670
671
static struct ucl_parser *
672
lua_ucl_parser_get (lua_State *L, int index)
673
{
674
return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META));
675
}
676
677
static ucl_object_t *
678
lua_ucl_object_get (lua_State *L, int index)
679
{
680
return *((ucl_object_t **) luaL_checkudata(L, index, OBJECT_META));
681
}
682
683
static void
684
lua_ucl_push_opaque (lua_State *L, ucl_object_t *obj)
685
{
686
ucl_object_t **pobj;
687
688
pobj = lua_newuserdata (L, sizeof (*pobj));
689
*pobj = obj;
690
luaL_getmetatable (L, OBJECT_META);
691
lua_setmetatable (L, -2);
692
}
693
694
static inline enum ucl_parse_type
695
lua_ucl_str_to_parse_type (const char *str)
696
{
697
enum ucl_parse_type type = UCL_PARSE_UCL;
698
699
if (str != NULL) {
700
if (strcasecmp (str, "msgpack") == 0) {
701
type = UCL_PARSE_MSGPACK;
702
}
703
else if (strcasecmp (str, "sexp") == 0 ||
704
strcasecmp (str, "csexp") == 0) {
705
type = UCL_PARSE_CSEXP;
706
}
707
else if (strcasecmp (str, "auto") == 0) {
708
type = UCL_PARSE_AUTO;
709
}
710
}
711
712
return type;
713
}
714
715
/***
716
* @method parser:parse_file(name)
717
* Parse UCL object from file.
718
* @param {string} name filename to parse
719
* @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
720
@example
721
local parser = ucl.parser()
722
local res,err = parser:parse_file('/some/file.conf')
723
724
if not res then
725
print('parser error: ' .. err)
726
else
727
-- Do something with object
728
end
729
*/
730
static int
731
lua_ucl_parser_parse_file (lua_State *L)
732
{
733
struct ucl_parser *parser;
734
const char *file;
735
int ret = 2;
736
737
parser = lua_ucl_parser_get (L, 1);
738
file = luaL_checkstring (L, 2);
739
740
if (parser != NULL && file != NULL) {
741
if (ucl_parser_add_file (parser, file)) {
742
lua_pushboolean (L, true);
743
ret = 1;
744
}
745
else {
746
lua_pushboolean (L, false);
747
lua_pushstring (L, ucl_parser_get_error (parser));
748
}
749
}
750
else {
751
lua_pushboolean (L, false);
752
lua_pushstring (L, "invalid arguments");
753
}
754
755
return ret;
756
}
757
758
/***
759
* @method parser:register_variable(name, value)
760
* Register parser variable
761
* @param {string} name name of variable
762
* @param {string} value value of variable
763
* @return {bool} success
764
@example
765
local parser = ucl.parser()
766
local res = parser:register_variable('CONFDIR', '/etc/foo')
767
*/
768
static int
769
lua_ucl_parser_register_variable (lua_State *L)
770
{
771
struct ucl_parser *parser;
772
const char *name, *value;
773
int ret = 2;
774
775
parser = lua_ucl_parser_get (L, 1);
776
name = luaL_checkstring (L, 2);
777
value = luaL_checkstring (L, 3);
778
779
if (parser != NULL && name != NULL && value != NULL) {
780
ucl_parser_register_variable (parser, name, value);
781
lua_pushboolean (L, true);
782
ret = 1;
783
}
784
else {
785
return luaL_error (L, "invalid arguments");
786
}
787
788
return ret;
789
}
790
791
/***
792
* @method parser:register_variables(vars)
793
* Register parser variables
794
* @param {table} vars names/values of variables
795
* @return {bool} success
796
@example
797
local parser = ucl.parser()
798
local res = parser:register_variables({CONFDIR = '/etc/foo', VARDIR = '/var'})
799
*/
800
static int
801
lua_ucl_parser_register_variables (lua_State *L)
802
{
803
struct ucl_parser *parser;
804
const char *name, *value;
805
int ret = 2;
806
807
parser = lua_ucl_parser_get (L, 1);
808
809
if (parser != NULL && lua_type (L, 2) == LUA_TTABLE) {
810
for (lua_pushnil (L); lua_next (L, 2); lua_pop (L, 1)) {
811
lua_pushvalue (L, -2);
812
name = luaL_checkstring (L, -1);
813
value = luaL_checkstring (L, -2);
814
ucl_parser_register_variable (parser, name, value);
815
lua_pop (L, 1);
816
}
817
818
lua_pushboolean (L, true);
819
ret = 1;
820
}
821
else {
822
return luaL_error (L, "invalid arguments");
823
}
824
825
return ret;
826
}
827
828
/***
829
* @method parser:parse_string(input)
830
* Parse UCL object from file.
831
* @param {string} input string to parse
832
* @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
833
*/
834
static int
835
lua_ucl_parser_parse_string (lua_State *L)
836
{
837
struct ucl_parser *parser;
838
const char *string;
839
size_t llen;
840
enum ucl_parse_type type = UCL_PARSE_UCL;
841
int ret = 2;
842
843
parser = lua_ucl_parser_get (L, 1);
844
string = luaL_checklstring (L, 2, &llen);
845
846
if (lua_type (L, 3) == LUA_TSTRING) {
847
type = lua_ucl_str_to_parse_type (lua_tostring (L, 3));
848
}
849
850
if (parser != NULL && string != NULL) {
851
if (ucl_parser_add_chunk_full (parser, (const unsigned char *)string,
852
llen, 0, UCL_DUPLICATE_APPEND, type)) {
853
lua_pushboolean (L, true);
854
ret = 1;
855
}
856
else {
857
lua_pushboolean (L, false);
858
lua_pushstring (L, ucl_parser_get_error (parser));
859
}
860
}
861
else {
862
lua_pushboolean (L, false);
863
lua_pushstring (L, "invalid arguments");
864
}
865
866
return ret;
867
}
868
869
/***
870
* @method parser:parse_text(input)
871
* Parse UCL object from text object (Rspamd specific).
872
* @param {rspamd_text} input text to parse
873
* @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
874
*/
875
static int
876
lua_ucl_parser_parse_text (lua_State *L)
877
{
878
struct ucl_parser *parser;
879
struct _rspamd_lua_text *t;
880
enum ucl_parse_type type = UCL_PARSE_UCL;
881
int ret = 2;
882
883
parser = lua_ucl_parser_get (L, 1);
884
885
if (lua_type (L, 2) == LUA_TUSERDATA) {
886
t = lua_touserdata (L, 2);
887
}
888
else if (lua_type (L, 2) == LUA_TSTRING) {
889
const gchar *s;
890
gsize len;
891
static struct _rspamd_lua_text st_t;
892
893
s = lua_tolstring (L, 2, &len);
894
st_t.start = s;
895
st_t.len = len;
896
897
t = &st_t;
898
}
899
else {
900
return luaL_error(L, "invalid argument as input, expected userdata or a string");
901
}
902
903
if (lua_type (L, 3) == LUA_TSTRING) {
904
type = lua_ucl_str_to_parse_type (lua_tostring (L, 3));
905
}
906
907
if (parser != NULL && t != NULL) {
908
if (ucl_parser_add_chunk_full (parser, (const unsigned char *)t->start,
909
t->len, 0, UCL_DUPLICATE_APPEND, type)) {
910
lua_pushboolean (L, true);
911
ret = 1;
912
}
913
else {
914
lua_pushboolean (L, false);
915
lua_pushstring (L, ucl_parser_get_error (parser));
916
}
917
}
918
else {
919
lua_pushboolean (L, false);
920
lua_pushstring (L, "invalid arguments");
921
}
922
923
return ret;
924
}
925
926
/***
927
* @method parser:get_object()
928
* Get top object from parser and export it to lua representation.
929
* @return {variant or nil} ucl object as lua native variable
930
*/
931
static int
932
lua_ucl_parser_get_object (lua_State *L)
933
{
934
struct ucl_parser *parser;
935
ucl_object_t *obj;
936
int ret = 1;
937
938
parser = lua_ucl_parser_get (L, 1);
939
obj = ucl_parser_get_object (parser);
940
941
if (obj != NULL) {
942
ret = ucl_object_push_lua (L, obj, false);
943
/* no need to keep reference */
944
ucl_object_unref (obj);
945
}
946
else {
947
lua_pushnil (L);
948
}
949
950
return ret;
951
}
952
953
/***
954
* @method parser:get_object_wrapped()
955
* Get top object from parser and export it to userdata object without
956
* unwrapping to lua.
957
* @return {ucl.object or nil} ucl object wrapped variable
958
*/
959
static int
960
lua_ucl_parser_get_object_wrapped (lua_State *L)
961
{
962
struct ucl_parser *parser;
963
ucl_object_t *obj;
964
int ret = 1;
965
966
parser = lua_ucl_parser_get (L, 1);
967
obj = ucl_parser_get_object (parser);
968
969
if (obj != NULL) {
970
lua_ucl_push_opaque (L, obj);
971
}
972
else {
973
lua_pushnil (L);
974
}
975
976
return ret;
977
}
978
979
/***
980
* @method parser:validate(schema)
981
* Validates the top object in the parser against schema. Schema might be
982
* another object or a string that represents file to load schema from.
983
*
984
* @param {string/table} schema input schema
985
* @return {result,err} two values: boolean result and the corresponding error
986
*
987
*/
988
static int
989
lua_ucl_parser_validate (lua_State *L)
990
{
991
struct ucl_parser *parser, *schema_parser;
992
ucl_object_t *schema;
993
const char *schema_file;
994
struct ucl_schema_error err;
995
996
parser = lua_ucl_parser_get (L, 1);
997
998
if (parser && parser->top_obj) {
999
if (lua_type (L, 2) == LUA_TTABLE) {
1000
schema = ucl_object_lua_import (L, 2);
1001
1002
if (schema == NULL) {
1003
lua_pushboolean (L, false);
1004
lua_pushstring (L, "cannot load schema from lua table");
1005
1006
return 2;
1007
}
1008
}
1009
else if (lua_type (L, 2) == LUA_TSTRING) {
1010
schema_parser = ucl_parser_new (0);
1011
schema_file = luaL_checkstring (L, 2);
1012
1013
if (!ucl_parser_add_file (schema_parser, schema_file)) {
1014
lua_pushboolean (L, false);
1015
lua_pushfstring (L, "cannot parse schema file \"%s\": "
1016
"%s", schema_file, ucl_parser_get_error (parser));
1017
ucl_parser_free (schema_parser);
1018
1019
return 2;
1020
}
1021
1022
schema = ucl_parser_get_object (schema_parser);
1023
ucl_parser_free (schema_parser);
1024
}
1025
else {
1026
lua_pushboolean (L, false);
1027
lua_pushstring (L, "invalid schema argument");
1028
1029
return 2;
1030
}
1031
1032
if (!ucl_object_validate (schema, parser->top_obj, &err)) {
1033
lua_pushboolean (L, false);
1034
lua_pushfstring (L, "validation error: "
1035
"%s", err.msg);
1036
}
1037
else {
1038
lua_pushboolean (L, true);
1039
lua_pushnil (L);
1040
}
1041
1042
ucl_object_unref (schema);
1043
}
1044
else {
1045
lua_pushboolean (L, false);
1046
lua_pushstring (L, "invalid parser or empty top object");
1047
}
1048
1049
return 2;
1050
}
1051
1052
static int
1053
lua_ucl_parser_gc (lua_State *L)
1054
{
1055
struct ucl_parser *parser;
1056
1057
parser = lua_ucl_parser_get (L, 1);
1058
ucl_parser_free (parser);
1059
1060
return 0;
1061
}
1062
1063
/***
1064
* @method object:unwrap()
1065
* Unwraps opaque ucl object to the native lua object (performing copying)
1066
* @return {variant} any lua object
1067
*/
1068
static int
1069
lua_ucl_object_unwrap (lua_State *L)
1070
{
1071
ucl_object_t *obj;
1072
1073
obj = lua_ucl_object_get (L, 1);
1074
1075
if (obj) {
1076
ucl_object_push_lua (L, obj, true);
1077
}
1078
else {
1079
lua_pushnil (L);
1080
}
1081
1082
return 1;
1083
}
1084
1085
static inline enum ucl_emitter
1086
lua_ucl_str_to_emit_type (const char *strtype)
1087
{
1088
enum ucl_emitter format = UCL_EMIT_JSON_COMPACT;
1089
1090
if (strcasecmp (strtype, "json") == 0) {
1091
format = UCL_EMIT_JSON;
1092
}
1093
else if (strcasecmp (strtype, "json-compact") == 0) {
1094
format = UCL_EMIT_JSON_COMPACT;
1095
}
1096
else if (strcasecmp (strtype, "yaml") == 0) {
1097
format = UCL_EMIT_YAML;
1098
}
1099
else if (strcasecmp (strtype, "config") == 0 ||
1100
strcasecmp (strtype, "ucl") == 0) {
1101
format = UCL_EMIT_CONFIG;
1102
}
1103
1104
return format;
1105
}
1106
1107
/***
1108
* @method object:tostring(type)
1109
* Unwraps opaque ucl object to string (json by default). Optionally you can
1110
* specify output format:
1111
*
1112
* - `json` - fine printed json
1113
* - `json-compact` - compacted json
1114
* - `config` - fine printed configuration
1115
* - `ucl` - same as `config`
1116
* - `yaml` - embedded yaml
1117
* @param {string} type optional
1118
* @return {string} string representation of the opaque ucl object
1119
*/
1120
static int
1121
lua_ucl_object_tostring (lua_State *L)
1122
{
1123
ucl_object_t *obj;
1124
enum ucl_emitter format = UCL_EMIT_JSON_COMPACT;
1125
1126
obj = lua_ucl_object_get (L, 1);
1127
1128
if (obj) {
1129
if (lua_gettop (L) > 1) {
1130
if (lua_type (L, 2) == LUA_TSTRING) {
1131
const char *strtype = lua_tostring (L, 2);
1132
1133
format = lua_ucl_str_to_emit_type (strtype);
1134
}
1135
}
1136
1137
return lua_ucl_to_string (L, obj, format);
1138
}
1139
else {
1140
lua_pushnil (L);
1141
}
1142
1143
return 1;
1144
}
1145
1146
/***
1147
* @method object:validate(schema[, path[, ext_refs]])
1148
* Validates the given ucl object using schema object represented as another
1149
* opaque ucl object. You can also specify path in the form `#/path/def` to
1150
* specify the specific schema element to perform validation.
1151
*
1152
* @param {ucl.object} schema schema object
1153
* @param {string} path optional path for validation procedure
1154
* @return {result,err} two values: boolean result and the corresponding
1155
* error, if `ext_refs` are also specified, then they are returned as opaque
1156
* ucl object as {result,err,ext_refs}
1157
*/
1158
static int
1159
lua_ucl_object_validate (lua_State *L)
1160
{
1161
ucl_object_t *obj, *schema, *ext_refs = NULL;
1162
const ucl_object_t *schema_elt;
1163
bool res = false;
1164
struct ucl_schema_error err;
1165
const char *path = NULL;
1166
1167
obj = lua_ucl_object_get (L, 1);
1168
schema = lua_ucl_object_get (L, 2);
1169
1170
if (schema && obj && ucl_object_type (schema) == UCL_OBJECT) {
1171
if (lua_gettop (L) > 2) {
1172
if (lua_type (L, 3) == LUA_TSTRING) {
1173
path = lua_tostring (L, 3);
1174
if (path[0] == '#') {
1175
path++;
1176
}
1177
}
1178
else if (lua_type (L, 3) == LUA_TUSERDATA || lua_type (L, 3) ==
1179
LUA_TTABLE) {
1180
/* External refs */
1181
ext_refs = lua_ucl_object_get (L, 3);
1182
}
1183
1184
if (lua_gettop (L) > 3) {
1185
if (lua_type (L, 4) == LUA_TUSERDATA || lua_type (L, 4) ==
1186
LUA_TTABLE) {
1187
/* External refs */
1188
ext_refs = lua_ucl_object_get (L, 4);
1189
}
1190
}
1191
}
1192
1193
if (path) {
1194
schema_elt = ucl_object_lookup_path_char (schema, path, '/');
1195
}
1196
else {
1197
/* Use the top object */
1198
schema_elt = schema;
1199
}
1200
1201
if (schema_elt) {
1202
res = ucl_object_validate_root_ext (schema_elt, obj, schema,
1203
ext_refs, &err);
1204
1205
if (res) {
1206
lua_pushboolean (L, res);
1207
lua_pushnil (L);
1208
1209
if (ext_refs) {
1210
lua_ucl_push_opaque (L, ext_refs);
1211
}
1212
}
1213
else {
1214
lua_pushboolean (L, res);
1215
lua_pushfstring (L, "validation error: %s", err.msg);
1216
1217
if (ext_refs) {
1218
lua_ucl_push_opaque (L, ext_refs);
1219
}
1220
}
1221
}
1222
else {
1223
lua_pushboolean (L, res);
1224
1225
lua_pushfstring (L, "cannot find the requested path: %s", path);
1226
1227
if (ext_refs) {
1228
lua_ucl_push_opaque (L, ext_refs);
1229
}
1230
}
1231
}
1232
else {
1233
lua_pushboolean (L, res);
1234
lua_pushstring (L, "invalid object or schema");
1235
}
1236
1237
if (ext_refs) {
1238
return 3;
1239
}
1240
1241
return 2;
1242
}
1243
1244
static int
1245
lua_ucl_object_gc (lua_State *L)
1246
{
1247
ucl_object_t *obj;
1248
1249
obj = lua_ucl_object_get (L, 1);
1250
1251
ucl_object_unref (obj);
1252
1253
return 0;
1254
}
1255
1256
static void
1257
lua_ucl_parser_mt (lua_State *L)
1258
{
1259
luaL_newmetatable (L, PARSER_META);
1260
1261
lua_pushvalue(L, -1);
1262
lua_setfield(L, -2, "__index");
1263
1264
lua_pushcfunction (L, lua_ucl_parser_gc);
1265
lua_setfield (L, -2, "__gc");
1266
1267
lua_pushcfunction (L, lua_ucl_parser_parse_file);
1268
lua_setfield (L, -2, "parse_file");
1269
1270
lua_pushcfunction (L, lua_ucl_parser_parse_string);
1271
lua_setfield (L, -2, "parse_string");
1272
1273
lua_pushcfunction (L, lua_ucl_parser_parse_text);
1274
lua_setfield (L, -2, "parse_text");
1275
1276
lua_pushcfunction (L, lua_ucl_parser_register_variable);
1277
lua_setfield (L, -2, "register_variable");
1278
1279
lua_pushcfunction (L, lua_ucl_parser_register_variables);
1280
lua_setfield (L, -2, "register_variables");
1281
1282
lua_pushcfunction (L, lua_ucl_parser_get_object);
1283
lua_setfield (L, -2, "get_object");
1284
1285
lua_pushcfunction (L, lua_ucl_parser_get_object_wrapped);
1286
lua_setfield (L, -2, "get_object_wrapped");
1287
1288
lua_pushcfunction (L, lua_ucl_parser_validate);
1289
lua_setfield (L, -2, "validate");
1290
1291
lua_pop (L, 1);
1292
}
1293
1294
static void
1295
lua_ucl_object_mt (lua_State *L)
1296
{
1297
luaL_newmetatable (L, OBJECT_META);
1298
1299
lua_pushvalue(L, -1);
1300
lua_setfield(L, -2, "__index");
1301
1302
lua_pushcfunction (L, lua_ucl_object_gc);
1303
lua_setfield (L, -2, "__gc");
1304
1305
lua_pushcfunction (L, lua_ucl_object_tostring);
1306
lua_setfield (L, -2, "__tostring");
1307
1308
lua_pushcfunction (L, lua_ucl_object_tostring);
1309
lua_setfield (L, -2, "tostring");
1310
1311
lua_pushcfunction (L, lua_ucl_object_unwrap);
1312
lua_setfield (L, -2, "unwrap");
1313
1314
lua_pushcfunction (L, lua_ucl_object_unwrap);
1315
lua_setfield (L, -2, "tolua");
1316
1317
lua_pushcfunction (L, lua_ucl_object_validate);
1318
lua_setfield (L, -2, "validate");
1319
1320
lua_pushstring (L, OBJECT_META);
1321
lua_setfield (L, -2, "class");
1322
1323
lua_pop (L, 1);
1324
}
1325
1326
static void
1327
lua_ucl_types_mt (lua_State *L)
1328
{
1329
luaL_newmetatable (L, UCL_OBJECT_TYPE_META);
1330
1331
lua_pushcfunction (L, lua_ucl_object_tostring);
1332
lua_setfield (L, -2, "__tostring");
1333
1334
lua_pushcfunction (L, lua_ucl_object_tostring);
1335
lua_setfield (L, -2, "tostring");
1336
1337
lua_pushstring (L, UCL_OBJECT_TYPE_META);
1338
lua_setfield (L, -2, "class");
1339
1340
lua_pop (L, 1);
1341
1342
luaL_newmetatable (L, UCL_ARRAY_TYPE_META);
1343
1344
lua_pushcfunction (L, lua_ucl_object_tostring);
1345
lua_setfield (L, -2, "__tostring");
1346
1347
lua_pushcfunction (L, lua_ucl_object_tostring);
1348
lua_setfield (L, -2, "tostring");
1349
1350
lua_pushstring (L, UCL_ARRAY_TYPE_META);
1351
lua_setfield (L, -2, "class");
1352
1353
lua_pop (L, 1);
1354
1355
luaL_newmetatable (L, UCL_IMPL_ARRAY_TYPE_META);
1356
1357
lua_pushcfunction (L, lua_ucl_object_tostring);
1358
lua_setfield (L, -2, "__tostring");
1359
1360
lua_pushcfunction (L, lua_ucl_object_tostring);
1361
lua_setfield (L, -2, "tostring");
1362
1363
lua_pushstring (L, UCL_IMPL_ARRAY_TYPE_META);
1364
lua_setfield (L, -2, "class");
1365
1366
lua_pop (L, 1);
1367
}
1368
1369
static int
1370
lua_ucl_to_json (lua_State *L)
1371
{
1372
ucl_object_t *obj;
1373
int format = UCL_EMIT_JSON;
1374
1375
if (lua_gettop (L) > 1) {
1376
if (lua_toboolean (L, 2)) {
1377
format = UCL_EMIT_JSON_COMPACT;
1378
}
1379
}
1380
1381
obj = ucl_object_lua_import (L, 1);
1382
if (obj != NULL) {
1383
lua_ucl_to_string (L, obj, format);
1384
ucl_object_unref (obj);
1385
}
1386
else {
1387
lua_pushnil (L);
1388
}
1389
1390
return 1;
1391
}
1392
1393
static int
1394
lua_ucl_to_config (lua_State *L)
1395
{
1396
ucl_object_t *obj;
1397
1398
obj = ucl_object_lua_import (L, 1);
1399
if (obj != NULL) {
1400
lua_ucl_to_string (L, obj, UCL_EMIT_CONFIG);
1401
ucl_object_unref (obj);
1402
}
1403
else {
1404
lua_pushnil (L);
1405
}
1406
1407
return 1;
1408
}
1409
1410
/***
1411
* @function ucl.to_format(var, format)
1412
* Converts lua variable `var` to the specified `format`. Formats supported are:
1413
*
1414
* - `json` - fine printed json
1415
* - `json-compact` - compacted json
1416
* - `config` - fine printed configuration
1417
* - `ucl` - same as `config`
1418
* - `yaml` - embedded yaml
1419
*
1420
* If `var` contains function, they are called during output formatting and if
1421
* they return string value, then this value is used for output.
1422
* @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
1423
* @param {string} format any available format
1424
* @return {string} string representation of `var` in the specific `format`.
1425
* @example
1426
local table = {
1427
str = 'value',
1428
num = 100500,
1429
null = ucl.null,
1430
func = function ()
1431
return 'huh'
1432
end
1433
}
1434
1435
print(ucl.to_format(table, 'ucl'))
1436
-- Output:
1437
--[[
1438
num = 100500;
1439
str = "value";
1440
null = null;
1441
func = "huh";
1442
--]]
1443
*/
1444
static int
1445
lua_ucl_to_format (lua_State *L)
1446
{
1447
ucl_object_t *obj;
1448
int format = UCL_EMIT_JSON;
1449
bool sort = false;
1450
1451
if (lua_gettop (L) > 1) {
1452
if (lua_type (L, 2) == LUA_TNUMBER) {
1453
format = lua_tonumber (L, 2);
1454
if (format < 0 || format >= UCL_EMIT_YAML) {
1455
lua_pushnil (L);
1456
return 1;
1457
}
1458
}
1459
else if (lua_type (L, 2) == LUA_TSTRING) {
1460
const char *strtype = lua_tostring (L, 2);
1461
1462
if (strcasecmp (strtype, "json") == 0) {
1463
format = UCL_EMIT_JSON;
1464
}
1465
else if (strcasecmp (strtype, "json-compact") == 0) {
1466
format = UCL_EMIT_JSON_COMPACT;
1467
}
1468
else if (strcasecmp (strtype, "yaml") == 0) {
1469
format = UCL_EMIT_YAML;
1470
}
1471
else if (strcasecmp (strtype, "config") == 0 ||
1472
strcasecmp (strtype, "ucl") == 0) {
1473
format = UCL_EMIT_CONFIG;
1474
}
1475
else if (strcasecmp (strtype, "msgpack") == 0 ||
1476
strcasecmp (strtype, "messagepack") == 0) {
1477
format = UCL_EMIT_MSGPACK;
1478
}
1479
}
1480
1481
if (lua_isboolean (L, 3)) {
1482
sort = lua_toboolean (L, 3);
1483
}
1484
}
1485
1486
obj = ucl_object_lua_import (L, 1);
1487
1488
if (obj != NULL) {
1489
1490
if (sort) {
1491
if (ucl_object_type (obj) == UCL_OBJECT) {
1492
ucl_object_sort_keys (obj, UCL_SORT_KEYS_RECURSIVE);
1493
}
1494
}
1495
1496
lua_ucl_to_string (L, obj, format);
1497
ucl_object_unref (obj);
1498
}
1499
else {
1500
lua_pushnil (L);
1501
}
1502
1503
return 1;
1504
}
1505
1506
static int
1507
lua_ucl_null_tostring (lua_State* L)
1508
{
1509
lua_pushstring (L, "null");
1510
return 1;
1511
}
1512
1513
static void
1514
lua_ucl_null_mt (lua_State *L)
1515
{
1516
luaL_newmetatable (L, NULL_META);
1517
1518
lua_pushcfunction (L, lua_ucl_null_tostring);
1519
lua_setfield (L, -2, "__tostring");
1520
1521
lua_pop (L, 1);
1522
}
1523
1524
int
1525
luaopen_ucl (lua_State *L)
1526
{
1527
lua_ucl_parser_mt (L);
1528
lua_ucl_null_mt (L);
1529
lua_ucl_object_mt (L);
1530
lua_ucl_types_mt (L);
1531
1532
/* Create the refs weak table: */
1533
lua_createtable (L, 0, 2);
1534
lua_pushliteral (L, "v"); /* tbl, "v" */
1535
lua_setfield (L, -2, "__mode");
1536
lua_pushvalue (L, -1); /* tbl, tbl */
1537
lua_setmetatable (L, -2); /* tbl */
1538
lua_setfield (L, LUA_REGISTRYINDEX, "ucl.refs");
1539
1540
lua_newtable (L);
1541
1542
lua_pushcfunction (L, lua_ucl_parser_init);
1543
lua_setfield (L, -2, "parser");
1544
1545
lua_pushcfunction (L, lua_ucl_to_json);
1546
lua_setfield (L, -2, "to_json");
1547
1548
lua_pushcfunction (L, lua_ucl_to_config);
1549
lua_setfield (L, -2, "to_config");
1550
1551
lua_pushcfunction (L, lua_ucl_to_format);
1552
lua_setfield (L, -2, "to_format");
1553
1554
ucl_null = lua_newuserdata (L, 0);
1555
luaL_getmetatable (L, NULL_META);
1556
lua_setmetatable (L, -2);
1557
1558
lua_pushvalue (L, -1);
1559
lua_setfield (L, LUA_REGISTRYINDEX, "ucl.null");
1560
1561
lua_setfield (L, -2, "null");
1562
1563
return 1;
1564
}
1565
1566
struct ucl_lua_funcdata*
1567
ucl_object_toclosure (const ucl_object_t *obj)
1568
{
1569
if (obj == NULL || obj->type != UCL_USERDATA) {
1570
return NULL;
1571
}
1572
1573
return (struct ucl_lua_funcdata*)obj->value.ud;
1574
}
1575
1576