todo: Add note about using blktrace.
[libguestfs.git] / generator / generator_ruby.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 open Generator_c
31
32 (* Generate ruby bindings. *)
33 let rec generate_ruby_c () =
34   generate_header CStyle LGPLv2plus;
35
36   pr "\
37 #include <stdio.h>
38 #include <stdlib.h>
39
40 #include <ruby.h>
41
42 #include \"guestfs.h\"
43
44 #include \"extconf.h\"
45
46 /* For Ruby < 1.9 */
47 #ifndef RARRAY_LEN
48 #define RARRAY_LEN(r) (RARRAY((r))->len)
49 #endif
50
51 static VALUE m_guestfs;                 /* guestfs module */
52 static VALUE c_guestfs;                 /* guestfs_h handle */
53 static VALUE e_Error;                   /* used for all errors */
54
55 static void ruby_guestfs_free (void *p)
56 {
57   if (!p) return;
58   guestfs_close ((guestfs_h *) p);
59 }
60
61 static VALUE ruby_guestfs_create (VALUE m)
62 {
63   guestfs_h *g;
64
65   g = guestfs_create ();
66   if (!g)
67     rb_raise (e_Error, \"failed to create guestfs handle\");
68
69   /* Don't print error messages to stderr by default. */
70   guestfs_set_error_handler (g, NULL, NULL);
71
72   /* Wrap it, and make sure the close function is called when the
73    * handle goes away.
74    */
75   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
76 }
77
78 static VALUE ruby_guestfs_close (VALUE gv)
79 {
80   guestfs_h *g;
81   Data_Get_Struct (gv, guestfs_h, g);
82
83   ruby_guestfs_free (g);
84   DATA_PTR (gv) = NULL;
85
86   return Qnil;
87 }
88
89 ";
90
91   List.iter (
92     fun (name, style, _, _, _, _, _) ->
93       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
94       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
95       pr ")\n";
96       pr "{\n";
97       pr "  guestfs_h *g;\n";
98       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
99       pr "  if (!g)\n";
100       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
101         name;
102       pr "\n";
103
104       List.iter (
105         function
106         | Pathname n | Device n | Dev_or_Path n | String n | Key n
107         | FileIn n | FileOut n ->
108             pr "  Check_Type (%sv, T_STRING);\n" n;
109             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
110             pr "  if (!%s)\n" n;
111             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
112             pr "              \"%s\", \"%s\");\n" n name
113         | BufferIn n ->
114             pr "  Check_Type (%sv, T_STRING);\n" n;
115             pr "  const char *%s = RSTRING (%sv)->ptr;\n" n n;
116             pr "  if (!%s)\n" n;
117             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
118             pr "              \"%s\", \"%s\");\n" n name;
119             pr "  size_t %s_size = RSTRING (%sv)->len;\n" n n
120         | OptString n ->
121             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
122         | StringList n | DeviceList n ->
123             pr "  char **%s;\n" n;
124             pr "  Check_Type (%sv, T_ARRAY);\n" n;
125             pr "  {\n";
126             pr "    size_t i, len;\n";
127             pr "    len = RARRAY_LEN (%sv);\n" n;
128             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
129               n;
130             pr "    for (i = 0; i < len; ++i) {\n";
131             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
132             pr "      %s[i] = StringValueCStr (v);\n" n;
133             pr "    }\n";
134             pr "    %s[len] = NULL;\n" n;
135             pr "  }\n";
136         | Bool n ->
137             pr "  int %s = RTEST (%sv);\n" n n
138         | Int n ->
139             pr "  int %s = NUM2INT (%sv);\n" n n
140         | Int64 n ->
141             pr "  long long %s = NUM2LL (%sv);\n" n n
142       ) (snd style);
143       pr "\n";
144
145       let error_code =
146         match fst style with
147         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
148         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
149         | RConstString _ | RConstOptString _ ->
150             pr "  const char *r;\n"; "NULL"
151         | RString _ -> pr "  char *r;\n"; "NULL"
152         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
153         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
154         | RStructList (_, typ) ->
155             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
156         | RBufferOut _ ->
157             pr "  char *r;\n";
158             pr "  size_t size;\n";
159             "NULL" in
160       pr "\n";
161
162       pr "  r = guestfs_%s " name;
163       generate_c_call_args ~handle:"g" style;
164       pr ";\n";
165
166       List.iter (
167         function
168         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
169         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
170         | BufferIn _ -> ()
171         | StringList n | DeviceList n ->
172             pr "  free (%s);\n" n
173       ) (snd style);
174
175       pr "  if (r == %s)\n" error_code;
176       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
177       pr "\n";
178
179       (match fst style with
180        | RErr ->
181            pr "  return Qnil;\n"
182        | RInt _ | RBool _ ->
183            pr "  return INT2NUM (r);\n"
184        | RInt64 _ ->
185            pr "  return ULL2NUM (r);\n"
186        | RConstString _ ->
187            pr "  return rb_str_new2 (r);\n";
188        | RConstOptString _ ->
189            pr "  if (r)\n";
190            pr "    return rb_str_new2 (r);\n";
191            pr "  else\n";
192            pr "    return Qnil;\n";
193        | RString _ ->
194            pr "  VALUE rv = rb_str_new2 (r);\n";
195            pr "  free (r);\n";
196            pr "  return rv;\n";
197        | RStringList _ ->
198            pr "  size_t i, len = 0;\n";
199            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
200            pr "  VALUE rv = rb_ary_new2 (len);\n";
201            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
202            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
203            pr "    free (r[i]);\n";
204            pr "  }\n";
205            pr "  free (r);\n";
206            pr "  return rv;\n"
207        | RStruct (_, typ) ->
208            let cols = cols_of_struct typ in
209            generate_ruby_struct_code typ cols
210        | RStructList (_, typ) ->
211            let cols = cols_of_struct typ in
212            generate_ruby_struct_list_code typ cols
213        | RHashtable _ ->
214            pr "  VALUE rv = rb_hash_new ();\n";
215            pr "  size_t i;\n";
216            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
217            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
218            pr "    free (r[i]);\n";
219            pr "    free (r[i+1]);\n";
220            pr "  }\n";
221            pr "  free (r);\n";
222            pr "  return rv;\n"
223        | RBufferOut _ ->
224            pr "  VALUE rv = rb_str_new (r, size);\n";
225            pr "  free (r);\n";
226            pr "  return rv;\n";
227       );
228
229       pr "}\n";
230       pr "\n"
231   ) all_functions;
232
233   pr "\
234 /* Initialize the module. */
235 void Init__guestfs ()
236 {
237   m_guestfs = rb_define_module (\"Guestfs\");
238   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
239   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
240
241 #ifdef HAVE_RB_DEFINE_ALLOC_FUNC
242   rb_define_alloc_func (c_guestfs, ruby_guestfs_create);
243 #endif
244
245   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
246   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
247
248 ";
249   (* Define the rest of the methods. *)
250   List.iter (
251     fun (name, style, _, _, _, _, _) ->
252       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
253       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
254   ) all_functions;
255
256   pr "}\n"
257
258 (* Ruby code to return a struct. *)
259 and generate_ruby_struct_code typ cols =
260   pr "  VALUE rv = rb_hash_new ();\n";
261   List.iter (
262     function
263     | name, FString ->
264         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
265     | name, FBuffer ->
266         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
267     | name, FUUID ->
268         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
269     | name, (FBytes|FUInt64) ->
270         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
271     | name, FInt64 ->
272         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
273     | name, FUInt32 ->
274         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
275     | name, FInt32 ->
276         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
277     | name, FOptPercent ->
278         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
279     | name, FChar -> (* XXX wrong? *)
280         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
281   ) cols;
282   pr "  guestfs_free_%s (r);\n" typ;
283   pr "  return rv;\n"
284
285 (* Ruby code to return a struct list. *)
286 and generate_ruby_struct_list_code typ cols =
287   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
288   pr "  size_t i;\n";
289   pr "  for (i = 0; i < r->len; ++i) {\n";
290   pr "    VALUE hv = rb_hash_new ();\n";
291   List.iter (
292     function
293     | name, FString ->
294         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
295     | name, FBuffer ->
296         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, r->val[i].%s_len));\n" name name name
297     | name, FUUID ->
298         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
299     | name, (FBytes|FUInt64) ->
300         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
301     | name, FInt64 ->
302         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
303     | name, FUInt32 ->
304         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
305     | name, FInt32 ->
306         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
307     | name, FOptPercent ->
308         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
309     | name, FChar -> (* XXX wrong? *)
310         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
311   ) cols;
312   pr "    rb_ary_push (rv, hv);\n";
313   pr "  }\n";
314   pr "  guestfs_free_%s_list (r);\n" typ;
315   pr "  return rv;\n"