summaryrefslogtreecommitdiff
path: root/modules/yaml/yaml.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/yaml/yaml.c')
-rw-r--r--modules/yaml/yaml.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/modules/yaml/yaml.c b/modules/yaml/yaml.c
new file mode 100644
index 00000000000..3ff133476ee
--- /dev/null
+++ b/modules/yaml/yaml.c
@@ -0,0 +1,232 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <yaml.h>
+
+
+#include <config.h>
+#include <lisp.h>
+
+#include <character.h> /* buffer.h needs it */
+#include <buffer.h>
+
+int plugin_is_GPL_compatible;
+static Lisp_Object Qyaml;
+
+typedef unsigned char uchar;
+
+struct context
+{
+ yaml_parser_t p;
+ int error;
+ Lisp_Object anchors; /* hashtable mapping alias to values */
+};
+
+static Lisp_Object parse_scalar (struct context *ctx, yaml_event_t *e);
+static Lisp_Object parse_sequence (struct context *ctx, yaml_event_t *e);
+static Lisp_Object parse_mapping (struct context *ctx, yaml_event_t *e);
+
+static Lisp_Object
+parse_element (struct context *ctx)
+{
+ Lisp_Object res = Qnil;
+ yaml_event_t e;
+
+ redo:
+ yaml_parser_parse (&ctx->p, &e);
+ const char *s = (char*)e.data.alias.anchor;
+
+ switch (e.type)
+ {
+ case YAML_STREAM_START_EVENT:
+ /* a stream is a sequence of documents */
+ res = parse_sequence (ctx, &e);
+ break;
+
+ case YAML_DOCUMENT_START_EVENT:
+ case YAML_DOCUMENT_END_EVENT:
+ /* keep reading */
+ yaml_event_delete (&e);
+ goto redo;
+
+ case YAML_ALIAS_EVENT:
+ res = Fgethash (make_string (s, strlen (s)), ctx->anchors, Qnil);
+ break;
+
+ case YAML_SCALAR_EVENT:
+ res = parse_scalar (ctx, &e);
+ if (s)
+ Fputhash (make_string (s, strlen (s)), res, ctx->anchors);
+ break;
+
+ case YAML_SEQUENCE_START_EVENT:
+ res = parse_sequence (ctx, &e);
+ if (s)
+ Fputhash (make_string (s, strlen (s)), res, ctx->anchors);
+ break;
+
+ case YAML_MAPPING_START_EVENT:
+ res = parse_mapping (ctx, &e);
+ if (s)
+ Fputhash (make_string (s, strlen (s)), res, ctx->anchors);
+ break;
+
+ case YAML_NO_EVENT:
+ case YAML_MAPPING_END_EVENT:
+ case YAML_SEQUENCE_END_EVENT:
+ case YAML_STREAM_END_EVENT:
+ res = Qnil;
+ break;
+ }
+
+ yaml_event_delete (&e);
+ return res;
+}
+
+static Lisp_Object
+parse_scalar (struct context *ctx, yaml_event_t *e)
+{
+ return make_string ((char*)e->data.scalar.value, e->data.scalar.length);
+}
+
+static Lisp_Object
+parse_sequence (struct context *ctx, yaml_event_t *e)
+{
+ /* always >= 1 elements in sequence */
+ Lisp_Object cons = Fcons (parse_element (ctx), Qnil);
+ Lisp_Object res = cons;
+
+ while (1)
+ {
+ Lisp_Object e = parse_element (ctx);
+
+ if (NILP (e))
+ break;
+
+ XSETCDR (cons, Fcons(e, Qnil));
+ cons = XCDR (cons);
+ }
+
+ return res;
+}
+
+static Lisp_Object
+parse_mapping (struct context *ctx, yaml_event_t *e)
+{
+ Lisp_Object args[2];
+ args[0] = QCtest;
+ args[1] = Qequal;
+ Lisp_Object res = Fmake_hash_table (2, args);
+
+ while (1)
+ {
+ Lisp_Object key = parse_element (ctx);
+
+ if (NILP (key))
+ break;
+
+ Lisp_Object val = parse_element (ctx);
+
+ Fputhash (key, val, res);
+ }
+
+ return res;
+}
+
+static void
+context_init (struct context *ctx)
+{
+ memset (ctx, 0, sizeof (*ctx));
+ Lisp_Object args[2];
+ args[0] = QCtest;
+ args[1] = Qequal;
+ ctx->anchors = Fmake_hash_table (2, args);
+}
+
+EXFUN (Fyaml_parse_string, 1);
+DEFUN ("yaml-parse-string", Fyaml_parse_string, Syaml_parse_string, 1, 1, 0,
+ doc: "Parse STRING as yaml.")
+ (Lisp_Object string)
+{
+ struct context ctx;
+ Lisp_Object res = Qnil;
+
+ context_init (&ctx);
+
+ yaml_parser_initialize (&ctx.p);
+ yaml_parser_set_input_string (&ctx.p, SDATA (string), SBYTES (string));
+ res = parse_element (&ctx);
+ yaml_parser_delete (&ctx.p);
+
+ return res;
+}
+
+
+EXFUN (Fyaml_parse_buffer, 0);
+DEFUN ("yaml-parse-buffer", Fyaml_parse_buffer, Syaml_parse_buffer, 0, 0, 0,
+ doc: "Parse current buffer as yaml.")
+ (void)
+{
+ struct context ctx;
+ Lisp_Object res = Qnil;
+
+ context_init (&ctx);
+
+ yaml_parser_initialize (&ctx.p);
+ yaml_parser_set_input_string (&ctx.p, BYTE_POS_ADDR (BEGV_BYTE), ZV_BYTE - BEGV_BYTE);
+ res = parse_element (&ctx);
+ yaml_parser_delete (&ctx.p);
+
+ return res;
+}
+
+
+EXFUN (Fyaml_parse_file, 1);
+DEFUN ("yaml-parse-file", Fyaml_parse_file, Syaml_parse_file, 1, 1, 0,
+ doc: "Parse FILE as yaml.")
+ (Lisp_Object file)
+{
+ struct gcpro gcpro1;
+ struct context ctx;
+
+ context_init (&ctx);
+
+ int r;
+ FILE *fh;
+ Lisp_Object res = Qnil;
+
+ fh = fopen((char*)SDATA (file), "r");
+
+ if (!fh)
+ goto out;
+
+ r = yaml_parser_initialize (&ctx.p);
+
+ if (!r)
+ goto out_close;
+
+ yaml_parser_set_input_file (&ctx.p, fh);
+
+ GCPRO1 (ctx.anchors);
+ res = parse_element (&ctx);
+ UNGCPRO;
+
+ yaml_parser_delete (&ctx.p);
+
+ out_close:
+ fclose (fh);
+
+ out:
+ return res;
+}
+
+void init ()
+{
+ DEFSYM (Qyaml, "yaml");
+
+ defsubr (&Syaml_parse_file);
+ defsubr (&Syaml_parse_string);
+ defsubr (&Syaml_parse_buffer);
+
+ Fprovide (Qyaml, Qnil);
+}