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