generator: Add Pointer parameter type to the generator.

This allows generic "foo *bar" pointers to be passed to
library functions (not to daemon functions).

In the language bindings (except Perl) these are handled
as generic int64s with the assumption being that any
pointer can be converted to and from this.  There is room
to add specific support for some pointer types in future
by specializing the match cases.  However this is inherently
tricky because it depends on the implementation details of
other bindings (eg. to support virDomainPtr in OCaml depends
on the implementation details of the ocaml-libvirt project).

Perl is slightly different in that you have to supply a
typemap.  Again this would depend on the implementation
detail of an external library unless you supplied a generic
typemap for int64.
This commit is contained in:
Richard Jones
2010-11-09 12:08:06 +00:00
committed by Richard W.M. Jones
parent eaedf025f5
commit 4ada0a7815
17 changed files with 95 additions and 26 deletions

View File

@@ -89,6 +89,7 @@ print_strings (char *const *argv)
| Bool n -> pr " printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
| Int n -> pr " printf (\"%%d\\n\", %s);\n" n
| Int64 n -> pr " printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
| Pointer _ -> assert false
) args;
pr " /* Java changes stdout line buffering so we need this: */\n";
pr " fflush (stdout);\n";

View File

@@ -116,6 +116,9 @@ let rec generate_prototype ?(extern = true) ?(static = false)
pr "const char *%s" n;
next ();
pr "size_t %s_size" n
| Pointer (t, n) ->
next ();
pr "%s %s" t n
) args;
if is_RBufferOut then (next (); pr "size_t *size_r");
if optargs <> [] then (
@@ -536,7 +539,8 @@ check_state (guestfs_h *g, const char *caller)
| BufferIn n
| StringList n
| DeviceList n
| Key n ->
| Key n
| Pointer (_, n) ->
pr " if (%s == NULL) {\n" n;
pr " error (g, \"%%s: %%s: parameter cannot be NULL\",\n";
pr " \"%s\", \"%s\");\n" shortname n;
@@ -639,6 +643,8 @@ check_state (guestfs_h *g, const char *caller)
| BufferIn n -> (* RHBZ#646822 *)
pr " fputc (' ', stderr);\n";
pr " guestfs___print_BufferIn (stderr, %s, %s_size);\n" n n
| Pointer (t, n) ->
pr " fprintf (stderr, \" (%s)%%p\", %s);\n" t n
) args;
(* Optional arguments. *)
@@ -770,6 +776,7 @@ check_state (guestfs_h *g, const char *caller)
pr " }\n";
pr " args.%s.%s_val = (char *) %s;\n" n n n;
pr " args.%s.%s_len = %s_size;\n" n n n
| Pointer _ -> assert false
) args;
pr " serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
(String.uppercase shortname);

View File

@@ -744,6 +744,9 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
) strs;
pr " NULL\n";
pr " };\n";
| Pointer _, _ ->
(* Difficult to make these pointers in order to run a test. *)
assert false
) (List.combine (snd style) args);
let error_code =
@@ -799,6 +802,7 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
pr ", %Ld" i
| Bool _, arg ->
let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
| Pointer _, _ -> assert false
) (List.combine (snd style) args);
(match fst style with

View File

@@ -129,6 +129,19 @@ let () =
) optargs
) all_functions;
(* Some parameter types not supported for daemon functions. *)
List.iter (
fun (name, (_, args, optargs), _, _, _, _, _) ->
let check_arg_type = function
| Pointer _ ->
failwithf "Pointer is not supported for daemon function %s."
name
| _ -> ()
in
List.iter check_arg_type args;
List.iter check_arg_type optargs;
) daemon_functions;
(* Check short descriptions. *)
List.iter (
fun (name, _, _, _, _, shortdesc, _) ->

View File

@@ -197,7 +197,7 @@ namespace Guestfs
pr ", bool %s" n
| Int n ->
pr ", int %s" n
| Int64 n ->
| Int64 n | Pointer (_, n) ->
pr ", long %s" n
) args;
pr ");\n"
@@ -222,7 +222,7 @@ namespace Guestfs
next (); pr "bool %s" n
| Int n ->
next (); pr "int %s" n
| Int64 n ->
| Int64 n | Pointer (_, n) ->
next (); pr "long %s" n
) args;
pr ")\n"

View File

@@ -105,6 +105,7 @@ and generate_daemon_actions () =
| BufferIn n ->
pr " const char *%s;\n" n;
pr " size_t %s_size;\n" n
| Pointer _ -> assert false
) args
);
pr "\n";
@@ -174,6 +175,7 @@ and generate_daemon_actions () =
| BufferIn n ->
pr " %s = args.%s.%s_val;\n" n n n;
pr " %s_size = args.%s.%s_len;\n" n n n
| Pointer _ -> assert false
) args;
pr "\n"
);

View File

@@ -323,6 +323,7 @@ Guestfish will prompt for these separately."
| Bool n -> pr " int %s;\n" n
| Int n -> pr " int %s;\n" n
| Int64 n -> pr " int64_t %s;\n" n
| Pointer _ -> assert false
) args;
if optargs <> [] then (
@@ -423,6 +424,7 @@ Guestfish will prompt for these separately."
parse_integer "argv[i++]" "xstrtoll" "long long" "int" range name
| Int64 name ->
parse_integer "argv[i++]" "xstrtoll" "long long" "int64_t" None name
| Pointer _ -> assert false
) args;
(* Optional arguments are prefixed with <argname>:<value> and
@@ -506,6 +508,7 @@ Guestfish will prompt for these separately."
pr " free_file_in (%s);\n" name
| StringList name | DeviceList name ->
pr " free_strings (%s);\n" name
| Pointer _ -> assert false
) args;
(* Any output flags? *)
@@ -810,6 +813,7 @@ and generate_fish_actions_pod () =
| FileIn n | FileOut n -> pr " (%s|-)" n
| BufferIn n -> pr " %s" n
| Key _ -> () (* keys are entered at a prompt *)
| Pointer _ -> assert false
) args;
List.iter (
function

View File

@@ -148,7 +148,7 @@ last_error h = do
pr "withCStringLen %s $ \\(%s, %s_size) -> " n n n
| OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
| StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
| Bool _ | Int _ | Int64 _ -> ()
| Bool _ | Int _ | Int64 _ | Pointer _ -> ()
) args;
(* Convert integer arguments. *)
let args =
@@ -156,7 +156,7 @@ last_error h = do
function
| Bool n -> sprintf "(fromBool %s)" n
| Int n -> sprintf "(fromIntegral %s)" n
| Int64 n -> sprintf "(fromIntegral %s)" n
| Int64 n | Pointer (_, n) -> sprintf "(fromIntegral %s)" n
| FileIn n | FileOut n
| Pathname n | Device n | Dev_or_Path n
| String n | OptString n
@@ -222,6 +222,7 @@ and generate_haskell_prototype ~handle ?(hs = false) (ret, args, optargs) =
| Bool _ -> pr "%s" bool
| Int _ -> pr "%s" int
| Int64 _ -> pr "%s" int
| Pointer _ -> pr "%s" int
| FileIn _ -> pr "%s" string
| FileOut _ -> pr "%s" string
);

View File

@@ -217,7 +217,7 @@ and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
pr "boolean %s" n
| Int n ->
pr "int %s" n
| Int64 n ->
| Int64 n | Pointer (_, n) ->
pr "long %s" n
) args;
@@ -347,7 +347,7 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
pr ", jboolean j%s" n
| Int n ->
pr ", jint j%s" n
| Int64 n ->
| Int64 n | Pointer (_, n) ->
pr ", jlong j%s" n
) args;
if optargs <> [] then
@@ -410,6 +410,8 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
pr " int %s;\n" n
| Int64 n ->
pr " int64_t %s;\n" n
| Pointer (t, n) ->
pr " %s %s;\n" t n
) args;
let needs_i =
@@ -458,6 +460,8 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
| Int n
| Int64 n ->
pr " %s = j%s;\n" n n
| Pointer (t, n) ->
pr " %s = (%s) j%s;\n" n t n
) args;
if optargs <> [] then (
@@ -497,9 +501,10 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
pr " (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
pr " }\n";
pr " free (%s);\n" n
| Bool n
| Int n
| Int64 n -> ()
| Bool _
| Int _
| Int64 _
| Pointer _ -> ()
) args;
(* Check for errors. *)

View File

@@ -198,6 +198,7 @@ and generate_ocaml_c () =
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <caml/config.h>
#include <caml/alloc.h>
@@ -400,6 +401,8 @@ copy_table (char * const * argv)
pr " int %s = Int_val (%sv);\n" n n
| Int64 n ->
pr " int64_t %s = Int64_val (%sv);\n" n n
| Pointer (t, n) ->
pr " %s %s = (%s) (intptr_t) Int64_val (%sv);\n" t n t n
) args;
(* Optional arguments. *)
@@ -471,7 +474,7 @@ copy_table (char * const * argv)
pr " free (%s);\n" n
| StringList n | DeviceList n ->
pr " ocaml_guestfs_free_strings (%s);\n" n;
| Bool _ | Int _ | Int64 _ -> ()
| Bool _ | Int _ | Int64 _ | Pointer _ -> ()
) args;
List.iter (
function
@@ -481,7 +484,7 @@ copy_table (char * const * argv)
| Bool _ | Int _ | Int64 _
| Pathname _ | Device _ | Dev_or_Path _ | OptString _
| FileIn _ | FileOut _ | BufferIn _ | Key _
| StringList _ | DeviceList _ -> ()
| StringList _ | DeviceList _ | Pointer _ -> ()
) optargs;
pr " if (r == %s)\n" error_code;
@@ -592,7 +595,7 @@ and generate_ocaml_function_type (ret, args, optargs) =
| StringList _ | DeviceList _ -> pr "string array -> "
| Bool _ -> pr "bool -> "
| Int _ -> pr "int -> "
| Int64 _ -> pr "int64 -> "
| Int64 _ | Pointer _ -> pr "int64 -> "
) args;
(match ret with
| RErr -> pr "unit" (* all errors are turned into exceptions *)

View File

@@ -242,6 +242,7 @@ clear_progress_callback (g)
| Bool n -> pr " int %s;\n" n
| Int n -> pr " int %s;\n" n
| Int64 n -> pr " int64_t %s;\n" n
| Pointer (t, n) -> pr " %s %s;\n" t n
) args;
(* PREINIT section (local variable declarations). *)
@@ -362,7 +363,7 @@ clear_progress_callback (g)
| Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
| Bool _ | Int _ | Int64 _
| FileIn _ | FileOut _
| BufferIn _ | Key _ -> ()
| BufferIn _ | Key _ | Pointer _ -> ()
| StringList n | DeviceList n -> pr " free (%s);\n" n
) args;
@@ -751,7 +752,7 @@ and generate_perl_prototype name (ret, args, optargs) =
match arg with
| Pathname n | Device n | Dev_or_Path n | String n
| OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n
| BufferIn n | Key n ->
| BufferIn n | Key n | Pointer (_, n) ->
pr "$%s" n
| StringList n | DeviceList n ->
pr "\\@%s" n

View File

@@ -200,7 +200,7 @@ PHP_FUNCTION (guestfs_last_error)
pr " char **%s;\n" n;
| Bool n ->
pr " zend_bool %s;\n" n
| Int n | Int64 n ->
| Int n | Int64 n | Pointer (_, n) ->
pr " long %s;\n" n
) args;
@@ -236,7 +236,7 @@ PHP_FUNCTION (guestfs_last_error)
| OptString n -> "s!"
| StringList n | DeviceList n -> "a"
| Bool n -> "b"
| Int n | Int64 n -> "l"
| Int n | Int64 n | Pointer (_, n) -> "l"
) args
) in
@@ -267,7 +267,7 @@ PHP_FUNCTION (guestfs_last_error)
pr ", &z_%s" n
| Bool n ->
pr ", &%s" n
| Int n | Int64 n ->
| Int n | Int64 n | Pointer (_, n) ->
pr ", &%s" n
) args;
List.iter (
@@ -330,7 +330,7 @@ PHP_FUNCTION (guestfs_last_error)
pr " %s[c] = NULL;\n" n;
pr " }\n";
pr "\n"
| Bool n | Int n | Int64 n -> ()
| Bool _ | Int _ | Int64 _ | Pointer _ -> ()
) args;
(* Optional arguments. *)
@@ -406,7 +406,7 @@ PHP_FUNCTION (guestfs_last_error)
pr " efree (%s);\n" n;
pr " }\n";
pr "\n"
| Bool n | Int n | Int64 n -> ()
| Bool _ | Int _ | Int64 _ | Pointer _ -> ()
) args;
(* Check for errors. *)

View File

@@ -324,6 +324,9 @@ py_guestfs_close (PyObject *self, PyObject *args)
| Bool n -> pr " int %s;\n" n
| Int n -> pr " int %s;\n" n
| Int64 n -> pr " long long %s;\n" n
| Pointer (t, n) ->
pr " long long %s_int64;\n" n;
pr " %s %s;\n" t n
) args;
if optargs <> [] then (
@@ -360,9 +363,11 @@ py_guestfs_close (PyObject *self, PyObject *args)
| StringList _ | DeviceList _ -> pr "O"
| Bool _ -> pr "i" (* XXX Python has booleans? *)
| Int _ -> pr "i"
| Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
* emulate C's int/long/long long in Python?
*)
| Int64 _ | Pointer _ ->
(* XXX Whoever thought it was a good idea to
* emulate C's int/long/long long in Python?
*)
pr "L"
| BufferIn _ -> pr "s#"
) args;
@@ -388,6 +393,7 @@ py_guestfs_close (PyObject *self, PyObject *args)
| Bool n -> pr ", &%s" n
| Int n -> pr ", &%s" n
| Int64 n -> pr ", &%s" n
| Pointer (_, n) -> pr ", &%s_int64" n
| BufferIn n -> pr ", &%s, &%s_size" n n
) args;
@@ -409,6 +415,8 @@ py_guestfs_close (PyObject *self, PyObject *args)
| StringList n | DeviceList n ->
pr " %s = get_string_list (py_%s);\n" n n;
pr " if (!%s) return NULL;\n" n
| Pointer (t, n) ->
pr " %s = (%s) (intptr_t) %s_int64;\n" n t n
) args;
pr "\n";
@@ -444,7 +452,7 @@ py_guestfs_close (PyObject *self, PyObject *args)
function
| Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
| FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
| BufferIn _ -> ()
| BufferIn _ | Pointer _ -> ()
| StringList n | DeviceList n ->
pr " free (%s);\n" n
) args;

View File

@@ -148,6 +148,8 @@ static VALUE ruby_guestfs_close (VALUE gv)
pr " int %s = NUM2INT (%sv);\n" n n
| Int64 n ->
pr " long long %s = NUM2LL (%sv);\n" n n
| Pointer (t, n) ->
pr " %s %s = (%s) (intptr_t) NUM2LL (%sv);\n" t n t n
) args;
pr "\n";
@@ -210,7 +212,7 @@ static VALUE ruby_guestfs_close (VALUE gv)
function
| Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
| FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
| BufferIn _ -> ()
| BufferIn _ | Pointer _ -> ()
| StringList n | DeviceList n ->
pr " free (%s);\n" n
) args;

View File

@@ -185,6 +185,23 @@ and argt =
*)
| FileIn of string
| FileOut of string
(* This specifies an opaque pointer that is passed through
* untouched. Only non-daemon functions are supported.
*
* Pointer ("foo *", "bar") translates to "foo *bar" in the
* C API. The pointer ("bar") cannot be NULL.
*
* This is less well supported in other language bindings:
* if the pointer type is known then we may be able to produce
* a suitable binding, otherwise this is translated into a 64
* bit int.
*
* Functions with this parameter type are not supported at all
* in guestfish (the function must be declared "NotInFish" else
* you will get an error). Also the function cannot contain
* tests, although we should fix this in future.
*)
| Pointer of (string * string)
type flags =
| ProtocolLimitWarning (* display warning about protocol size limits *)

View File

@@ -230,7 +230,7 @@ let map_chars f str =
let name_of_argt = function
| Pathname n | Device n | Dev_or_Path n | String n | OptString n
| StringList n | DeviceList n | Bool n | Int n | Int64 n
| FileIn n | FileOut n | BufferIn n | Key n -> n
| FileIn n | FileOut n | BufferIn n | Key n | Pointer (_, n) -> n
let seq_of_test = function
| TestRun s | TestOutput (s, _) | TestOutputList (s, _)

View File

@@ -86,6 +86,7 @@ let generate_xdr () =
| BufferIn n ->
pr " opaque %s<>;\n" n
| FileIn _ | FileOut _ -> ()
| Pointer _ -> assert false
) args;
pr "};\n\n"
);