generator: Add Pointer parameter type to the generator.
authorRichard Jones <rjones@redhat.com>
Tue, 9 Nov 2010 12:08:06 +0000 (12:08 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Thu, 18 Nov 2010 11:34:32 +0000 (11:34 +0000)
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.
(cherry picked from commit 4ada0a7815075c9cbe9d8b00da791c105ae739a9)

17 files changed:
generator/generator_bindtests.ml
generator/generator_c.ml
generator/generator_capitests.ml
generator/generator_checks.ml
generator/generator_csharp.ml
generator/generator_daemon.ml
generator/generator_fish.ml
generator/generator_haskell.ml
generator/generator_java.ml
generator/generator_ocaml.ml
generator/generator_perl.ml
generator/generator_php.ml
generator/generator_python.ml
generator/generator_ruby.ml
generator/generator_types.ml
generator/generator_utils.ml
generator/generator_xdr.ml

index 02b0680..ebe2e24 100644 (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";
index 1d580e0..b06ab40 100644 (file)
@@ -115,6 +115,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 (
@@ -530,7 +533,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;
@@ -633,6 +637,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. *)
@@ -764,6 +770,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);
index 325b37c..190e10f 100644 (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
index 3474047..0fb8ea4 100644 (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, _) ->
index e178945..5cc71c3 100644 (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"
index df9f965..e3d87e5 100644 (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"
       );
index 1341fa2..70977ad 100644 (file)
@@ -322,6 +322,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 (
@@ -422,6 +423,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
@@ -505,6 +507,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? *)
@@ -809,6 +812,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
index b49e385..88e4f7f 100644 (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
       );
index b551740..5ac92f7 100644 (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. *)
index 888a152..860242c 100644 (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 *)
index 96b8dd1..72f978d 100644 (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
index b71d5c3..d405656 100644 (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. *)
index f85f5d6..bc570a8 100644 (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;
index d0a7cd2..6d627b0 100644 (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;
index 262fb20..a480aac 100644 (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 *)
index 425a579..6dc11bf 100644 (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, _)
index 4942149..8904a86 100644 (file)
@@ -86,6 +86,7 @@ let generate_xdr () =
              | BufferIn n ->
                  pr "  opaque %s<>;\n" n
              | FileIn _ | FileOut _ -> ()
+             | Pointer _ -> assert false
            ) args;
            pr "};\n\n"
       );