daemon: Send back the errno as a string.
[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, (ret, args, optargs as style), _, _, _, _, _) ->
93       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
94       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) args;
95       (* XXX This makes the hash mandatory, meaning that you have
96        * to specify {} for no arguments.  We could make it so this
97        * can be omitted.  However that is a load of hassle because
98        * you have to completely change the way that arguments are
99        * passed in.  See:
100        * http://www.redhat.com/archives/libvir-list/2008-April/msg00004.html
101        *)
102       if optargs <> [] then
103         pr ", VALUE optargsv";
104       pr ")\n";
105       pr "{\n";
106       pr "  guestfs_h *g;\n";
107       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
108       pr "  if (!g)\n";
109       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
110         name;
111       pr "\n";
112
113       List.iter (
114         function
115         | Pathname n | Device n | Dev_or_Path n | String n | Key n
116         | FileIn n | FileOut n ->
117             pr "  Check_Type (%sv, T_STRING);\n" n;
118             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
119             pr "  if (!%s)\n" n;
120             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
121             pr "              \"%s\", \"%s\");\n" n name
122         | BufferIn n ->
123             pr "  Check_Type (%sv, T_STRING);\n" n;
124             pr "  const char *%s = RSTRING (%sv)->ptr;\n" n n;
125             pr "  if (!%s)\n" n;
126             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
127             pr "              \"%s\", \"%s\");\n" n name;
128             pr "  size_t %s_size = RSTRING (%sv)->len;\n" n n
129         | OptString n ->
130             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
131         | StringList n | DeviceList n ->
132             pr "  char **%s;\n" n;
133             pr "  Check_Type (%sv, T_ARRAY);\n" n;
134             pr "  {\n";
135             pr "    size_t i, len;\n";
136             pr "    len = RARRAY_LEN (%sv);\n" n;
137             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
138               n;
139             pr "    for (i = 0; i < len; ++i) {\n";
140             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
141             pr "      %s[i] = StringValueCStr (v);\n" n;
142             pr "    }\n";
143             pr "    %s[len] = NULL;\n" n;
144             pr "  }\n";
145         | Bool n ->
146             pr "  int %s = RTEST (%sv);\n" n n
147         | Int n ->
148             pr "  int %s = NUM2INT (%sv);\n" n n
149         | Int64 n ->
150             pr "  long long %s = NUM2LL (%sv);\n" n n
151       ) args;
152       pr "\n";
153
154       (* Optional arguments are passed in a final hash parameter. *)
155       if optargs <> [] then (
156         let uc_name = String.uppercase name in
157         pr "  Check_Type (optargsv, T_HASH);\n";
158         pr "  struct guestfs_%s_argv optargs_s = { .bitmask = 0 };\n" name;
159         pr "  struct guestfs_%s_argv *optargs = &optargs_s;\n" name;
160         pr "  VALUE v;\n";
161         List.iter (
162           fun argt ->
163             let n = name_of_argt argt in
164             let uc_n = String.uppercase n in
165             pr "  v = rb_hash_lookup (optargsv, ID2SYM (rb_intern (\"%s\")));\n" n;
166             pr "  if (v != Qnil) {\n";
167             (match argt with
168              | Bool n ->
169                  pr "    optargs_s.%s = RTEST (v);\n" n;
170              | Int n ->
171                  pr "    optargs_s.%s = NUM2INT (v);\n" n;
172              | Int64 n ->
173                  pr "    optargs_s.%s = NUM2LL (v);\n" n;
174              | String _ ->
175                  pr "    Check_Type (v, T_STRING);\n";
176                  pr "    optargs_s.%s = StringValueCStr (v);\n" n
177              | _ -> assert false
178             );
179             pr "    optargs_s.bitmask |= GUESTFS_%s_%s_BITMASK;\n" uc_name uc_n;
180             pr "  }\n";
181         ) optargs;
182         pr "\n";
183       );
184
185       let error_code =
186         match ret with
187         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
188         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
189         | RConstString _ | RConstOptString _ ->
190             pr "  const char *r;\n"; "NULL"
191         | RString _ -> pr "  char *r;\n"; "NULL"
192         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
193         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
194         | RStructList (_, typ) ->
195             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
196         | RBufferOut _ ->
197             pr "  char *r;\n";
198             pr "  size_t size;\n";
199             "NULL" in
200       pr "\n";
201
202       if optargs = [] then
203         pr "  r = guestfs_%s " name
204       else
205         pr "  r = guestfs_%s_argv " name;
206       generate_c_call_args ~handle:"g" style;
207       pr ";\n";
208
209       List.iter (
210         function
211         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
212         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
213         | BufferIn _ -> ()
214         | StringList n | DeviceList n ->
215             pr "  free (%s);\n" n
216       ) args;
217
218       pr "  if (r == %s)\n" error_code;
219       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
220       pr "\n";
221
222       (match ret with
223        | RErr ->
224            pr "  return Qnil;\n"
225        | RInt _ | RBool _ ->
226            pr "  return INT2NUM (r);\n"
227        | RInt64 _ ->
228            pr "  return ULL2NUM (r);\n"
229        | RConstString _ ->
230            pr "  return rb_str_new2 (r);\n";
231        | RConstOptString _ ->
232            pr "  if (r)\n";
233            pr "    return rb_str_new2 (r);\n";
234            pr "  else\n";
235            pr "    return Qnil;\n";
236        | RString _ ->
237            pr "  VALUE rv = rb_str_new2 (r);\n";
238            pr "  free (r);\n";
239            pr "  return rv;\n";
240        | RStringList _ ->
241            pr "  size_t i, len = 0;\n";
242            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
243            pr "  VALUE rv = rb_ary_new2 (len);\n";
244            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
245            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
246            pr "    free (r[i]);\n";
247            pr "  }\n";
248            pr "  free (r);\n";
249            pr "  return rv;\n"
250        | RStruct (_, typ) ->
251            let cols = cols_of_struct typ in
252            generate_ruby_struct_code typ cols
253        | RStructList (_, typ) ->
254            let cols = cols_of_struct typ in
255            generate_ruby_struct_list_code typ cols
256        | RHashtable _ ->
257            pr "  VALUE rv = rb_hash_new ();\n";
258            pr "  size_t i;\n";
259            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
260            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
261            pr "    free (r[i]);\n";
262            pr "    free (r[i+1]);\n";
263            pr "  }\n";
264            pr "  free (r);\n";
265            pr "  return rv;\n"
266        | RBufferOut _ ->
267            pr "  VALUE rv = rb_str_new (r, size);\n";
268            pr "  free (r);\n";
269            pr "  return rv;\n";
270       );
271
272       pr "}\n";
273       pr "\n"
274   ) all_functions;
275
276   pr "\
277 /* Initialize the module. */
278 void Init__guestfs ()
279 {
280   m_guestfs = rb_define_module (\"Guestfs\");
281   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
282   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
283
284 #ifdef HAVE_RB_DEFINE_ALLOC_FUNC
285   rb_define_alloc_func (c_guestfs, ruby_guestfs_create);
286 #endif
287
288   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
289   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
290
291 ";
292   (* Define the rest of the methods. *)
293   List.iter (
294     fun (name, (_, args, optargs), _, _, _, _, _) ->
295       let nr_args = List.length args + if optargs <> [] then 1 else 0 in
296       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
297       pr "        ruby_guestfs_%s, %d);\n" name nr_args
298   ) all_functions;
299
300   pr "}\n"
301
302 (* Ruby code to return a struct. *)
303 and generate_ruby_struct_code typ cols =
304   pr "  VALUE rv = rb_hash_new ();\n";
305   List.iter (
306     function
307     | name, FString ->
308         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
309     | name, FBuffer ->
310         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
311     | name, FUUID ->
312         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
313     | name, (FBytes|FUInt64) ->
314         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
315     | name, FInt64 ->
316         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
317     | name, FUInt32 ->
318         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
319     | name, FInt32 ->
320         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
321     | name, FOptPercent ->
322         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
323     | name, FChar -> (* XXX wrong? *)
324         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
325   ) cols;
326   pr "  guestfs_free_%s (r);\n" typ;
327   pr "  return rv;\n"
328
329 (* Ruby code to return a struct list. *)
330 and generate_ruby_struct_list_code typ cols =
331   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
332   pr "  size_t i;\n";
333   pr "  for (i = 0; i < r->len; ++i) {\n";
334   pr "    VALUE hv = rb_hash_new ();\n";
335   List.iter (
336     function
337     | name, FString ->
338         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
339     | name, FBuffer ->
340         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
341     | name, FUUID ->
342         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
343     | name, (FBytes|FUInt64) ->
344         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
345     | name, FInt64 ->
346         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
347     | name, FUInt32 ->
348         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
349     | name, FInt32 ->
350         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
351     | name, FOptPercent ->
352         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
353     | name, FChar -> (* XXX wrong? *)
354         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
355   ) cols;
356   pr "    rb_ary_push (rv, hv);\n";
357   pr "  }\n";
358   pr "  guestfs_free_%s_list (r);\n" typ;
359   pr "  return rv;\n"