#include <assert.h>
#include "lyaml.h"
typedef struct {
yaml_emitter_t emitter;
lua_State *outputL;
luaL_Buffer yamlbuff;
lua_State *errL;
luaL_Buffer errbuff;
int error;
} lyaml_emitter;
static int
emit_STREAM_START (lua_State *L, lyaml_emitter *emitter)
{
yaml_event_t event;
yaml_encoding_t yaml_encoding;
const char *encoding = NULL;
RAWGET_STRDUP (encoding); lua_pop (L, 1);
#define MENTRY(_s) (STREQ (encoding, #_s)) { yaml_encoding = YAML_##_s##_ENCODING; }
if (encoding == NULL) { yaml_encoding = YAML_ANY_ENCODING; } else
if MENTRY( UTF8 ) else
if MENTRY( UTF16LE ) else
if MENTRY( UTF16BE ) else
{
emitter->error++;
luaL_addsize (&emitter->errbuff,
sprintf (luaL_prepbuffer (&emitter->errbuff),
"invalid stream encoding '%s'", encoding));
}
#undef MENTRY
if (encoding) free ((void *) encoding);
if (emitter->error != 0)
return 0;
yaml_stream_start_event_initialize (&event, yaml_encoding);
return yaml_emitter_emit (&emitter->emitter, &event);
}
static int
emit_STREAM_END (lua_State *L, lyaml_emitter *emitter)
{
yaml_event_t event;
yaml_stream_end_event_initialize (&event);
return yaml_emitter_emit (&emitter->emitter, &event);
}
static int
emit_DOCUMENT_START (lua_State *L, lyaml_emitter *emitter)
{
yaml_event_t event;
yaml_version_directive_t version_directive, *Pversion_directive = NULL;
yaml_tag_directive_t *tag_directives_start = NULL, *tag_directives_end = NULL;
int implicit = 0;
RAWGET_PUSHTABLE ("version_directive");
if (lua_type (L, -1) == LUA_TTABLE)
{
RAWGETS_INTEGER (version_directive.major, "major");
ERROR_IFNIL ("version_directive missing key 'major'");
if (emitter->error == 0)
{
RAWGETS_INTEGER (version_directive.minor, "minor");
ERROR_IFNIL ("version_directive missing key 'minor'");
}
Pversion_directive = &version_directive;
}
lua_pop (L, 1);
RAWGET_PUSHTABLE ("tag_directives");
if (lua_type (L, -1) == LUA_TTABLE)
{
size_t bytes = lua_objlen (L, -1) * sizeof (yaml_tag_directive_t);
tag_directives_start = (yaml_tag_directive_t *) malloc (bytes);
tag_directives_end = tag_directives_start;
lua_pushnil (L);
while (lua_next (L, -2) != 0)
{
RAWGETS_STRDUP (tag_directives_end->handle, "handle");
ERROR_IFNIL ("tag_directives item missing key 'handle'");
lua_pop (L, 1);
RAWGETS_STRDUP (tag_directives_end->prefix, "prefix");
ERROR_IFNIL ("tag_directives item missing key 'prefix'");
lua_pop (L, 1);
tag_directives_end += 1;
lua_pop (L, 1);
}
}
lua_pop (L, 1);
RAWGET_BOOLEAN (implicit); lua_pop (L, 1);
if (emitter->error != 0)
return 0;
yaml_document_start_event_initialize (&event, Pversion_directive,
tag_directives_start, tag_directives_end, implicit);
return yaml_emitter_emit (&emitter->emitter, &event);
}
static int
emit_DOCUMENT_END (lua_State *L, lyaml_emitter *emitter)
{
yaml_event_t event;
int implicit = 0;
RAWGET_BOOLEAN (implicit);
yaml_document_end_event_initialize (&event, implicit);
return yaml_emitter_emit (&emitter->emitter, &event);
}
static int
emit_MAPPING_START (lua_State *L, lyaml_emitter *emitter)
{
yaml_event_t event;
yaml_mapping_style_t yaml_style;
yaml_char_t *anchor = NULL, *tag = NULL;
int implicit = 1;
const char *style = NULL;
RAWGET_STRDUP (style); lua_pop (L, 1);
#define MENTRY(_s) (STREQ (style, #_s)) { yaml_style = YAML_##_s##_MAPPING_STYLE; }
if (style == NULL) { yaml_style = YAML_ANY_MAPPING_STYLE; } else
if MENTRY( BLOCK ) else
if MENTRY( FLOW ) else
{
emitter->error++;
luaL_addsize (&emitter->errbuff,
sprintf (luaL_prepbuffer (&emitter->errbuff),
"invalid mapping style '%s'", style));
}
#undef MENTRY
if (style) free ((void *) style);
RAWGET_YAML_CHARP (anchor); lua_pop (L, 1);
RAWGET_YAML_CHARP (tag); lua_pop (L, 1);
RAWGET_BOOLEAN (implicit); lua_pop (L, 1);
yaml_mapping_start_event_initialize (&event, anchor, tag, implicit, yaml_style);
return yaml_emitter_emit (&emitter->emitter, &event);
}
static int
emit_MAPPING_END (lua_State *L, lyaml_emitter *emitter)
{
yaml_event_t event;
yaml_mapping_end_event_initialize (&event);
return yaml_emitter_emit (&emitter->emitter, &event);
}
static int
emit_SEQUENCE_START (lua_State *L, lyaml_emitter *emitter)
{
yaml_event_t event;
yaml_sequence_style_t yaml_style;
yaml_char_t *anchor = NULL, *tag = NULL;
int implicit = 1;
const char *style = NULL;
RAWGET_STRDUP (style); lua_pop (L, 1);
#define MENTRY(_s) (STREQ (style, #_s)) { yaml_style = YAML_##_s##_SEQUENCE_STYLE; }
if (style == NULL) { yaml_style = YAML_ANY_SEQUENCE_STYLE; } else
if MENTRY( BLOCK ) else
if MENTRY( FLOW ) else
{
emitter->error++;
luaL_addsize (&emitter->errbuff,
sprintf (luaL_prepbuffer (&emitter->errbuff),
"invalid sequence style '%s'", style));
}
#undef MENTRY
if (style) free ((void *) style);
RAWGET_YAML_CHARP (anchor); lua_pop (L, 1);
RAWGET_YAML_CHARP (tag); lua_pop (L, 1);
RAWGET_BOOLEAN (implicit); lua_pop (L, 1);
yaml_sequence_start_event_initialize (&event, anchor, tag, implicit, yaml_style);
return yaml_emitter_emit (&emitter->emitter, &event);
}
static int
emit_SEQUENCE_END (lua_State *L, lyaml_emitter *emitter)
{
yaml_event_t event;
yaml_sequence_end_event_initialize (&event);
return yaml_emitter_emit (&emitter->emitter, &event);
}
static int
emit_SCALAR (lua_State *L, lyaml_emitter *emitter)
{
yaml_event_t event;
yaml_scalar_style_t yaml_style;
yaml_char_t *anchor = NULL, *tag = NULL, *value;
int length = 0, plain_implicit = 1, quoted_implicit = 1;
const char *style = NULL;
RAWGET_STRDUP (style); lua_pop (L, 1);
#define MENTRY(_s) (STREQ (style, #_s)) { yaml_style = YAML_##_s##_SCALAR_STYLE; }
if (style == NULL) { yaml_style = YAML_ANY_SCALAR_STYLE; } else
if MENTRY( PLAIN ) else
if MENTRY( SINGLE_QUOTED ) else
if MENTRY( DOUBLE_QUOTED ) else
if MENTRY( LITERAL ) else
if MENTRY( FOLDED ) else
{
emitter->error++;
luaL_addsize (&emitter->errbuff,
sprintf (luaL_prepbuffer (&emitter->errbuff),
"invalid scalar style '%s'", style));
}
#undef MENTRY
if (style) free ((void *) style);
RAWGET_YAML_CHARP (anchor); lua_pop (L, 1);
RAWGET_YAML_CHARP (tag); lua_pop (L, 1);
RAWGET_YAML_CHARP (value); length = lua_objlen (L, -1); lua_pop (L, 1);
RAWGET_BOOLEAN (plain_implicit);
RAWGET_BOOLEAN (quoted_implicit);
yaml_scalar_event_initialize (&event, anchor, tag, value, length,
plain_implicit, quoted_implicit, yaml_style);
return yaml_emitter_emit (&emitter->emitter, &event);
}
static int
emit_ALIAS (lua_State *L, lyaml_emitter *emitter)
{
yaml_event_t event;
yaml_char_t *anchor;
RAWGET_YAML_CHARP (anchor);
yaml_alias_event_initialize (&event, anchor);
return yaml_emitter_emit (&emitter->emitter, &event);
}
static int
emit (lua_State *L)
{
lyaml_emitter *emitter;
int yaml_ok = 0;
int finalize = 0;
luaL_argcheck (L, lua_istable (L, 1), 1, "expected table");
emitter = (lyaml_emitter *) lua_touserdata (L, lua_upvalueindex (1));
{
const char *type;
RAWGET_STRDUP (type); lua_pop (L, 1);
if (type == NULL)
{
emitter->error++;
luaL_addstring (&emitter->errbuff, "no type field in event table");
}
#define MENTRY(_s) (STREQ (type, #_s)) { yaml_ok = emit_##_s (L, emitter); }
else if MENTRY( SCALAR )
else if MENTRY( MAPPING_START )
else if MENTRY( MAPPING_END )
else if MENTRY( SEQUENCE_START )
else if MENTRY( SEQUENCE_END )
else if MENTRY( DOCUMENT_START )
else if MENTRY( DOCUMENT_END )
else if MENTRY( STREAM_START )
else if MENTRY( STREAM_END )
else if MENTRY( ALIAS )
#undef MENTRY
else
{
emitter->error++;
luaL_addsize (&emitter->errbuff,
sprintf (luaL_prepbuffer (&emitter->errbuff),
"invalid event type '%s'", type));
}
if (type && STREQ (type, "STREAM_END"))
finalize = 1;
if (type) free ((void *) type);
}
if (!emitter->error && !yaml_ok)
{
if (emitter->emitter.problem)
luaL_addstring (&emitter->errbuff, emitter->emitter.problem);
else
luaL_addstring (&emitter->errbuff, "LibYAML call failed");
emitter->error++;
}
if (emitter->error != 0)
{
assert (emitter->error == 1);
lua_pushboolean (L, 0);
luaL_pushresult (&emitter->errbuff);
lua_xmove (emitter->errL, L, 1);
return 2;
}
if (finalize)
{
lua_pushboolean (L, 1);
luaL_pushresult (&emitter->yamlbuff);
lua_xmove (emitter->outputL, L, 1);
return 2;
}
lua_pushboolean (L, 1);
return 1;
}
static int
append_output (void *arg, unsigned char *buff, size_t len)
{
lyaml_emitter *emitter = (lyaml_emitter *) arg;
luaL_addlstring (&emitter->yamlbuff, (char *) buff, len);
return 1;
}
static int
emitter_gc (lua_State *L)
{
lyaml_emitter *emitter = (lyaml_emitter *) lua_touserdata (L, 1);
if (emitter)
yaml_emitter_delete (&emitter->emitter);
return 0;
}
int
Pemitter (lua_State *L)
{
lyaml_emitter *emitter;
lua_newtable (L);
emitter = (lyaml_emitter *) lua_newuserdata (L, sizeof (*emitter));
emitter->error = 0;
if (!yaml_emitter_initialize (&emitter->emitter))
{
if (!emitter->emitter.problem)
emitter->emitter.problem = "cannot initialize emitter";
return luaL_error (L, "%s", emitter->emitter.problem);
}
yaml_emitter_set_unicode (&emitter->emitter, 1);
yaml_emitter_set_width (&emitter->emitter, 2);
yaml_emitter_set_output (&emitter->emitter, &append_output, emitter);
luaL_newmetatable (L, "lyaml.emitter");
lua_pushcfunction (L, emitter_gc);
lua_setfield (L, -2, "__gc");
lua_setmetatable (L, -2);
lua_pushcclosure (L, emit, 1);
lua_setfield (L, -2, "emit");
emitter->errL = lua_newthread (L);
luaL_buffinit (emitter->errL, &emitter->errbuff);
lua_setfield (L, -2, "errthread");
emitter->outputL = lua_newthread (L);
luaL_buffinit (emitter->outputL, &emitter->yamlbuff);
lua_setfield (L, -2, "outputthread");
return 1;
}