From c0e4b5dc693cefdc81a4ec7cc1073a2cae371803 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Sat, 2 Jan 2010 19:46:20 +0000 Subject: [PATCH] Experimental C# bindings. Tested in only limited situations, with Mono on Linux. --- HACKING | 3 + README | 5 +- src/Makefile.am | 1 + src/generator.ml | 222 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 224 insertions(+), 7 deletions(-) diff --git a/HACKING b/HACKING index 9cc16c3..7dbc360 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 8e8be59..ad04884 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 7d9220a..619f46e 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 dc0c9c1..3bc8d6f 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 " /// \n"; + pr " /// %s\n" shortdesc; + pr " /// \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 -- 1.8.3.1