Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/lyaml/ext/yaml/emitter.c
178703 views
1
/*
2
* emitter.c, LibYAML emitter binding for Lua
3
* Written by Gary V. Vaughan, 2013
4
*
5
* Copyright (C) 2013-2022 Gary V. Vaughan
6
*
7
* Permission is hereby granted, free of charge, to any person obtaining a copy
8
* of this software and associated documentation files (the "Software"), to deal
9
* in the Software without restriction, including without limitation the rights
10
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
* copies of the Software, and to permit persons to whom the Software is
12
* furnished to do so, subject to the following conditions:
13
*
14
* The above copyright notice and this permission notice shall be included in
15
* all copies or substantial portions of the Software.
16
*
17
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
* THE SOFTWARE.
24
*/
25
26
#include <assert.h>
27
28
#include "lyaml.h"
29
30
31
typedef struct {
32
yaml_emitter_t emitter;
33
34
/* output accumulator */
35
lua_State *outputL;
36
luaL_Buffer yamlbuff;
37
38
/* error handling */
39
lua_State *errL;
40
luaL_Buffer errbuff;
41
int error;
42
} lyaml_emitter;
43
44
45
/* Emit a STREAM_START event. */
46
static int
47
emit_STREAM_START (lua_State *L, lyaml_emitter *emitter)
48
{
49
yaml_event_t event;
50
yaml_encoding_t yaml_encoding;
51
const char *encoding = NULL;
52
53
RAWGET_STRDUP (encoding); lua_pop (L, 1);
54
55
#define MENTRY(_s) (STREQ (encoding, #_s)) { yaml_encoding = YAML_##_s##_ENCODING; }
56
if (encoding == NULL) { yaml_encoding = YAML_ANY_ENCODING; } else
57
if MENTRY( UTF8 ) else
58
if MENTRY( UTF16LE ) else
59
if MENTRY( UTF16BE ) else
60
{
61
emitter->error++;
62
luaL_addsize (&emitter->errbuff,
63
sprintf (luaL_prepbuffer (&emitter->errbuff),
64
"invalid stream encoding '%s'", encoding));
65
}
66
#undef MENTRY
67
68
if (encoding) free ((void *) encoding);
69
70
if (emitter->error != 0)
71
return 0;
72
73
yaml_stream_start_event_initialize (&event, yaml_encoding);
74
return yaml_emitter_emit (&emitter->emitter, &event);
75
}
76
77
78
/* Emit a STREAM_END event. */
79
static int
80
emit_STREAM_END (lua_State *L, lyaml_emitter *emitter)
81
{
82
yaml_event_t event;
83
yaml_stream_end_event_initialize (&event);
84
return yaml_emitter_emit (&emitter->emitter, &event);
85
}
86
87
88
/* Emit a DOCUMENT_START event. */
89
static int
90
emit_DOCUMENT_START (lua_State *L, lyaml_emitter *emitter)
91
{
92
yaml_event_t event;
93
yaml_version_directive_t version_directive, *Pversion_directive = NULL;
94
yaml_tag_directive_t *tag_directives_start = NULL, *tag_directives_end = NULL;
95
int implicit = 0;
96
97
RAWGET_PUSHTABLE ("version_directive");
98
if (lua_type (L, -1) == LUA_TTABLE)
99
{
100
RAWGETS_INTEGER (version_directive.major, "major");
101
ERROR_IFNIL ("version_directive missing key 'major'");
102
if (emitter->error == 0)
103
{
104
RAWGETS_INTEGER (version_directive.minor, "minor");
105
ERROR_IFNIL ("version_directive missing key 'minor'");
106
}
107
Pversion_directive = &version_directive;
108
}
109
lua_pop (L, 1); /* pop version_directive rawget */
110
111
RAWGET_PUSHTABLE ("tag_directives");
112
if (lua_type (L, -1) == LUA_TTABLE)
113
{
114
size_t bytes = lua_objlen (L, -1) * sizeof (yaml_tag_directive_t);
115
116
tag_directives_start = (yaml_tag_directive_t *) malloc (bytes);
117
tag_directives_end = tag_directives_start;
118
119
lua_pushnil (L); /* first key */
120
while (lua_next (L, -2) != 0)
121
{
122
RAWGETS_STRDUP (tag_directives_end->handle, "handle");
123
ERROR_IFNIL ("tag_directives item missing key 'handle'");
124
lua_pop (L, 1); /* pop handle */
125
126
RAWGETS_STRDUP (tag_directives_end->prefix, "prefix");
127
ERROR_IFNIL ("tag_directives item missing key 'prefix'");
128
lua_pop (L, 1); /* pop prefix */
129
130
tag_directives_end += 1;
131
132
/* pop tag_directives list elewent, leave key for next iteration */
133
lua_pop (L, 1);
134
}
135
}
136
lua_pop (L, 1); /* pop lua_rawget "tag_directives" result */
137
138
RAWGET_BOOLEAN (implicit); lua_pop (L, 1);
139
140
if (emitter->error != 0)
141
return 0;
142
143
yaml_document_start_event_initialize (&event, Pversion_directive,
144
tag_directives_start, tag_directives_end, implicit);
145
return yaml_emitter_emit (&emitter->emitter, &event);
146
}
147
148
149
/* Emit a DOCUMENT_END event. */
150
static int
151
emit_DOCUMENT_END (lua_State *L, lyaml_emitter *emitter)
152
{
153
yaml_event_t event;
154
int implicit = 0;
155
156
RAWGET_BOOLEAN (implicit);
157
158
yaml_document_end_event_initialize (&event, implicit);
159
return yaml_emitter_emit (&emitter->emitter, &event);
160
}
161
162
163
/* Emit a MAPPING_START event. */
164
static int
165
emit_MAPPING_START (lua_State *L, lyaml_emitter *emitter)
166
{
167
yaml_event_t event;
168
yaml_mapping_style_t yaml_style;
169
yaml_char_t *anchor = NULL, *tag = NULL;
170
int implicit = 1;
171
const char *style = NULL;
172
173
RAWGET_STRDUP (style); lua_pop (L, 1);
174
175
#define MENTRY(_s) (STREQ (style, #_s)) { yaml_style = YAML_##_s##_MAPPING_STYLE; }
176
if (style == NULL) { yaml_style = YAML_ANY_MAPPING_STYLE; } else
177
if MENTRY( BLOCK ) else
178
if MENTRY( FLOW ) else
179
{
180
emitter->error++;
181
luaL_addsize (&emitter->errbuff,
182
sprintf (luaL_prepbuffer (&emitter->errbuff),
183
"invalid mapping style '%s'", style));
184
}
185
#undef MENTRY
186
187
if (style) free ((void *) style);
188
189
RAWGET_YAML_CHARP (anchor); lua_pop (L, 1);
190
RAWGET_YAML_CHARP (tag); lua_pop (L, 1);
191
RAWGET_BOOLEAN (implicit); lua_pop (L, 1);
192
193
yaml_mapping_start_event_initialize (&event, anchor, tag, implicit, yaml_style);
194
return yaml_emitter_emit (&emitter->emitter, &event);
195
}
196
197
198
/* Emit a MAPPING_END event. */
199
static int
200
emit_MAPPING_END (lua_State *L, lyaml_emitter *emitter)
201
{
202
yaml_event_t event;
203
yaml_mapping_end_event_initialize (&event);
204
return yaml_emitter_emit (&emitter->emitter, &event);
205
}
206
207
208
/* Emit a SEQUENCE_START event. */
209
static int
210
emit_SEQUENCE_START (lua_State *L, lyaml_emitter *emitter)
211
{
212
yaml_event_t event;
213
yaml_sequence_style_t yaml_style;
214
yaml_char_t *anchor = NULL, *tag = NULL;
215
int implicit = 1;
216
const char *style = NULL;
217
218
RAWGET_STRDUP (style); lua_pop (L, 1);
219
220
#define MENTRY(_s) (STREQ (style, #_s)) { yaml_style = YAML_##_s##_SEQUENCE_STYLE; }
221
if (style == NULL) { yaml_style = YAML_ANY_SEQUENCE_STYLE; } else
222
if MENTRY( BLOCK ) else
223
if MENTRY( FLOW ) else
224
{
225
emitter->error++;
226
luaL_addsize (&emitter->errbuff,
227
sprintf (luaL_prepbuffer (&emitter->errbuff),
228
"invalid sequence style '%s'", style));
229
}
230
#undef MENTRY
231
232
if (style) free ((void *) style);
233
234
RAWGET_YAML_CHARP (anchor); lua_pop (L, 1);
235
RAWGET_YAML_CHARP (tag); lua_pop (L, 1);
236
RAWGET_BOOLEAN (implicit); lua_pop (L, 1);
237
238
yaml_sequence_start_event_initialize (&event, anchor, tag, implicit, yaml_style);
239
return yaml_emitter_emit (&emitter->emitter, &event);
240
}
241
242
243
/* Emit a SEQUENCE_END event. */
244
static int
245
emit_SEQUENCE_END (lua_State *L, lyaml_emitter *emitter)
246
{
247
yaml_event_t event;
248
yaml_sequence_end_event_initialize (&event);
249
return yaml_emitter_emit (&emitter->emitter, &event);
250
}
251
252
253
/* Emit a SCALAR event. */
254
static int
255
emit_SCALAR (lua_State *L, lyaml_emitter *emitter)
256
{
257
yaml_event_t event;
258
yaml_scalar_style_t yaml_style;
259
yaml_char_t *anchor = NULL, *tag = NULL, *value;
260
int length = 0, plain_implicit = 1, quoted_implicit = 1;
261
const char *style = NULL;
262
263
RAWGET_STRDUP (style); lua_pop (L, 1);
264
265
#define MENTRY(_s) (STREQ (style, #_s)) { yaml_style = YAML_##_s##_SCALAR_STYLE; }
266
if (style == NULL) { yaml_style = YAML_ANY_SCALAR_STYLE; } else
267
if MENTRY( PLAIN ) else
268
if MENTRY( SINGLE_QUOTED ) else
269
if MENTRY( DOUBLE_QUOTED ) else
270
if MENTRY( LITERAL ) else
271
if MENTRY( FOLDED ) else
272
{
273
emitter->error++;
274
luaL_addsize (&emitter->errbuff,
275
sprintf (luaL_prepbuffer (&emitter->errbuff),
276
"invalid scalar style '%s'", style));
277
}
278
#undef MENTRY
279
280
if (style) free ((void *) style);
281
282
RAWGET_YAML_CHARP (anchor); lua_pop (L, 1);
283
RAWGET_YAML_CHARP (tag); lua_pop (L, 1);
284
RAWGET_YAML_CHARP (value); length = lua_objlen (L, -1); lua_pop (L, 1);
285
RAWGET_BOOLEAN (plain_implicit);
286
RAWGET_BOOLEAN (quoted_implicit);
287
288
yaml_scalar_event_initialize (&event, anchor, tag, value, length,
289
plain_implicit, quoted_implicit, yaml_style);
290
return yaml_emitter_emit (&emitter->emitter, &event);
291
}
292
293
294
/* Emit an ALIAS event. */
295
static int
296
emit_ALIAS (lua_State *L, lyaml_emitter *emitter)
297
{
298
yaml_event_t event;
299
yaml_char_t *anchor;
300
301
RAWGET_YAML_CHARP (anchor);
302
303
yaml_alias_event_initialize (&event, anchor);
304
return yaml_emitter_emit (&emitter->emitter, &event);
305
}
306
307
308
static int
309
emit (lua_State *L)
310
{
311
lyaml_emitter *emitter;
312
int yaml_ok = 0;
313
int finalize = 0;
314
315
luaL_argcheck (L, lua_istable (L, 1), 1, "expected table");
316
317
emitter = (lyaml_emitter *) lua_touserdata (L, lua_upvalueindex (1));
318
319
{
320
const char *type;
321
322
RAWGET_STRDUP (type); lua_pop (L, 1);
323
324
if (type == NULL)
325
{
326
emitter->error++;
327
luaL_addstring (&emitter->errbuff, "no type field in event table");
328
}
329
#define MENTRY(_s) (STREQ (type, #_s)) { yaml_ok = emit_##_s (L, emitter); }
330
/* Minimize comparisons by putting more common types earlier. */
331
else if MENTRY( SCALAR )
332
else if MENTRY( MAPPING_START )
333
else if MENTRY( MAPPING_END )
334
else if MENTRY( SEQUENCE_START )
335
else if MENTRY( SEQUENCE_END )
336
else if MENTRY( DOCUMENT_START )
337
else if MENTRY( DOCUMENT_END )
338
else if MENTRY( STREAM_START )
339
else if MENTRY( STREAM_END )
340
else if MENTRY( ALIAS )
341
#undef MENTRY
342
else
343
{
344
emitter->error++;
345
luaL_addsize (&emitter->errbuff,
346
sprintf (luaL_prepbuffer (&emitter->errbuff),
347
"invalid event type '%s'", type));
348
}
349
350
/* If the stream has finished, finalize the YAML output. */
351
if (type && STREQ (type, "STREAM_END"))
352
finalize = 1;
353
354
if (type) free ((void *) type);
355
}
356
357
/* Copy any yaml_emitter_t errors into the error buffer. */
358
if (!emitter->error && !yaml_ok)
359
{
360
if (emitter->emitter.problem)
361
luaL_addstring (&emitter->errbuff, emitter->emitter.problem);
362
else
363
luaL_addstring (&emitter->errbuff, "LibYAML call failed");
364
emitter->error++;
365
}
366
367
/* Report errors back to the caller as `false, "error message"`. */
368
if (emitter->error != 0)
369
{
370
assert (emitter->error == 1); /* bail on uncaught additional errors */
371
lua_pushboolean (L, 0);
372
luaL_pushresult (&emitter->errbuff);
373
lua_xmove (emitter->errL, L, 1);
374
return 2;
375
}
376
377
/* Return `true, "YAML string"` after accepting a STREAM_END event. */
378
if (finalize)
379
{
380
lua_pushboolean (L, 1);
381
luaL_pushresult (&emitter->yamlbuff);
382
lua_xmove (emitter->outputL, L, 1);
383
return 2;
384
}
385
386
/* Otherwise, just report success to the caller as `true`. */
387
lua_pushboolean (L, 1);
388
return 1;
389
}
390
391
392
static int
393
append_output (void *arg, unsigned char *buff, size_t len)
394
{
395
lyaml_emitter *emitter = (lyaml_emitter *) arg;
396
luaL_addlstring (&emitter->yamlbuff, (char *) buff, len);
397
return 1;
398
}
399
400
401
static int
402
emitter_gc (lua_State *L)
403
{
404
lyaml_emitter *emitter = (lyaml_emitter *) lua_touserdata (L, 1);
405
406
if (emitter)
407
yaml_emitter_delete (&emitter->emitter);
408
409
return 0;
410
}
411
412
413
int
414
Pemitter (lua_State *L)
415
{
416
lyaml_emitter *emitter;
417
418
lua_newtable (L); /* object table */
419
420
/* Create a user datum to store the emitter. */
421
emitter = (lyaml_emitter *) lua_newuserdata (L, sizeof (*emitter));
422
emitter->error = 0;
423
424
/* Initialize the emitter. */
425
if (!yaml_emitter_initialize (&emitter->emitter))
426
{
427
if (!emitter->emitter.problem)
428
emitter->emitter.problem = "cannot initialize emitter";
429
return luaL_error (L, "%s", emitter->emitter.problem);
430
}
431
yaml_emitter_set_unicode (&emitter->emitter, 1);
432
yaml_emitter_set_width (&emitter->emitter, 2);
433
yaml_emitter_set_output (&emitter->emitter, &append_output, emitter);
434
435
/* Set it's metatable, and ensure it is garbage collected properly. */
436
luaL_newmetatable (L, "lyaml.emitter");
437
lua_pushcfunction (L, emitter_gc);
438
lua_setfield (L, -2, "__gc");
439
lua_setmetatable (L, -2);
440
441
/* Set the emit method of object as a closure over the user datum, and
442
return the whole object. */
443
lua_pushcclosure (L, emit, 1);
444
lua_setfield (L, -2, "emit");
445
446
/* Set up a separate thread to collect error messages; save the thread
447
in the returned table so that it's not garbage collected when the
448
function call stack for Pemitter is cleaned up. */
449
emitter->errL = lua_newthread (L);
450
luaL_buffinit (emitter->errL, &emitter->errbuff);
451
lua_setfield (L, -2, "errthread");
452
453
/* Create a thread for the YAML buffer. */
454
emitter->outputL = lua_newthread (L);
455
luaL_buffinit (emitter->outputL, &emitter->yamlbuff);
456
lua_setfield (L, -2, "outputthread");
457
458
return 1;
459
}
460
461