summaryrefslogtreecommitdiff
path: root/src/mod_irc/iconv_erl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_irc/iconv_erl.c')
-rw-r--r--src/mod_irc/iconv_erl.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/mod_irc/iconv_erl.c b/src/mod_irc/iconv_erl.c
new file mode 100644
index 00000000..4cca2ece
--- /dev/null
+++ b/src/mod_irc/iconv_erl.c
@@ -0,0 +1,115 @@
+/* $Id$ */
+
+#include <stdio.h>
+#include <erl_driver.h>
+#include <ei.h>
+#include <iconv.h>
+
+typedef struct {
+ ErlDrvPort port;
+ iconv_t cd;
+} iconv_data;
+
+
+static ErlDrvData iconv_erl_start(ErlDrvPort port, char *buff)
+{
+ iconv_data* d = (iconv_data*)driver_alloc(sizeof(iconv_data));
+ d->port = port;
+ d->cd = NULL;
+
+ set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
+
+ return (ErlDrvData)d;
+}
+
+static void iconv_erl_stop(ErlDrvData handle)
+{
+ driver_free((char*)handle);
+}
+
+static int iconv_erl_control(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, int len,
+ char **rbuf, int rlen)
+{
+ int i;
+ int size;
+ int index = 0;
+ int avail;
+ int inleft, outleft;
+ ErlDrvBinary *b;
+ char *from, *to, *string, *stmp, *rstring, *rtmp;
+ iconv_t cd;
+
+ ei_decode_version(buf, &index, &i);
+ ei_decode_tuple_header(buf, &index, &i);
+ ei_get_type(buf, &index, &i, &size);
+ from = malloc(size + 1);
+ ei_decode_string(buf, &index, from);
+
+ ei_get_type(buf, &index, &i, &size);
+ to = malloc(size + 1);
+ ei_decode_string(buf, &index, to);
+
+ ei_get_type(buf, &index, &i, &size);
+ stmp = string = malloc(size + 1);
+ ei_decode_string(buf, &index, string);
+
+ cd = iconv_open(to, from);
+ // TODO: check result
+ /*
+ if(cd == (iconv_t) -1)
+ {
+ perror ("iconv_open");
+ }
+ else
+ {
+ printf("iconv_open from=%s, to=%s OK\r\n", from, to);
+ printf("string=%s size=%d\r\n", string, size);
+ }
+ */
+
+ outleft = avail = 4*size;
+ inleft = size;
+ rtmp = rstring = malloc(avail);
+ iconv(cd, &stmp, &inleft, &rtmp, &outleft);
+
+ size = rtmp - rstring;
+
+ //printf("size=%d, res=%s\r\n", size, rstring);
+
+ *rbuf = (char*)(b = driver_alloc_binary(size));
+ memcpy(b->orig_bytes, rstring, size);
+
+ free(from);
+ free(to);
+ free(string);
+ free(rstring);
+ iconv_close(cd);
+
+ return size;
+}
+
+
+
+ErlDrvEntry iconv_driver_entry = {
+ NULL, /* F_PTR init, N/A */
+ iconv_erl_start, /* L_PTR start, called when port is opened */
+ iconv_erl_stop, /* F_PTR stop, called when port is closed */
+ NULL, /* 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 */
+ "iconv_erl", /* char *driver_name, the argument to open_port */
+ NULL, /* F_PTR finish, called when unloaded */
+ NULL, /* handle */
+ iconv_erl_control, /* F_PTR control, port_command callback */
+ NULL, /* F_PTR timeout, reserved */
+ NULL /* F_PTR outputv, reserved */
+};
+
+DRIVER_INIT(iconv_erl) /* must match name in driver_entry */
+{
+ return &iconv_driver_entry;
+}
+
+