1b2672b5d34c7c930c4d7918239779171e4823f7
[libguestfs.git] / generator / generator_csharp.ml
1 (* libguestfs
2  * Copyright (C) 2009-2010 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *)
18
19 (* Please read generator/README first. *)
20
21 open Printf
22
23 open Generator_types
24 open Generator_utils
25 open Generator_pr
26 open Generator_docstrings
27 open Generator_optgroups
28 open Generator_actions
29 open Generator_structs
30
31 let rec generate_csharp () =
32   generate_header CPlusPlusStyle LGPLv2plus;
33
34   (* XXX Make this configurable by the C# assembly users. *)
35   let library = "libguestfs.so.0" in
36
37   pr "\
38 // These C# bindings are highly experimental at present.
39 //
40 // Firstly they only work on Linux (ie. Mono).  In order to get them
41 // to work on Windows (ie. .Net) you would need to port the library
42 // itself to Windows first.
43 //
44 // The second issue is that some calls are known to be incorrect and
45 // can cause Mono to segfault.  Particularly: calls which pass or
46 // return string[], or return any structure value.  This is because
47 // we haven't worked out the correct way to do this from C#.
48 //
49 // The third issue is that when compiling you get a lot of warnings.
50 // We are not sure whether the warnings are important or not.
51 //
52 // Fourthly we do not routinely build or test these bindings as part
53 // of the make && make check cycle, which means that regressions might
54 // go unnoticed.
55 //
56 // Suggestions and patches are welcome.
57
58 // To compile:
59 //
60 // gmcs Libguestfs.cs
61 // mono Libguestfs.exe
62 //
63 // (You'll probably want to add a Test class / static main function
64 // otherwise this won't do anything useful).
65
66 using System;
67 using System.IO;
68 using System.Runtime.InteropServices;
69 using System.Runtime.Serialization;
70 using System.Collections;
71
72 namespace Guestfs
73 {
74   class Error : System.ApplicationException
75   {
76     public Error (string message) : base (message) {}
77     protected Error (SerializationInfo info, StreamingContext context) {}
78   }
79
80   class Guestfs
81   {
82     IntPtr _handle;
83
84     [DllImport (\"%s\")]
85     static extern IntPtr guestfs_create ();
86
87     public Guestfs ()
88     {
89       _handle = guestfs_create ();
90       if (_handle == IntPtr.Zero)
91         throw new Error (\"could not create guestfs handle\");
92     }
93
94     [DllImport (\"%s\")]
95     static extern void guestfs_close (IntPtr h);
96
97     ~Guestfs ()
98     {
99       guestfs_close (_handle);
100     }
101
102     [DllImport (\"%s\")]
103     static extern string guestfs_last_error (IntPtr h);
104
105 " library library library;
106
107   (* Generate C# structure bindings.  We prefix struct names with
108    * underscore because C# cannot have conflicting struct names and
109    * method names (eg. "class stat" and "stat").
110    *)
111   List.iter (
112     fun (typ, cols) ->
113       pr "    [StructLayout (LayoutKind.Sequential)]\n";
114       pr "    public class _%s {\n" typ;
115       List.iter (
116         function
117         | name, FChar -> pr "      char %s;\n" name
118         | name, FString -> pr "      string %s;\n" name
119         | name, FBuffer ->
120             pr "      uint %s_len;\n" name;
121             pr "      string %s;\n" name
122         | name, FUUID ->
123             pr "      [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
124             pr "      string %s;\n" name
125         | name, FUInt32 -> pr "      uint %s;\n" name
126         | name, FInt32 -> pr "      int %s;\n" name
127         | name, (FUInt64|FBytes) -> pr "      ulong %s;\n" name
128         | name, FInt64 -> pr "      long %s;\n" name
129         | name, FOptPercent -> pr "      float %s; /* [0..100] or -1 */\n" name
130       ) cols;
131       pr "    }\n";
132       pr "\n"
133   ) structs;
134
135   (* Generate C# function bindings. *)
136   List.iter (
137     fun (name, style, _, _, _, shortdesc, _) ->
138       let rec csharp_return_type () =
139         match fst style with
140         | RErr -> "void"
141         | RBool n -> "bool"
142         | RInt n -> "int"
143         | RInt64 n -> "long"
144         | RConstString n
145         | RConstOptString n
146         | RString n
147         | RBufferOut n -> "string"
148         | RStruct (_,n) -> "_" ^ n
149         | RHashtable n -> "Hashtable"
150         | RStringList n -> "string[]"
151         | RStructList (_,n) -> sprintf "_%s[]" n
152
153       and c_return_type () =
154         match fst style with
155         | RErr
156         | RBool _
157         | RInt _ -> "int"
158         | RInt64 _ -> "long"
159         | RConstString _
160         | RConstOptString _
161         | RString _
162         | RBufferOut _ -> "string"
163         | RStruct (_,n) -> "_" ^ n
164         | RHashtable _
165         | RStringList _ -> "string[]"
166         | RStructList (_,n) -> sprintf "_%s[]" n
167
168       and c_error_comparison () =
169         match fst style with
170         | RErr
171         | RBool _
172         | RInt _
173         | RInt64 _ -> "== -1"
174         | RConstString _
175         | RConstOptString _
176         | RString _
177         | RBufferOut _
178         | RStruct (_,_)
179         | RHashtable _
180         | RStringList _
181         | RStructList (_,_) -> "== null"
182
183       and generate_extern_prototype () =
184         pr "    static extern %s guestfs_%s (IntPtr h"
185           (c_return_type ()) name;
186         List.iter (
187           function
188           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
189           | FileIn n | FileOut n
190           | Key n
191           | BufferIn n ->
192               pr ", [In] string %s" n
193           | StringList n | DeviceList n ->
194               pr ", [In] string[] %s" n
195           | Bool n ->
196               pr ", bool %s" n
197           | Int n ->
198               pr ", int %s" n
199           | Int64 n ->
200               pr ", long %s" n
201         ) (snd style);
202         pr ");\n"
203
204       and generate_public_prototype () =
205         pr "    public %s %s (" (csharp_return_type ()) name;
206         let comma = ref false in
207         let next () =
208           if !comma then pr ", ";
209           comma := true
210         in
211         List.iter (
212           function
213           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
214           | FileIn n | FileOut n
215           | Key n
216           | BufferIn n ->
217               next (); pr "string %s" n
218           | StringList n | DeviceList n ->
219               next (); pr "string[] %s" n
220           | Bool n ->
221               next (); pr "bool %s" n
222           | Int n ->
223               next (); pr "int %s" n
224           | Int64 n ->
225               next (); pr "long %s" n
226         ) (snd style);
227         pr ")\n"
228
229       and generate_call () =
230         pr "guestfs_%s (_handle" name;
231         List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
232         pr ");\n";
233       in
234
235       pr "    [DllImport (\"%s\")]\n" library;
236       generate_extern_prototype ();
237       pr "\n";
238       pr "    /// <summary>\n";
239       pr "    /// %s\n" shortdesc;
240       pr "    /// </summary>\n";
241       generate_public_prototype ();
242       pr "    {\n";
243       pr "      %s r;\n" (c_return_type ());
244       pr "      r = ";
245       generate_call ();
246       pr "      if (r %s)\n" (c_error_comparison ());
247       pr "        throw new Error (guestfs_last_error (_handle));\n";
248       (match fst style with
249        | RErr -> ()
250        | RBool _ ->
251            pr "      return r != 0 ? true : false;\n"
252        | RHashtable _ ->
253            pr "      Hashtable rr = new Hashtable ();\n";
254            pr "      for (size_t i = 0; i < r.Length; i += 2)\n";
255            pr "        rr.Add (r[i], r[i+1]);\n";
256            pr "      return rr;\n"
257        | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
258        | RString _ | RBufferOut _ | RStruct _ | RStringList _
259        | RStructList _ ->
260            pr "      return r;\n"
261       );
262       pr "    }\n";
263       pr "\n";
264   ) all_functions_sorted;
265
266   pr "  }
267 }
268 "