From: Sergei Golovan <sgolovan(a)gmail.com>
Replace the use of liberl_interface, which is removed in Erlang 23,
by libei. The implementation uses the ei_decode_iodata() function
which has been introduces only for Erlang 23, so it doesnt work with
earlier Erlang versions.
---
erlang/Makefile.am | 1 -
erlang/main.c | 312 +++++++++++++++++++++++++-------------------
generator/erlang.ml | 239 ++++++++++++++++-----------------
3 files changed, 295 insertions(+), 257 deletions(-)
diff --git a/erlang/Makefile.am b/erlang/Makefile.am
index 19b0e973e..3da3f9145 100644
--- a/erlang/Makefile.am
+++ b/erlang/Makefile.am
@@ -90,7 +90,6 @@ erl_guestfs_CFLAGS = \
$(WARN_CFLAGS) $(WERROR_CFLAGS)
erl_guestfs_LDADD = \
- $(ERLANG_LIB_DIR_erl_interface)/lib/liberl_interface.a \
$(ERLANG_LIB_DIR_erl_interface)/lib/libei.a \
-lpthread \
$(top_builddir)/common/utils/libutils.la \
diff --git a/erlang/main.c b/erlang/main.c
index b9b3dced9..a56ee1fab 100644
--- a/erlang/main.c
+++ b/erlang/main.c
@@ -25,11 +25,7 @@
#include <errno.h>
#include <arpa/inet.h>
-#include <erl_interface.h>
-/* We should switch over to using
- #include <ei.h>
-instead of erl_interface.
-*/
+#include <ei.h>
#include "error.h"
#include "full-read.h"
@@ -38,36 +34,25 @@ instead of erl_interface.
#include "guestfs.h"
#include "guestfs-utils.h"
+#include "actions.h"
+
guestfs_h *g;
-extern ETERM *dispatch (ETERM *message);
-extern int atom_equals (ETERM *atom, const char *name);
-extern ETERM *make_error (const char *funname);
-extern ETERM *unknown_optarg (const char *funname, ETERM *optargname);
-extern ETERM *unknown_function (ETERM *fun);
-extern ETERM *make_string_list (char **r);
-extern ETERM *make_table (char **r);
-extern ETERM *make_bool (int r);
-extern char **get_string_list (ETERM *term);
-extern int get_bool (ETERM *term);
-extern int get_int (ETERM *term);
-extern int64_t get_int64 (ETERM *term);
-
/* This stops things getting out of hand, but also lets us detect
* protocol problems quickly.
*/
#define MAX_MESSAGE_SIZE (32*1024*1024)
-static unsigned char *read_message (void);
-static void write_reply (ETERM *);
+static char *read_message (void);
+static void write_reply (ei_x_buff *);
int
main (void)
{
- unsigned char *buf;
- ETERM *ret, *message;
-
- erl_init (NULL, 0);
+ char *buff;
+ int index;
+ int version;
+ ei_x_buff reply;
/* This process has a single libguestfs handle. If the Erlang
* system creates more than one handle, then more than one of these
@@ -79,15 +64,20 @@ main (void)
guestfs_set_error_handler (g, NULL, NULL);
- while ((buf = read_message ()) != NULL) {
- message = erl_decode (buf);
- free (buf);
+ while ((buff = read_message ()) != NULL) {
+ if (ei_x_new_with_version (&reply) != 0)
+ error (EXIT_FAILURE, 0, "could not allocate reply buffer");
- ret = dispatch (message);
- erl_free_term (message);
+ index = 0;
+ if (ei_decode_version (buff, &index, &version) != 0)
+ error (EXIT_FAILURE, 0, "could not interpret the input message");
- write_reply (ret);
- erl_free_term (ret);
+ if (dispatch (&reply, buff, &index) != 0)
+ error (EXIT_FAILURE, 0, "could not decode input data or encode reply
message");
+
+ free (buff);
+ write_reply (&reply);
+ ei_x_free (&reply);
}
guestfs_close (g);
@@ -98,12 +88,12 @@ main (void)
/* The Erlang port always sends the length of the buffer as 4
* bytes in network byte order, followed by the message buffer.
*/
-static unsigned char *
+static char *
read_message (void)
{
uint32_t buf;
size_t size;
- unsigned char *r;
+ char *r;
errno = 0;
if (full_read (0, &buf, 4) != 4) {
@@ -129,19 +119,10 @@ read_message (void)
}
static void
-write_reply (ETERM *term)
+write_reply (ei_x_buff *buff)
{
- size_t size;
+ size_t size = buff->index;
unsigned char sbuf[4];
- unsigned char *buf;
-
- size = erl_term_len (term);
-
- buf = malloc (size);
- if (buf == NULL)
- error (EXIT_FAILURE, errno, "malloc");
-
- erl_encode (term, buf);
sbuf[0] = (size >> 24) & 0xff;
sbuf[1] = (size >> 16) & 0xff;
@@ -151,171 +132,228 @@ write_reply (ETERM *term)
if (full_write (1, sbuf, 4) != 4)
error (EXIT_FAILURE, errno, "write message size");
- if (full_write (1, buf, size) != size)
+ if (full_write (1, buff->buff, size) != size)
error (EXIT_FAILURE, errno, "write message content");
-
- free (buf);
}
/* Note that all published Erlang code/examples etc uses strncmp in
* a buggy way. This is the right way to do it.
*/
int
-atom_equals (ETERM *atom, const char *name)
+atom_equals (const char *atom, const char *name)
{
const size_t namelen = strlen (name);
- const size_t atomlen = ERL_ATOM_SIZE (atom);
+ const size_t atomlen = strlen (atom);
if (namelen != atomlen) return 0;
- return strncmp (ERL_ATOM_PTR (atom), name, atomlen) == 0;
+ return strncmp (atom, name, atomlen) == 0;
}
-ETERM *
-make_error (const char *funname)
+int
+make_error (ei_x_buff *buff, const char *funname)
{
- ETERM *error = erl_mk_atom ("error");
- ETERM *msg = erl_mk_string (guestfs_last_error (g));
- ETERM *num = erl_mk_int (guestfs_last_errno (g));
- ETERM *t[3] = { error, msg, num };
- return erl_mk_tuple (t, 3);
+ if (ei_x_encode_tuple_header (buff, 3) != 0) return -1;
+ if (ei_x_encode_atom (buff, "error") != 0) return -1;
+ if (ei_x_encode_string (buff, guestfs_last_error (g)) != 0) return -1;
+ if (ei_x_encode_long (buff, guestfs_last_errno (g)) != 0) return -1;
+ return 0;
}
-ETERM *
-unknown_function (ETERM *fun)
+int
+unknown_function (ei_x_buff *buff, const char *fun)
{
- ETERM *unknown = erl_mk_atom ("unknown");
- ETERM *funcopy = erl_copy_term (fun);
- ETERM *t[2] = { unknown, funcopy };
- return erl_mk_tuple (t, 2);
+ if (ei_x_encode_tuple_header (buff, 2) != 0) return -1;
+ if (ei_x_encode_atom (buff, "unknown") != 0) return -1;
+ if (ei_x_encode_atom (buff, fun) != 0) return -1;
+ return 0;
}
-ETERM *
-unknown_optarg (const char *funname, ETERM *optargname)
+int
+unknown_optarg (ei_x_buff *buff, const char *funname, const char *optargname)
{
- ETERM *unknownarg = erl_mk_atom ("unknownarg");
- ETERM *copy = erl_copy_term (optargname);
- ETERM *t[2] = { unknownarg, copy };
- return erl_mk_tuple (t, 2);
+ if (ei_x_encode_tuple_header (buff, 2) != 0) return -1;
+ if (ei_x_encode_atom (buff, "unknownarg") != 0) return -1;
+ if (ei_x_encode_atom (buff, optargname) != 0) return -1;
+ return 0;
}
-ETERM *
-make_string_list (char **r)
+int
+make_string_list (ei_x_buff *buff, char **r)
{
size_t i, size;
- CLEANUP_FREE ETERM **t = NULL;
- for (size = 0; r[size] != NULL; ++size)
- ;
+ for (size = 0; r[size] != NULL; ++size);
- t = malloc (sizeof (ETERM *) * size);
- if (t == NULL)
- return make_error ("make_string_list");
+ if (ei_x_encode_list_header (buff, size) != 0) return -1;
for (i = 0; r[i] != NULL; ++i)
- t[i] = erl_mk_string (r[i]);
+ if (ei_x_encode_string (buff, r[i]) != 0) return -1;
- return erl_mk_list (t, size);
+ if (size > 0)
+ if (ei_x_encode_empty_list (buff) != 0) return -1;
+
+ return 0;
}
/* Make a hash table. The number of elements returned by the C
* function is always even.
*/
-ETERM *
-make_table (char **r)
+int
+make_table (ei_x_buff *buff, char **r)
{
size_t i, size;
- CLEANUP_FREE ETERM **t = NULL;
- ETERM *a[2];
- for (size = 0; r[size] != NULL; ++size)
- ;
+ for (size = 0; r[size] != NULL; ++size);
- t = malloc (sizeof (ETERM *) * (size/2));
- if (t == NULL)
- return make_error ("make_table");
+ if (ei_x_encode_list_header (buff, size/2) != 0) return -1;
for (i = 0; r[i] != NULL; i += 2) {
- a[0] = erl_mk_string (r[i]);
- a[1] = erl_mk_string (r[i+1]);
- t[i/2] = erl_mk_tuple (a, 2);
+ if (ei_x_encode_tuple_header (buff, 2) != 0) return -1;
+ if (ei_x_encode_string (buff, r[i]) != 0) return -1;
+ if (ei_x_encode_string (buff, r[i+1]) != 0) return -1;
}
- return erl_mk_list (t, size/2);
+ if (size/2 > 0)
+ if (ei_x_encode_empty_list (buff) != 0) return -1;
+
+ return 0;
}
-ETERM *
-make_bool (int r)
+int
+make_bool (ei_x_buff *buff, int r)
{
if (r)
- return erl_mk_atom ("true");
+ return ei_x_encode_atom (buff, "true");
else
- return erl_mk_atom ("false");
+ return ei_x_encode_atom (buff, "false");
}
-char **
-get_string_list (ETERM *term)
+int
+decode_string_list (const char *buff, int *index, char ***res)
{
- ETERM *t;
- size_t i, size;
+ int i, size;
char **r;
- for (size = 0, t = term; !ERL_IS_EMPTY_LIST (t);
- size++, t = ERL_CONS_TAIL (t))
- ;
+ if (ei_decode_list_header (buff, index, &size) != 0)
+ error (EXIT_FAILURE, 0, "not a list");
r = malloc ((size+1) * sizeof (char *));
if (r == NULL)
error (EXIT_FAILURE, errno, "malloc");
- for (i = 0, t = term; !ERL_IS_EMPTY_LIST (t); i++, t = ERL_CONS_TAIL (t))
- r[i] = erl_iolist_to_string (ERL_CONS_HEAD (t));
+ for (i = 0; i < size; i++)
+ if (decode_string (buff, index, &r[i]) != 0) return -1;
+
+ // End of a list is encoded by an empty list, so skip it
+ if (size > 0 && buff[*index] == ERL_NIL_EXT)
+ (*index)++;
+
r[size] = NULL;
+ *res = r;
- return r;
+ return 0;
}
int
-get_bool (ETERM *term)
+decode_string (const char *buff, int *index, char **res)
{
- if (atom_equals (term, "true"))
- return 1;
+ size_t size;
+
+ if (decode_binary (buff, index, res, &size) != 0) return -1;
+
+ (*res)[size] = 0;
+
+ return 0;
+}
+
+int
+decode_binary (const char *buff, int *index, char **res, size_t *size)
+{
+ int index0;
+ int size0;
+ char *r;
+
+ index0 = *index;
+ if (ei_decode_iodata (buff, index, &size0, NULL) != 0) return -1;
+
+ r = malloc (size0+1); // In case if it's called from decode_string ()
+ if (r == NULL)
+ error (EXIT_FAILURE, errno, "malloc");
+
+ *index = index0;
+ if (ei_decode_iodata (buff, index, NULL, r) != 0) {
+ free (r);
+ return -1;
+ }
+
+ *res = r;
+ *size = (size_t) size0;
+
+ return 0;
+}
+
+int
+decode_bool (const char *buff, int *index, int *res)
+{
+ char atom[MAXATOMLEN];
+
+ if (ei_decode_atom (buff, index, atom) != 0) return -1;
+
+ if (atom_equals (atom, "true"))
+ *res = 1;
else
- return 0;
+ *res = 0;
+
+ return 0;
}
int
-get_int (ETERM *term)
+decode_int (const char *buff, int *index, int *res)
{
- switch (ERL_TYPE (term)) {
- case ERL_INTEGER:
- return ERL_INT_VALUE (term);
- case ERL_U_INTEGER:
- return (int) ERL_INT_UVALUE (term);
- case ERL_LONGLONG:
+ unsigned char c;
+ long l;
+ long long ll;
+
+ if (ei_decode_char (buff, index, (char *) &c) == 0) {
+ // Byte integers in Erlang are to be treated as unsigned
+ *res = (int) c;
+ return 0;
+ }
+ if (ei_decode_long (buff, index, &l) == 0) {
/* XXX check for overflow */
- return (int) ERL_LL_VALUE (term);
- case ERL_U_LONGLONG:
+ *res = (int) l;
+ return 0;
+ }
+ if (ei_decode_longlong (buff, index, &ll) == 0) {
/* XXX check for overflow */
- return (int) ERL_LL_UVALUE (term);
- default:
- /* XXX fail in some way */
- return -1;
+ *res = (int) ll;
+ return 0;
}
+ /* XXX fail in some way */
+ return -1;
}
-int64_t
-get_int64 (ETERM *term)
+int
+decode_int64 (const char *buff, int *index, int64_t *res)
{
- switch (ERL_TYPE (term)) {
- case ERL_INTEGER:
- return ERL_INT_VALUE (term);
- case ERL_U_INTEGER:
- return ERL_INT_UVALUE (term);
- case ERL_LONGLONG:
- return ERL_LL_VALUE (term);
- case ERL_U_LONGLONG:
- return (int64_t) ERL_LL_UVALUE (term);
- default:
- /* XXX fail in some way */
- return -1;
+ unsigned char c;
+ long l;
+ long long ll;
+
+ if (ei_decode_char (buff, index, (char *) &c) == 0) {
+ // Byte integers in Erlang are to be treated as unsigned
+ *res = (int64_t) c;
+ return 0;
+ }
+ if (ei_decode_long (buff, index, &l) == 0) {
+ *res = (int64_t) l;
+ return 0;
}
+ if (ei_decode_longlong (buff, index, &ll) == 0) {
+ /* XXX check for overflow */
+ *res = (int64_t) ll;
+ return 0;
+ }
+ /* XXX fail in some way */
+ return -1;
}
+
diff --git a/generator/erlang.ml b/generator/erlang.ml
index 0cee9c3ef..65af75aaf 100644
--- a/generator/erlang.ml
+++ b/generator/erlang.ml
@@ -192,30 +192,30 @@ and generate_erlang_actions_h () =
extern guestfs_h *g;
-extern ETERM *dispatch (ETERM *args_tuple);
-extern int atom_equals (ETERM *atom, const char *name);
-extern ETERM *make_error (const char *funname);
-extern ETERM *unknown_optarg (const char *funname, ETERM *optargname);
-extern ETERM *unknown_function (ETERM *fun);
-extern ETERM *make_string_list (char **r);
-extern ETERM *make_table (char **r);
-extern ETERM *make_bool (int r);
-extern char **get_string_list (ETERM *term);
-extern int get_bool (ETERM *term);
-extern int get_int (ETERM *term);
-extern int64_t get_int64 (ETERM *term);
-
-#define ARG(i) (ERL_TUPLE_ELEMENT(args_tuple,(i)+1))
+extern int dispatch (ei_x_buff *retbuff, const char *buff, int *index);
+extern int make_error (ei_x_buff *retbuff, const char *funname);
+extern int unknown_optarg (ei_x_buff *retbuff, const char *funname, const char
*optargname);
+extern int unknown_function (ei_x_buff *retbuff, const char *fun);
+extern int make_string_list (ei_x_buff *buff, char **r);
+extern int make_table (ei_x_buff *buff, char **r);
+extern int make_bool (ei_x_buff *buff, int r);
+extern int atom_equals (const char *atom, const char *name);
+extern int decode_string_list (const char *buff, int *index, char ***res);
+extern int decode_string (const char *buff, int *index, char **res);
+extern int decode_binary (const char *buff, int *index, char **res, size_t *size);
+extern int decode_bool (const char *buff, int *index, int *res);
+extern int decode_int (const char *buff, int *index, int *res);
+extern int decode_int64 (const char *buff, int *index, int64_t *res);
";
let emit_copy_list_decl typ =
- pr "ETERM *make_%s_list (const struct guestfs_%s_list *%ss);\n"
+ pr "int make_%s_list (ei_x_buff *buff, const struct guestfs_%s_list
*%ss);\n"
typ typ typ;
in
List.iter (
fun { s_name = typ; s_cols = cols } ->
- pr "ETERM *make_%s (const struct guestfs_%s *%s);\n" typ typ typ;
+ pr "int make_%s (ei_x_buff *buff, const struct guestfs_%s *%s);\n" typ
typ typ;
) external_structs;
List.iter (
@@ -229,7 +229,7 @@ extern int64_t get_int64 (ETERM *term);
List.iter (
fun { name } ->
- pr "ETERM *run_%s (ETERM *args_tuple);\n" name
+ pr "int run_%s (ei_x_buff *retbuff, const char *buff, int *index);\n"
name
) (actions |> external_functions |> sort);
pr "\n";
@@ -247,11 +247,7 @@ and generate_erlang_structs () =
#include <string.h>
#include <errno.h>
-#include <erl_interface.h>
-/* We should switch over to using
- #include <ei.h>
-instead of erl_interface.
-*/
+#include <ei.h>
#include \"guestfs.h\"
#include \"guestfs-utils.h\"
@@ -262,57 +258,61 @@ instead of erl_interface.
(* Struct copy functions. *)
let emit_copy_list_function typ =
pr "\n";
- pr "ETERM *\n";
- pr "make_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
+ pr "int\n";
+ pr "make_%s_list (ei_x_buff *buff, const struct guestfs_%s_list *%ss)\n"
typ typ typ;
pr "{\n";
pr " size_t len = %ss->len;\n" typ;
pr " size_t i;\n";
- pr " CLEANUP_FREE ETERM **t;\n";
pr "\n";
- pr " t = malloc (sizeof (ETERM *) * len);\n";
- pr " if (t == NULL)\n";
- pr " return make_error (\"make_%s_list\");\n" typ;
+ pr " if (ei_x_encode_list_header (buff, len) != 0) return -1;\n";
+ pr " for (i = 0; i < len; ++i) {\n";
+ pr " if (make_%s (buff, &%ss->val[i]) != 0) return -1;\n" typ
typ;
+ pr " }\n";
+ pr " if (len > 0)\n";
+ pr " if (ei_x_encode_empty_list (buff) != 0) return -1;\n";
pr "\n";
- pr " for (i = 0; i < len; ++i)\n";
- pr " t[i] = make_%s (&%ss->val[i]);\n" typ typ;
- pr "\n";
- pr " return erl_mk_list (t, len);\n";
+ pr " return 0;\n";
pr "}\n";
in
List.iter (
fun { s_name = typ; s_cols = cols } ->
pr "\n";
- pr "ETERM *\n";
- pr "make_%s (const struct guestfs_%s *%s)\n" typ typ typ;
+ pr "int\n";
+ pr "make_%s (ei_x_buff *buff, const struct guestfs_%s *%s)\n" typ typ
typ;
pr "{\n";
- pr " ETERM *t[%d];\n" (List.length cols);
+ pr " if (ei_x_encode_list_header (buff, %d) !=0) return -1;\n"
(List.length cols);
pr "\n";
List.iteri (
fun i col ->
(match col with
| name, FString ->
- pr " t[%d] = erl_mk_string (%s->%s);\n" i typ name
+ pr " if (ei_x_encode_string (buff, %s->%s) != 0) return
-1;\n" typ name
| name, FBuffer ->
- pr " t[%d] = erl_mk_estring (%s->%s, %s->%s_len);\n"
- i typ name typ name
+ pr " if (ei_x_encode_string_len (buff, %s->%s, %s->%s_len) !=
0) return -1;\n"
+ typ name typ name
| name, FUUID ->
- pr " t[%d] = erl_mk_estring (%s->%s, 32);\n" i typ name
+ pr " if (ei_x_encode_string_len (buff, %s->%s, 32) != 0) return
-1;\n" typ name
| name, (FBytes|FInt64|FUInt64) ->
- pr " t[%d] = erl_mk_longlong (%s->%s);\n" i typ name
+ pr " if (ei_x_encode_longlong (buff, %s->%s) != 0) return
-1;\n" typ name
| name, (FInt32|FUInt32) ->
- pr " t[%d] = erl_mk_int (%s->%s);\n" i typ name
+ pr " if (ei_x_encode_long (buff, %s->%s) != 0) return -1;\n"
typ name
| name, FOptPercent ->
- pr " if (%s->%s >= 0)\n" typ name;
- pr " t[%d] = erl_mk_float (%s->%s);\n" i typ name;
- pr " else\n";
- pr " t[%d] = erl_mk_atom (\"undefined\");\n" i;
+ pr " if (%s->%s >= 0) {\n" typ name;
+ pr " if (ei_x_encode_double (buff, %s->%s) != 0) return
-1;\n" typ name;
+ pr " } else {\n";
+ pr " if (ei_x_encode_atom (buff, \"undefined\") != 0)
return -1;\n";
+ pr " }\n"
| name, FChar ->
- pr " t[%d] = erl_mk_int (%s->%s);\n" i typ name
+ pr " if (ei_x_encode_char (buff, %s->%s) != 0) return -1;\n"
typ name
);
) cols;
+ if cols <> [] then (
+ pr "\n";
+ pr " if (ei_x_encode_empty_list (buff) != 0) return -1;\n"
+ );
pr "\n";
- pr " return erl_mk_list (t, %d);\n" (List.length cols);
+ pr " return 0;\n";
pr "}\n";
) external_structs;
@@ -341,11 +341,7 @@ and generate_erlang_actions actions () =
#include <string.h>
#include <errno.h>
-#include <erl_interface.h>
-/* We should switch over to using
- #include <ei.h>
-instead of erl_interface.
-*/
+#include <ei.h>
#include \"guestfs.h\"
#include \"guestfs-utils.h\"
@@ -358,33 +354,43 @@ instead of erl_interface.
fun { name; style = (ret, args, optargs as style);
c_function; c_optarg_prefix } ->
pr "\n";
- pr "ETERM *\n";
- pr "run_%s (ETERM *args_tuple)\n" name;
+ pr "int\n";
+ pr "run_%s (ei_x_buff *retbuff, const char *buff, int *idx)\n" name;
pr "{\n";
List.iteri (
fun i ->
function
| String (_, n) ->
- pr " CLEANUP_FREE char *%s = erl_iolist_to_string (ARG (%d));\n" n
i
+ pr " CLEANUP_FREE char *%s;\n" n;
+ pr " if (decode_string (buff, idx, &%s) != 0) return -1;\n" n
| OptString n ->
pr " CLEANUP_FREE char *%s;\n" n;
- pr " if (atom_equals (ARG (%d), \"undefined\"))\n" i;
- pr " %s = NULL;\n" n;
- pr " else\n";
- pr " %s = erl_iolist_to_string (ARG (%d));\n" n i
+ pr " char %s_opt[MAXATOMLEN];\n" n;
+ pr " if (ei_decode_atom(buff, idx, %s_opt) == 0) {\n" n;
+ pr " if (atom_equals (%s_opt, \"undefined\"))\n" n;
+ pr " %s = NULL;\n" n;
+ pr " else\n";
+ pr " %s = %s_opt;\n" n n;
+ pr " } else {\n";
+ pr " if (decode_string (buff, idx, &%s) != 0) return -1;\n"
n;
+ pr " }\n"
| BufferIn n ->
- pr " ETERM *%s_bin = erl_iolist_to_binary (ARG (%d));\n" n i;
- pr " const void *%s = ERL_BIN_PTR (%s_bin);\n" n n;
- pr " size_t %s_size = ERL_BIN_SIZE (%s_bin);\n" n n
+ pr " CLEANUP_FREE char *%s;\n" n;
+ pr " size_t %s_size;\n" n;
+ pr " if (decode_binary (buff, idx, &%s, &%s_size) != 0) return
-1;\n" n n
| StringList (_, n) ->
- pr " CLEANUP_FREE_STRING_LIST char **%s = get_string_list (ARG
(%d));\n" n i
+ pr " CLEANUP_FREE_STRING_LIST char **%s;\n" n;
+ pr " if (decode_string_list (buff, idx, &%s) != 0) return
-1;\n" n
| Bool n ->
- pr " int %s = get_bool (ARG (%d));\n" n i
+ pr " int %s;\n" n;
+ pr " if (decode_bool (buff, idx, &%s) != 0) return -1;\n" n
| Int n ->
- pr " int %s = get_int (ARG (%d));\n" n i
+ pr " int %s;\n" n;
+ pr " if (decode_int (buff, idx, &%s) != 0) return -1;\n" n
| Int64 n ->
- pr " int64_t %s = get_int64 (ARG (%d));\n" n i
+ pr " int64_t %s;\n" n;
+ pr " if (decode_int64 (buff, idx, &%s) != 0) return -1;\n" n
| Pointer (t, n) ->
pr " void * /* %s */ %s = POINTER_NOT_IMPLEMENTED
(\"%s\");\n" t n t
) args;
@@ -394,11 +400,13 @@ instead of erl_interface.
pr "\n";
pr " struct %s optargs_s = { .bitmask = 0 };\n" c_function;
pr " struct %s *optargs = &optargs_s;\n" c_function;
- pr " ETERM *optargst = ARG (%d);\n" (List.length args);
- pr " while (!ERL_IS_EMPTY_LIST (optargst)) {\n";
- pr " ETERM *hd = ERL_CONS_HEAD (optargst);\n";
- pr " ETERM *hd_name = ERL_TUPLE_ELEMENT (hd, 0);\n";
- pr " ETERM *hd_value = ERL_TUPLE_ELEMENT (hd, 1);\n";
+ pr " int optargsize;\n";
+ pr " if (ei_decode_list_header (buff, idx, &optargsize) != 0) return
-1;\n";
+ pr " for (int i = 0; i < optargsize; i++) {\n";
+ pr " int hd;\n";
+ pr " if (ei_decode_tuple_header (buff, idx, &hd) != 0) return
-1;\n";
+ pr " char hd_name[MAXATOMLEN];\n";
+ pr " if (ei_decode_atom (buff, idx, hd_name) != 0) return -1;\n";
pr "\n";
List.iter (
fun argt ->
@@ -407,21 +415,22 @@ instead of erl_interface.
pr " if (atom_equals (hd_name, \"%s\")) {\n" n;
pr " optargs_s.bitmask |= %s_%s_BITMASK;\n"
c_optarg_prefix uc_n;
- pr " optargs_s.%s = " n;
+ pr " ";
(match argt with
- | OBool _ -> pr "get_bool (hd_value)"
- | OInt _ -> pr "get_int (hd_value)"
- | OInt64 _ -> pr "get_int64 (hd_value)"
- | OString _ -> pr "erl_iolist_to_string (hd_value)"
- | OStringList n -> pr "get_string_list (hd_value)"
+ | OBool _ -> pr "if (decode_bool (buff, idx, &optargs_s.%s) !=
0) return -1;" n
+ | OInt _ -> pr "if (decode_int (buff, idx, &optargs_s.%s) != 0)
return -1" n
+ | OInt64 _ -> pr "if (decode_int64 (buff, idx, &optargs_s.%s) !=
0) return -1" n
+ | OString _ -> pr "if (decode_string (buff, idx, (char **)
&optargs_s.%s) != 0) return -1" n
+ | OStringList n -> pr "if (decode_string_list (buff, idx, (char ***)
&optargs_s.%s) != 0) return -1" n
);
pr ";\n";
pr " }\n";
pr " else\n";
) optargs;
- pr " return unknown_optarg (\"%s\", hd_name);\n" name;
- pr " optargst = ERL_CONS_TAIL (optargst);\n";
+ pr " return unknown_optarg (retbuff, \"%s\",
hd_name);\n" name;
pr " }\n";
+ pr " if (optargsize > 0 && buff[*idx] == ERL_NIL_EXT)\n";
+ pr " (*idx)++;\n";
pr "\n";
);
@@ -471,52 +480,46 @@ instead of erl_interface.
| `CannotReturnError -> ()
| `ErrorIsMinusOne ->
pr " if (r == -1)\n";
- pr " return make_error (\"%s\");\n" name;
+ pr " return make_error (retbuff, \"%s\");\n" name;
| `ErrorIsNULL ->
pr " if (r == NULL)\n";
- pr " return make_error (\"%s\");\n" name;
+ pr " return make_error (retbuff, \"%s\");\n" name;
);
pr "\n";
(match ret with
- | RErr -> pr " return erl_mk_atom (\"ok\");\n"
- | RInt _ -> pr " return erl_mk_int (r);\n"
- | RInt64 _ -> pr " return erl_mk_longlong (r);\n"
- | RBool _ -> pr " return make_bool (r);\n"
- | RConstString _ -> pr " return erl_mk_string (r);\n"
+ | RErr -> pr " if (ei_x_encode_atom (retbuff, \"ok\") != 0)
return -1;\n"
+ | RInt _ -> pr " if (ei_x_encode_long (retbuff, r) != 0) return
-1;\n"
+ | RInt64 _ -> pr " if (ei_x_encode_longlong (retbuff, r) != 0) return
-1;\n"
+ | RBool _ -> pr " if (make_bool (retbuff, r) != 0) return -1;\n"
+ | RConstString _ -> pr " if (ei_x_encode_string (retbuff, r) != 0) return
-1;\n"
| RConstOptString _ ->
- pr " ETERM *rt;\n";
- pr " if (r)\n";
- pr " rt = erl_mk_string (r);\n";
- pr " else\n";
- pr " rt = erl_mk_atom (\"undefined\");\n";
- pr " return rt;\n"
+ pr " if (r) {\n";
+ pr " if (ei_x_encode_string (retbuff, r) != 0) return -1;\n";
+ pr " } else {\n";
+ pr " if (ei_x_encode_atom (retbuff, \"undefined\") != 0)
return -1;\n";
+ pr " }\n"
| RString _ ->
- pr " ETERM *rt = erl_mk_string (r);\n";
+ pr " if (ei_x_encode_string (retbuff, r) != 0) return -1;\n";
pr " free (r);\n";
- pr " return rt;\n"
| RStringList _ ->
- pr " ETERM *rt = make_string_list (r);\n";
- pr " guestfs_int_free_string_list (r);\n\n";
- pr " return rt;\n"
+ pr " if (make_string_list (retbuff, r) != 0) return -1;\n";
+ pr " guestfs_int_free_string_list (r);\n"
| RStruct (_, typ) ->
- pr " ETERM *rt = make_%s (r);\n" typ;
- pr " guestfs_free_%s (r);\n" typ;
- pr " return rt;\n"
+ pr " if (make_%s (retbuff, r) != 0) return -1;\n" typ;
+ pr " guestfs_free_%s (r);\n" typ
| RStructList (_, typ) ->
- pr " ETERM *rt = make_%s_list (r);\n" typ;
- pr " guestfs_free_%s_list (r);\n" typ;
- pr " return rt;\n"
+ pr " if (make_%s_list (retbuff, r) != 0) return -1;\n" typ;
+ pr " guestfs_free_%s_list (r);\n" typ
| RHashtable _ ->
- pr " ETERM *rt = make_table (r);\n";
- pr " guestfs_int_free_string_list (r);\n";
- pr " return rt;\n"
+ pr " if (make_table (retbuff, r) != 0) return -1;\n";
+ pr " guestfs_int_free_string_list (r);\n"
| RBufferOut _ ->
- pr " ETERM *rt = erl_mk_estring (r, size);\n";
+ pr " if (ei_x_encode_binary (retbuff, r, size) != 0) return
-1;\n";
pr " free (r);\n";
- pr " return rt;\n"
);
+ pr " return 0;\n";
pr "}\n";
) (actions |> external_functions |> sort);
@@ -532,23 +535,21 @@ and generate_erlang_dispatch () =
#include <string.h>
#include <errno.h>
-#include <erl_interface.h>
-/* We should switch over to using
- #include <ei.h>
-instead of erl_interface.
-*/
+#include <ei.h>
#include \"guestfs.h\"
#include \"guestfs-utils.h\"
#include \"actions.h\"
-ETERM *
-dispatch (ETERM *args_tuple)
+int
+dispatch (ei_x_buff *retbuff, const char *buff, int *index)
{
- ETERM *fun;
+ int arity;
+ char fun[MAXATOMLEN];
- fun = ERL_TUPLE_ELEMENT (args_tuple, 0);
+ if (ei_decode_tuple_header (buff, index, &arity) != 0) return -1;
+ if (ei_decode_atom (buff, index, fun) != 0) return -1;
/* XXX We should use gperf here. */
";
@@ -556,10 +557,10 @@ dispatch (ETERM *args_tuple)
List.iter (
fun { name; style = ret, args, optargs } ->
pr "if (atom_equals (fun, \"%s\"))\n" name;
- pr " return run_%s (args_tuple);\n" name;
+ pr " return run_%s (retbuff, buff, index);\n" name;
pr " else ";
) (actions |> external_functions |> sort);
- pr "return unknown_function (fun);
+ pr "return unknown_function (retbuff, fun);
}
";
--
2.26.2