summaryrefslogtreecommitdiff
path: root/src/expat_erl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/expat_erl.c')
-rw-r--r--src/expat_erl.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/src/expat_erl.c b/src/expat_erl.c
new file mode 100644
index 00000000..b330eca1
--- /dev/null
+++ b/src/expat_erl.c
@@ -0,0 +1,155 @@
+/* $Id$ */
+
+#include <stdio.h>
+#include <erl_driver.h>
+#include <ei.h>
+#include <expat.h>
+
+typedef struct {
+ ErlDrvPort port;
+ XML_Parser parser;
+} expat_data;
+
+
+void *erlXML_StartElementHandler(expat_data *d,
+ const XML_Char *name,
+ const XML_Char **atts)
+{
+ int i;
+ ei_x_buff buf;
+
+ ei_x_new_with_version(&buf);
+ ei_x_encode_tuple_header(&buf, 2);
+ ei_x_encode_atom(&buf, "xmlstart");
+ ei_x_encode_tuple_header(&buf, 2);
+ ei_x_encode_string(&buf, name);
+
+ for (i = 0; atts[i]; i += 2) {}
+
+ ei_x_encode_list_header(&buf, i/2);
+
+ for (i = 0; atts[i]; i += 2)
+ {
+ ei_x_encode_tuple_header(&buf, 2);
+ ei_x_encode_string(&buf, atts[i]);
+ ei_x_encode_string(&buf, atts[i+1]);
+ }
+
+ ei_x_encode_empty_list(&buf);
+
+ driver_output(d->port, buf.buff, buf.index);
+ ei_x_free(&buf);
+ return NULL;
+}
+
+void *erlXML_EndElementHandler(expat_data *d,
+ const XML_Char *name)
+{
+ ei_x_buff buf;
+
+ ei_x_new_with_version(&buf);
+ ei_x_encode_tuple_header(&buf, 2);
+ ei_x_encode_atom(&buf, "xmlend");
+ ei_x_encode_string(&buf, name);
+
+ driver_output(d->port, buf.buff, buf.index);
+ ei_x_free(&buf);
+ return NULL;
+}
+
+void *erlXML_CharacterDataHandler(expat_data *d,
+ const XML_Char *s,
+ int len)
+{
+ ei_x_buff buf;
+
+ ei_x_new_with_version(&buf);
+ ei_x_encode_tuple_header(&buf, 2);
+ ei_x_encode_atom(&buf, "xmlcdata");
+ ei_x_encode_string_len(&buf, s, len);
+
+ driver_output(d->port, buf.buff, buf.index);
+ ei_x_free(&buf);
+ return NULL;
+}
+
+
+static ErlDrvData expat_erl_start(ErlDrvPort port, char *buff)
+{
+ expat_data* d = (expat_data*)driver_alloc(sizeof(expat_data));
+ d->port = port;
+ d->parser = XML_ParserCreate("UTF-8");
+ XML_SetUserData(d->parser, d);
+
+ XML_SetStartElementHandler(
+ d->parser, (XML_StartElementHandler)erlXML_StartElementHandler);
+ XML_SetEndElementHandler(
+ d->parser, (XML_EndElementHandler)erlXML_EndElementHandler);
+ XML_SetCharacterDataHandler(
+ d->parser, (XML_CharacterDataHandler)erlXML_CharacterDataHandler);
+
+
+ return (ErlDrvData)d;
+}
+
+static void expat_erl_stop(ErlDrvData handle)
+{
+ /* TODO: free parser */
+ driver_free((char*)handle);
+}
+
+static void expat_erl_output(ErlDrvData handle, char *buff, int bufflen)
+{
+ expat_data* d = (expat_data*)handle;
+ int res, errcode;
+ char *errstring;
+ ei_x_buff buf;
+
+ /*buff[bufflen] = 0;
+
+ fprintf(stderr, "RCVD: '%s'\n", buff);
+ fflush(stderr);*/
+
+ res = XML_Parse(d->parser, buff, bufflen, 0);
+
+ if(!res)
+ {
+ errcode = XML_GetErrorCode(d->parser);
+ errstring = (char *)XML_ErrorString(errcode);
+
+ ei_x_new_with_version(&buf);
+ ei_x_encode_tuple_header(&buf, 2);
+ ei_x_encode_atom(&buf, "xmlerror");
+ ei_x_encode_tuple_header(&buf, 2);
+ ei_x_encode_long(&buf, errcode);
+ ei_x_encode_string(&buf, errstring);
+
+ driver_output(d->port, buf.buff, buf.index);
+ ei_x_free(&buf);
+ }
+
+ //driver_output(d->port, &res, 1);
+}
+
+
+
+ErlDrvEntry expat_driver_entry = {
+ NULL, /* F_PTR init, N/A */
+ expat_erl_start, /* L_PTR start, called when port is opened */
+ expat_erl_stop, /* F_PTR stop, called when port is closed */
+ expat_erl_output, /* F_PTR output, called when erlang has sent */
+ NULL, /* F_PTR ready_input, called when input descriptor ready */
+ NULL, /* F_PTR ready_output, called when output descriptor ready */
+ "expat_erl", /* char *driver_name, the argument to open_port */
+ NULL, /* F_PTR finish, called when unloaded */
+ NULL, /* F_PTR control, port_command callback */
+ NULL, /* F_PTR timeout, reserved */
+ NULL /* F_PTR outputv, reserved */
+};
+
+DRIVER_INIT(expat_erl) /* must match name in driver_entry */
+{
+ return &expat_driver_entry;
+}
+
+