summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Jones <rich@koneko.local>2010-01-02 19:46:20 +0000
committerRichard Jones <rjones@redhat.com>2010-01-02 21:55:17 +0000
commitc0e4b5dc693cefdc81a4ec7cc1073a2cae371803 (patch)
tree07cc21debde09942704b9faa0589ff5840c997b7
parentd3c615c2d6167e6f0ae4d23b2902ea08a66a11ae (diff)
downloadlibguestfs-c0e4b5dc693cefdc81a4ec7cc1073a2cae371803.tar.gz
libguestfs-c0e4b5dc693cefdc81a4ec7cc1073a2cae371803.tar.xz
libguestfs-c0e4b5dc693cefdc81a4ec7cc1073a2cae371803.zip
Experimental C# bindings.
Tested in only limited situations, with Mono on Linux.
-rw-r--r--HACKING3
-rw-r--r--README5
-rw-r--r--src/Makefile.am1
-rwxr-xr-xsrc/generator.ml222
4 files changed, 224 insertions, 7 deletions
diff --git a/HACKING b/HACKING
index 9cc16c3e..7dbc360e 100644
--- a/HACKING
+++ b/HACKING
@@ -74,6 +74,9 @@ capitests/
contrib/
Outside contributions, experimental parts.
+csharp/
+ Experimental C# bindings.
+
daemon/
The daemon that runs inside the guest and carries out actions.
diff --git a/README b/README
index 8e8be596..ad04884b 100644
--- a/README
+++ b/README
@@ -16,8 +16,9 @@ LVs, what filesystem is in each LV, etc.). It can also run commands
in the context of the guest. Also you can access filesystems over FTP.
Libguestfs is a library that can be linked with C and C++ management
-programs (or management programs written in OCaml, Perl, Python, Ruby, Java
-or Haskell). You can also use it from shell scripts or the command line.
+programs (or management programs written in OCaml, Perl, Python, Ruby,
+Java, Haskell or C#). You can also use it from shell scripts or the
+command line.
Libguestfs was written by Richard W.M. Jones (rjones@redhat.com) and
hacked on by lots of other people. For discussion, development,
diff --git a/src/Makefile.am b/src/Makefile.am
index 7d9220a7..619f46ef 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -52,6 +52,7 @@ stamp-generator: generator.ml
mkdir -p $(top_srcdir)/perl/lib/Sys
mkdir -p $(top_srcdir)/ruby/ext/guestfs
mkdir -p $(top_srcdir)/java/com/redhat/et/libguestfs
+ mkdir -p $(top_srcdir)/csharp
cd $(top_srcdir) && ocaml -warn-error A src/generator.ml
include_HEADERS = guestfs.h guestfs-actions.h guestfs-structs.h
diff --git a/src/generator.ml b/src/generator.ml
index dc0c9c14..3bc8d6f1 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -4815,16 +4815,18 @@ let copyright_years =
if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
(* Generate a header block in a number of standard styles. *)
-type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
+type comment_style =
+ CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
type license = GPLv2plus | LGPLv2plus
let generate_header ?(extra_inputs = []) comment license =
let inputs = "src/generator.ml" :: extra_inputs in
let c = match comment with
- | CStyle -> pr "/* "; " *"
- | HashStyle -> pr "# "; "#"
- | OCamlStyle -> pr "(* "; " *"
- | HaskellStyle -> pr "{- "; " " in
+ | CStyle -> pr "/* "; " *"
+ | CPlusPlusStyle -> pr "// "; "//"
+ | HashStyle -> pr "# "; "#"
+ | OCamlStyle -> pr "(* "; " *"
+ | HaskellStyle -> pr "{- "; " " in
pr "libguestfs generated file\n";
pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
List.iter (pr "%s %s\n" c) inputs;
@@ -4865,6 +4867,7 @@ let generate_header ?(extra_inputs = []) comment license =
);
(match comment with
| CStyle -> pr " */\n"
+ | CPlusPlusStyle
| HashStyle -> ()
| OCamlStyle -> pr " *)\n"
| HaskellStyle -> pr "-}\n"
@@ -9918,6 +9921,214 @@ and generate_haskell_prototype ~handle ?(hs = false) style =
);
pr ")"
+and generate_csharp () =
+ generate_header CPlusPlusStyle LGPLv2plus;
+
+ (* XXX Make this configurable by the C# assembly users. *)
+ let library = "libguestfs.so.0" in
+
+ pr "\
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Collections;
+
+namespace Guestfs
+{
+ class Error : System.ApplicationException
+ {
+ public Error (string message) : base (message) {}
+ protected Error (SerializationInfo info, StreamingContext context) {}
+ }
+
+ class Guestfs
+ {
+ IntPtr _handle;
+
+ [DllImport (\"%s\")]
+ static extern IntPtr guestfs_create ();
+
+ public Guestfs ()
+ {
+ _handle = guestfs_create ();
+ if (_handle == IntPtr.Zero)
+ throw new Error (\"could not create guestfs handle\");
+ }
+
+ [DllImport (\"%s\")]
+ static extern void guestfs_close (IntPtr h);
+
+ ~Guestfs ()
+ {
+ guestfs_close (_handle);
+ }
+
+ [DllImport (\"%s\")]
+ static extern string guestfs_last_error (IntPtr h);
+
+" library library library;
+
+ (* Generate C# structure bindings. We prefix struct names with
+ * underscore because C# cannot have conflicting struct names and
+ * method names (eg. "class stat" and "stat").
+ *)
+ List.iter (
+ fun (typ, cols) ->
+ pr " [StructLayout (LayoutKind.Sequential)]\n";
+ pr " public class _%s {\n" typ;
+ List.iter (
+ function
+ | name, FChar -> pr " char %s;\n" name
+ | name, FString -> pr " string %s;\n" name
+ | name, FBuffer ->
+ pr " uint %s_len;\n" name;
+ pr " string %s;\n" name
+ | name, FUUID ->
+ pr " [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
+ pr " string %s;\n" name
+ | name, FUInt32 -> pr " uint %s;\n" name
+ | name, FInt32 -> pr " int %s;\n" name
+ | name, (FUInt64|FBytes) -> pr " ulong %s;\n" name
+ | name, FInt64 -> pr " long %s;\n" name
+ | name, FOptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
+ ) cols;
+ pr " }\n";
+ pr "\n"
+ ) structs;
+
+ (* Generate C# function bindings. *)
+ List.iter (
+ fun (name, style, _, _, _, shortdesc, _) ->
+ let rec csharp_return_type () =
+ match fst style with
+ | RErr -> "void"
+ | RBool n -> "bool"
+ | RInt n -> "int"
+ | RInt64 n -> "long"
+ | RConstString n
+ | RConstOptString n
+ | RString n
+ | RBufferOut n -> "string"
+ | RStruct (_,n) -> "_" ^ n
+ | RHashtable n -> "Hashtable"
+ | RStringList n -> "string[]"
+ | RStructList (_,n) -> sprintf "_%s[]" n
+
+ and c_return_type () =
+ match fst style with
+ | RErr
+ | RBool _
+ | RInt _ -> "int"
+ | RInt64 _ -> "long"
+ | RConstString _
+ | RConstOptString _
+ | RString _
+ | RBufferOut _ -> "string"
+ | RStruct (_,n) -> "_" ^ n
+ | RHashtable _
+ | RStringList _ -> "string[]"
+ | RStructList (_,n) -> sprintf "_%s[]" n
+
+ and c_error_comparison () =
+ match fst style with
+ | RErr
+ | RBool _
+ | RInt _
+ | RInt64 _ -> "== -1"
+ | RConstString _
+ | RConstOptString _
+ | RString _
+ | RBufferOut _
+ | RStruct (_,_)
+ | RHashtable _
+ | RStringList _
+ | RStructList (_,_) -> "== null"
+
+ and generate_extern_prototype () =
+ pr " static extern %s guestfs_%s (IntPtr h"
+ (c_return_type ()) name;
+ List.iter (
+ function
+ | Pathname n | Device n | Dev_or_Path n | String n | OptString n
+ | FileIn n | FileOut n ->
+ pr ", [In] string %s" n
+ | StringList n | DeviceList n ->
+ pr ", [In] string[] %s" n
+ | Bool n ->
+ pr ", bool %s" n
+ | Int n ->
+ pr ", int %s" n
+ | Int64 n ->
+ pr ", long %s" n
+ ) (snd style);
+ pr ");\n"
+
+ and generate_public_prototype () =
+ pr " public %s %s (" (csharp_return_type ()) name;
+ let comma = ref false in
+ let next () =
+ if !comma then pr ", ";
+ comma := true
+ in
+ List.iter (
+ function
+ | Pathname n | Device n | Dev_or_Path n | String n | OptString n
+ | FileIn n | FileOut n ->
+ next (); pr "string %s" n
+ | StringList n | DeviceList n ->
+ next (); pr "string[] %s" n
+ | Bool n ->
+ next (); pr "bool %s" n
+ | Int n ->
+ next (); pr "int %s" n
+ | Int64 n ->
+ next (); pr "long %s" n
+ ) (snd style);
+ pr ")\n"
+
+ and generate_call () =
+ pr "guestfs_%s (_handle" name;
+ List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
+ 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 ();
+ pr " {\n";
+ pr " %s r;\n" (c_return_type ());
+ pr " r = ";
+ generate_call ();
+ pr " if (r %s)\n" (c_error_comparison ());
+ pr " throw new Error (\"%s: \" + guestfs_last_error (_handle));\n"
+ name;
+ (match fst style with
+ | RErr -> ()
+ | RBool _ ->
+ pr " return r != 0 ? true : false;\n"
+ | RHashtable _ ->
+ pr " Hashtable rr = new Hashtable ();\n";
+ pr " for (int i = 0; i < r.Length; i += 2)\n";
+ pr " rr.Add (r[i], r[i+1]);\n";
+ pr " return rr;\n"
+ | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
+ | RString _ | RBufferOut _ | RStruct _ | RStringList _
+ | RStructList _ ->
+ pr " return r;\n"
+ );
+ pr " }\n";
+ pr "\n";
+ ) all_functions_sorted;
+
+ pr " }
+}
+"
+
and generate_bindtests () =
generate_header CStyle LGPLv2plus;
@@ -10924,6 +11135,7 @@ Run it from the top source directory using the command
output_to "java/Bindtests.java" generate_java_bindtests;
output_to "haskell/Guestfs.hs" generate_haskell_hs;
output_to "haskell/Bindtests.hs" generate_haskell_bindtests;
+ output_to "csharp/Libguestfs.cs" generate_csharp;
output_to "src/MAX_PROC_NR" generate_max_proc_nr;
(* Always generate this file last, and unconditionally. It's used