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