[Libguestfs] [PATCH 3/6] generator: In non-C bindings, generate '*_opts' alias.

Richard W.M. Jones rjones at redhat.com
Sat Jul 14 13:28:26 UTC 2012


From: "Richard W.M. Jones" <rjones at redhat.com>

In C, a function called 'func' which has once_had_no_optargs=true will
(because of the previous commit) generate 'func_opts' and a
backwards-compatibility function called 'func'.

This commit changes some of the non-C bindings so that they also
generate 'func_opts' which is merely a wrapper that calls 'func'.

This avoids incompatibility when we rename 'mkfs_opts' etc back to
plain 'mkfs', and it also makes it easier to translate between other
language bindings and C code.

NB: Some bindings do not include aliases:

  PHP:     There's no way to easily alias methods in PHP < 5.3, and we
           can't assume everyone has this minimum version.

  GObject: Very complex to add aliases, but we should probably do this
           at some point.

  Haskell: No support for optargs in these bindings.  Unfortunately
           this means that we can no longer bind 'Guestfs.add_drive'
           (since it will be changed to add optional arguments) making
           the Haskell bindings even less useful than they were already.
---
 generator/generator_actions.ml |    6 +++--
 generator/generator_csharp.ml  |   20 ++++++++++++---
 generator/generator_erlang.ml  |   54 +++++++++++++++++++++++++++++++++++-----
 generator/generator_fish.ml    |   28 +++++++++++++++------
 generator/generator_java.ml    |   48 ++++++++++++++++++++++++++++++++++-
 generator/generator_ocaml.ml   |   38 +++++++++++++++++++++-------
 generator/generator_perl.ml    |   36 +++++++++++++++++++++++++--
 generator/generator_python.ml  |    8 +++++-
 generator/generator_ruby.ml    |   12 +++++++--
 generator/generator_types.ml   |    2 ++
 10 files changed, 218 insertions(+), 34 deletions(-)

diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index 97b0290..0073c45 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -32,7 +32,8 @@ let defaults = { name = ""; style = RErr, [], []; proc_nr = None;
                  progress = false; camel_name = "";
                  cancellable = false; config_only = false;
                  once_had_no_optargs = false;
-                 c_name = ""; c_function = ""; c_optarg_prefix = "" }
+                 c_name = ""; c_function = ""; c_optarg_prefix = "";
+                 non_c_aliases = [] }
 
 (* These test functions are used in the language binding tests. *)
 
@@ -9319,7 +9320,8 @@ let non_daemon_functions, daemon_functions =
       { f with
           c_name = f.name ^ "_opts";
           c_function = "guestfs_" ^ f.name ^ "_opts_argv";
-          c_optarg_prefix = "GUESTFS_" ^ String.uppercase f.name ^ "_OPTS" }
+          c_optarg_prefix = "GUESTFS_" ^ String.uppercase f.name ^ "_OPTS";
+          non_c_aliases = [ f.name ^ "_opts" ] }
   in
   let non_daemon_functions = List.map make_c_function non_daemon_functions in
   let daemon_functions = List.map make_c_function daemon_functions in
diff --git a/generator/generator_csharp.ml b/generator/generator_csharp.ml
index 70b9a8d..e1a31cf 100644
--- a/generator/generator_csharp.ml
+++ b/generator/generator_csharp.ml
@@ -136,7 +136,7 @@ namespace Guestfs
   (* Generate C# function bindings. *)
   List.iter (
     fun { name = name; style = ret, args, optargs; c_function = c_function;
-          shortdesc = shortdesc } ->
+          shortdesc = shortdesc; non_c_aliases = non_c_aliases } ->
       let rec csharp_return_type () =
         match ret with
         | RErr -> "void"
@@ -204,7 +204,7 @@ namespace Guestfs
         if optargs <> [] then pr ", void *";
         pr ");\n"
 
-      and generate_public_prototype () =
+      and generate_public_prototype name =
         pr "    public %s %s (" (csharp_return_type ()) name;
         let comma = ref false in
         let next () =
@@ -237,15 +237,27 @@ namespace Guestfs
          *)
         if optargs <> [] then pr ", NULL";
         pr ");\n";
+
+      and generate_alias alias =
+        generate_public_prototype alias;
+        pr "    {\n";
+        (match ret with
+        | RErr -> pr "      ";
+        | _ -> pr "      return "
+        );
+        pr "%s (%s);\n" name (String.concat ", " (List.map name_of_argt args));
+        pr "    }\n";
+        pr "\n";
       in
 
       pr "    [DllImport (\"%s\")]\n" library;
       generate_extern_prototype ();
       pr "\n";
+
       pr "    /// <summary>\n";
       pr "    /// %s\n" shortdesc;
       pr "    /// </summary>\n";
-      generate_public_prototype ();
+      generate_public_prototype name;
       pr "    {\n";
       pr "      %s r;\n" (c_return_type ());
       pr "      r = ";
@@ -268,6 +280,8 @@ namespace Guestfs
       );
       pr "    }\n";
       pr "\n";
+
+      List.iter generate_alias non_c_aliases
   ) all_functions_sorted;
 
   pr "  }
diff --git a/generator/generator_erlang.ml b/generator/generator_erlang.ml
index 083b573..3c2c04d 100644
--- a/generator/generator_erlang.ml
+++ b/generator/generator_erlang.ml
@@ -40,12 +40,16 @@ let rec generate_erlang_erl () =
 
   (* Export the public actions. *)
   List.iter (
-    fun { name = name; style = _, args, optargs } ->
+    fun { name = name; style = _, args, optargs; non_c_aliases = aliases } ->
       let nr_args = List.length args in
-      if optargs = [] then
-        pr "-export([%s/%d]).\n" name (nr_args+1)
-      else
-        pr "-export([%s/%d, %s/%d]).\n" name (nr_args+1) name (nr_args+2)
+      let export name =
+        if optargs = [] then
+          pr "-export([%s/%d]).\n" name (nr_args+1)
+        else
+          pr "-export([%s/%d, %s/%d]).\n" name (nr_args+1) name (nr_args+2)
+      in
+      export name;
+      List.iter export aliases
   ) all_functions_sorted;
 
   pr "\n";
@@ -95,7 +99,7 @@ loop(Port) ->
    * process which dispatches them to the port.
    *)
   List.iter (
-    fun { name = name; style = _, args, optargs } ->
+    fun { name = name; style = _, args, optargs; non_c_aliases = aliases } ->
       pr "%s(G" name;
       List.iter (
         fun arg ->
@@ -135,6 +139,44 @@ loop(Port) ->
         pr ").\n"
       );
 
+      (* Aliases. *)
+      List.iter (
+        fun alias ->
+          pr "%s(G" alias;
+          List.iter (
+            fun arg ->
+              pr ", %s" (String.capitalize (name_of_argt arg))
+          ) args;
+          if optargs <> [] then
+            pr ", Optargs";
+          pr ") ->\n";
+
+          pr "  %s(G" name;
+          List.iter (
+            fun arg ->
+              pr ", %s" (String.capitalize (name_of_argt arg))
+          ) args;
+          if optargs <> [] then
+            pr ", Optargs";
+          pr ").\n";
+
+          if optargs <> [] then (
+            pr "%s(G" alias;
+            List.iter (
+              fun arg ->
+                pr ", %s" (String.capitalize (name_of_argt arg))
+            ) args;
+            pr ") ->\n";
+
+            pr "  %s(G" name;
+            List.iter (
+              fun arg ->
+                pr ", %s" (String.capitalize (name_of_argt arg))
+            ) args;
+            pr ").\n"
+          )
+      ) aliases;
+
       pr "\n"
   ) all_functions_sorted
 
diff --git a/generator/generator_fish.ml b/generator/generator_fish.ml
index 12e2acd..aba46e9 100644
--- a/generator/generator_fish.ml
+++ b/generator/generator_fish.ml
@@ -37,6 +37,11 @@ let doc_opttype_of = function
   | OInt64 n -> "N"
   | OString n -> ".."
 
+let get_aliases { fish_alias = fish_alias; non_c_aliases = non_c_aliases } =
+  let non_c_aliases =
+    List.map (fun n -> replace_char n '_' '-') non_c_aliases in
+  fish_alias @ non_c_aliases
+
 (* Generate a lot of different functions for guestfish. *)
 let generate_fish_cmds () =
   generate_header CStyle GPLv2plus;
@@ -84,8 +89,9 @@ let generate_fish_cmds () =
 
   (* List of command_entry structs. *)
   List.iter (
-    fun { name = name; fish_alias = aliases; shortdesc = shortdesc;
-          longdesc = longdesc } ->
+    fun ({ name = name; shortdesc = shortdesc; longdesc = longdesc } as f) ->
+      let aliases = get_aliases f in
+
       let name2 = replace_char name '_' '-' in
       let describe_alias =
         if aliases <> [] then
@@ -109,8 +115,10 @@ let generate_fish_cmds () =
   ) fish_commands;
 
   List.iter (
-    fun ({ name = name; style = _, args, optargs; fish_alias = aliases;
+    fun ({ name = name; style = _, args, optargs;
            shortdesc = shortdesc; longdesc = longdesc } as f) ->
+      let aliases = get_aliases f in
+
       let name2 = replace_char name '_' '-' in
 
       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
@@ -694,7 +702,8 @@ struct command_table;
 ";
 
   List.iter (
-    fun { name = name; fish_alias = aliases } ->
+    fun ({ name = name } as f) ->
+      let aliases = get_aliases f in
       let name2 = replace_char name '_' '-' in
 
       (* The basic command. *)
@@ -742,7 +751,8 @@ static const char *const commands[] = {
    *)
   let commands =
     List.map (
-      fun { name = name; fish_alias = aliases } ->
+      fun ({ name = name } as f) ->
+        let aliases = get_aliases f in
         let name2 = replace_char name '_' '-' in
         name2 :: aliases
     ) (all_functions @ fish_commands) in
@@ -813,8 +823,9 @@ and generate_fish_actions_pod () =
   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
 
   List.iter (
-    fun ({ name = name; style = _, args, optargs; fish_alias = aliases;
-          longdesc = longdesc } as f) ->
+    fun ({ name = name; style = _, args, optargs; longdesc = longdesc } as f) ->
+      let aliases = get_aliases f in
+
       let longdesc =
         Str.global_substitute rex (
           fun s ->
@@ -876,7 +887,8 @@ Guestfish will prompt for these separately.\n\n";
 (* Generate documentation for guestfish-only commands. *)
 and generate_fish_commands_pod () =
   List.iter (
-    fun { name = name; fish_alias = aliases; longdesc = longdesc } ->
+    fun ({ name = name; longdesc = longdesc } as f) ->
+      let aliases = get_aliases f in
       let name = replace_char name '_' '-' in
 
       List.iter (
diff --git a/generator/generator_java.ml b/generator/generator_java.ml
index 62a1775..d239e1f 100644
--- a/generator/generator_java.ml
+++ b/generator/generator_java.ml
@@ -95,7 +95,7 @@ public class GuestFS {
   List.iter (
     fun ({ name = name; style = (ret, args, optargs as style);
            in_docs = in_docs; shortdesc = shortdesc;
-           longdesc = longdesc } as f) ->
+           longdesc = longdesc; non_c_aliases = non_c_aliases } as f) ->
       if in_docs then (
         let doc = replace_str longdesc "C<guestfs_" "C<g." in
         let doc =
@@ -200,6 +200,52 @@ public class GuestFS {
         pr "\n"
       );
 
+      (* Aliases. *)
+      List.iter (
+        fun alias ->
+          pr "  ";
+          generate_java_prototype ~public:true ~semicolon:false alias style;
+          pr "\n";
+          pr "  {\n";
+          (match ret with
+          | RErr -> pr "    "
+          | _ ->    pr "    return "
+          );
+          pr "%s (" name;
+          let needs_comma = ref false in
+          List.iter (
+            fun arg ->
+              if !needs_comma then pr ", ";
+              needs_comma := true;
+              pr "%s" (name_of_argt arg)
+          ) args;
+          if optargs <> [] then (
+            if !needs_comma then pr ", ";
+            needs_comma := true;
+            pr "optargs"
+          );
+          pr ");\n";
+          pr "  }\n";
+          pr "\n";
+
+          if optargs <> [] then (
+            pr "  ";
+            generate_java_prototype ~public:true ~semicolon:false
+              alias (ret, args, []);
+            pr "\n";
+            pr "  {\n";
+            (match ret with
+            | RErr -> pr "    "
+            | _ ->    pr "    return "
+            );
+            pr "%s (" name;
+            List.iter (fun arg -> pr "%s, " (name_of_argt arg)) args;
+            pr "null);\n";
+            pr "  }\n";
+            pr "\n"
+          )
+      ) non_c_aliases;
+
       (* Prototype for the native method. *)
       pr "  ";
       generate_java_prototype ~privat:true ~native:true name style;
diff --git a/generator/generator_ocaml.ml b/generator/generator_ocaml.ml
index f54ed2c..392f9cb 100644
--- a/generator/generator_ocaml.ml
+++ b/generator/generator_ocaml.ml
@@ -125,6 +125,7 @@ val user_cancel : t -> unit
   (* The actions. *)
   List.iter (
     fun { name = name; style = style; deprecated_by = deprecated_by;
+          non_c_aliases = non_c_aliases;
           in_docs = in_docs; shortdesc = shortdesc } ->
       generate_ocaml_prototype name style;
 
@@ -137,7 +138,14 @@ val user_cancel : t -> unit
         );
         pr " *)\n";
       );
-      pr "\n"
+      pr "\n";
+
+      (* Aliases. *)
+      List.iter (
+        fun alias ->
+          generate_ocaml_prototype alias style;
+          pr "\n";
+      ) non_c_aliases;
   ) all_functions_sorted;
 
   pr "\
@@ -173,15 +181,22 @@ class guestfs : unit -> object
 ";
 
   List.iter (
-    function
-    | { name = name; style = ((_, [], _) as style) } ->
+    fun { name = name; style = style; non_c_aliases = non_c_aliases } ->
+      (match style with
+      | _, [], _ ->
         pr "  method %s : " name;
         generate_ocaml_function_type ~extra_unit:true style;
         pr "\n"
-    | { name = name; style = style } ->
+      | _, (_::_), _ ->
         pr "  method %s : " name;
         generate_ocaml_function_type style;
         pr "\n"
+      );
+      List.iter (fun alias ->
+        pr "  method %s : " alias;
+        generate_ocaml_function_type style;
+        pr "\n"
+      ) non_c_aliases
   ) all_functions_sorted;
 
   pr "end\n"
@@ -243,15 +258,16 @@ let () =
 
   (* The actions. *)
   List.iter (
-    fun { name = name; style = style } ->
+    fun { name = name; style = style; non_c_aliases = non_c_aliases } ->
       generate_ocaml_prototype ~is_external:true name style;
+      List.iter (fun alias -> pr "let %s = %s\n" alias name) non_c_aliases
   ) all_functions_sorted;
 
   (* OO API. *)
   pr "
 class guestfs () =
   let g = create () in
-  object
+  object (self)
     method close () = close g
     method set_event_callback = set_event_callback g
     method delete_event_callback = delete_event_callback g
@@ -261,15 +277,19 @@ class guestfs () =
 ";
 
   List.iter (
-    function
-    | { name = name; style = _, [], optargs } ->
+    fun { name = name; style = style; non_c_aliases = non_c_aliases } ->
+      (match style with
+      | _, [], optargs ->
         (* No required params?  Add explicit unit. *)
         let optargs =
           String.concat ""
             (List.map (fun arg -> " ?" ^ name_of_optargt arg) optargs) in
         pr "    method %s%s () = %s g%s\n" name optargs name optargs
-    | { name = name } ->
+      | _, (_::_), _ ->
         pr "    method %s = %s g\n" name name
+      );
+      List.iter
+        (fun alias -> pr "    method %s = self#%s\n" alias name) non_c_aliases
   ) all_functions_sorted;
 
   pr "  end\n"
diff --git a/generator/generator_perl.ml b/generator/generator_perl.ml
index d5cf814..b363bfc 100644
--- a/generator/generator_perl.ml
+++ b/generator/generator_perl.ml
@@ -797,7 +797,7 @@ handlers and threads.
     function
     | { in_docs = false } -> ()
     | ({ name = name; style = style; in_docs = true;
-         longdesc = longdesc } as f) ->
+         longdesc = longdesc; non_c_aliases = non_c_aliases } as f) ->
       let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
       pr "=item ";
       generate_perl_prototype name style;
@@ -805,9 +805,28 @@ handlers and threads.
       pr "%s\n\n" longdesc;
       if f.protocol_limit_warning then
         pr "%s\n\n" protocol_limit_warning;
-      match deprecation_notice f with
+      (match deprecation_notice f with
       | None -> ()
       | Some txt -> pr "%s\n\n" txt
+      );
+
+      (* Aliases. *)
+      List.iter (
+        fun alias ->
+          pr "=item ";
+          generate_perl_prototype alias style;
+          pr "\n";
+          pr "\n";
+          pr "This is an alias of L</%s>.\n" name;
+          pr "\n";
+          pr "=cut\n\n";
+          pr "sub %s {\n" alias;
+          pr "  &%s (@_)\n" name;
+          pr "}\n";
+          pr "\n";
+          pr "=pod\n";
+          pr "\n";
+      ) non_c_aliases
   ) all_functions_sorted;
 
   pr "=cut\n\n";
@@ -873,6 +892,19 @@ handlers and threads.
   ) all_functions_sorted;
   pr ");\n\n";
 
+  pr "# Add aliases to the introspection hash.\n";
+  let i = ref 0 in
+  List.iter (
+    fun { name = name; non_c_aliases = non_c_aliases } ->
+      List.iter (
+        fun alias ->
+          pr "my %%ielem%d = %%{$guestfs_introspection{%s}};\n" !i name;
+          pr "$guestfs_introspection{%s} = \\%%ielem%d;\n" alias !i;
+          incr i
+      ) non_c_aliases
+  ) all_functions_sorted;
+  pr "\n";
+
   (* End of file. *)
   pr "\
 1;
diff --git a/generator/generator_python.ml b/generator/generator_python.ml
index 548094c..dda0414 100644
--- a/generator/generator_python.ml
+++ b/generator/generator_python.ml
@@ -695,7 +695,7 @@ class GuestFS:
 
   List.iter (
     fun ({ name = name; style = ret, args, optargs; in_docs = in_docs;
-          longdesc = longdesc } as f) ->
+          longdesc = longdesc; non_c_aliases = non_c_aliases } as f) ->
       pr "    def %s (self" name;
       List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
       List.iter (
@@ -750,4 +750,10 @@ class GuestFS:
       List.iter (fun arg -> pr ", %s" (name_of_argt arg))
         (args @ args_of_optargs optargs);
       pr ")\n\n";
+
+      (* Aliases. *)
+      List.iter (
+        fun alias ->
+          pr "    %s = %s\n\n" alias name
+      ) non_c_aliases
   ) all_functions
diff --git a/generator/generator_ruby.ml b/generator/generator_ruby.ml
index f82d90c..7ab2177 100644
--- a/generator/generator_ruby.ml
+++ b/generator/generator_ruby.ml
@@ -633,10 +633,18 @@ void Init__guestfs ()
 
   (* Methods. *)
   List.iter (
-    fun { name = name; style = _, args, optargs } ->
+    fun { name = name; style = _, args, optargs;
+          non_c_aliases = non_c_aliases } ->
       let nr_args = List.length args + if optargs <> [] then 1 else 0 in
       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
-      pr "        ruby_guestfs_%s, %d);\n" name nr_args
+      pr "        ruby_guestfs_%s, %d);\n" name nr_args;
+
+      (* Aliases. *)
+      List.iter (
+        fun alias ->
+          pr "  rb_define_method (c_guestfs, \"%s\",\n" alias;
+          pr "        ruby_guestfs_%s, %d);\n" name nr_args
+      ) non_c_aliases
   ) all_functions;
 
   pr "}\n"
diff --git a/generator/generator_types.ml b/generator/generator_types.ml
index ce7aea3..aeb751c 100644
--- a/generator/generator_types.ml
+++ b/generator/generator_types.ml
@@ -419,6 +419,8 @@ type action = {
   c_function : string;            (* full name of C API function called by
                                      non-C bindings *)
   c_optarg_prefix : string;       (* prefix for optarg names/bitmask names *)
+  non_c_aliases : string list;    (* back-compat aliases that have to be
+                                     generated for this function *)
 }
 
 (* Field types for structures. *)
-- 
1.7.10.4




More information about the Libguestfs mailing list