X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=generator%2Fgenerator_ruby.ml;h=7c8788d04895c679fbde910144914a288f4c04d3;hb=9b60f3a9f3b38c085e9265e56ddb839dabe6e416;hp=b237c7f0da77d59fd2341f645525a7b959bcddd3;hpb=6a64114929a0b098f5a1e31e17e7802127925007;p=libguestfs.git diff --git a/generator/generator_ruby.ml b/generator/generator_ruby.ml index b237c7f..7c8788d 100644 --- a/generator/generator_ruby.ml +++ b/generator/generator_ruby.ml @@ -55,9 +55,12 @@ static VALUE c_guestfs; /* guestfs_h handle */ static VALUE e_Error; /* used for all errors */ static void ruby_event_callback_wrapper (guestfs_h *g, void *data, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len); +static VALUE ruby_event_callback_wrapper_wrapper (VALUE argv); +static VALUE ruby_event_callback_handle_exception (VALUE not_used, VALUE exn); static VALUE **get_all_event_callbacks (guestfs_h *g, size_t *len_rtn); -static void ruby_guestfs_free (void *gvp) +static void +ruby_guestfs_free (void *gvp) { guestfs_h *g = gvp; @@ -84,7 +87,17 @@ static void ruby_guestfs_free (void *gvp) } } -static VALUE ruby_guestfs_create (VALUE m) +/* + * call-seq: + * Guestfs::Guestfs.new() -> Guestfs::Guestfs + * + * Call + * +guestfs_create+[http://libguestfs.org/guestfs.3.html#guestfs_create] + * to create a new libguestfs handle. The handle is represented in + * Ruby as an instance of the Guestfs::Guestfs class. + */ +static VALUE +ruby_guestfs_create (VALUE m) { guestfs_h *g; @@ -101,7 +114,16 @@ static VALUE ruby_guestfs_create (VALUE m) return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g); } -static VALUE ruby_guestfs_close (VALUE gv) +/* + * call-seq: + * g.close() -> nil + * + * Call + * +guestfs_close+[http://libguestfs.org/guestfs.3.html#guestfs_close] + * to close the libguestfs handle. + */ +static VALUE +ruby_guestfs_close (VALUE gv) { guestfs_h *g; Data_Get_Struct (gv, guestfs_h, g); @@ -112,6 +134,14 @@ static VALUE ruby_guestfs_close (VALUE gv) return Qnil; } +/* + * call-seq: + * g.set_event_callback(cb, event_bitmask) -> event_handle + * + * Call + * +guestfs_set_event_callback+[http://libguestfs.org/guestfs.3.html#guestfs_set_event_callback] + * to register an event callback. This returns an event handle. + */ static VALUE ruby_set_event_callback (VALUE gv, VALUE cbv, VALUE event_bitmaskv) { @@ -143,6 +173,14 @@ ruby_set_event_callback (VALUE gv, VALUE cbv, VALUE event_bitmaskv) return INT2NUM (eh); } +/* + * call-seq: + * g.delete_event_callback(event_handle) -> nil + * + * Call + * +guestfs_delete_event_callback+[http://libguestfs.org/guestfs.3.html#guestfs_delete_event_callback] + * to delete an event callback. + */ static VALUE ruby_delete_event_callback (VALUE gv, VALUE event_handlev) { @@ -176,7 +214,7 @@ ruby_event_callback_wrapper (guestfs_h *g, const uint64_t *array, size_t array_len) { size_t i; - VALUE eventv, event_handlev, bufv, arrayv; + VALUE eventv, event_handlev, bufv, arrayv, argv; eventv = ULL2NUM (event); event_handlev = INT2NUM (event_handle); @@ -187,12 +225,49 @@ ruby_event_callback_wrapper (guestfs_h *g, for (i = 0; i < array_len; ++i) rb_ary_push (arrayv, ULL2NUM (array[i])); - /* XXX If the Ruby callback raises any sort of exception then - * it causes the process to segfault. I don't understand how - * to catch exceptions here. + /* Wrap up the arguments in an array which will be unpacked + * and passed as multiple arguments. This is a crap limitation + * of rb_rescue. + * http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/~poffice/mail/ruby-talk/65698 */ - rb_funcall (*(VALUE *) data, rb_intern (\"call\"), 4, + argv = rb_ary_new2 (5); + rb_ary_store (argv, 0, * (VALUE *) data /* function */); + rb_ary_store (argv, 1, eventv); + rb_ary_store (argv, 2, event_handlev); + rb_ary_store (argv, 3, bufv); + rb_ary_store (argv, 4, arrayv); + + rb_rescue (ruby_event_callback_wrapper_wrapper, argv, + ruby_event_callback_handle_exception, Qnil); +} + +static VALUE +ruby_event_callback_wrapper_wrapper (VALUE argv) +{ + VALUE fn, eventv, event_handlev, bufv, arrayv; + + fn = rb_ary_entry (argv, 0); + eventv = rb_ary_entry (argv, 1); + event_handlev = rb_ary_entry (argv, 2); + bufv = rb_ary_entry (argv, 3); + arrayv = rb_ary_entry (argv, 4); + + rb_funcall (fn, rb_intern (\"call\"), 4, eventv, event_handlev, bufv, arrayv); + + return Qnil; +} + +static VALUE +ruby_event_callback_handle_exception (VALUE not_used, VALUE exn) +{ + /* Callbacks aren't supposed to throw exceptions. The best we + * can do is to print the error. + */ + fprintf (stderr, \"libguestfs: exception in callback: %%s\", + StringValueCStr (exn)); + + return Qnil; } static VALUE ** @@ -231,8 +306,67 @@ get_all_event_callbacks (guestfs_h *g, size_t *len_rtn) "; List.iter ( - fun (name, (ret, args, optargs as style), _, _, _, _, _) -> - pr "static VALUE ruby_guestfs_%s (VALUE gv" name; + fun (name, (ret, args, optargs as style), _, flags, _, shortdesc, longdesc) -> + (* Generate rdoc. *) + if not (List.mem NotInDocs flags); then ( + let doc = replace_str longdesc "C [] then + doc ^ "\n\nOptional arguments are supplied in the final hash parameter, which is a hash of the argument name to its value. Pass an empty {} for no optional arguments." + else doc in + let doc = + if List.mem ProtocolLimitWarning flags then + doc ^ "\n\n" ^ protocol_limit_warning + else doc in + let doc = + if List.mem DangerWillRobinson flags then + doc ^ "\n\n" ^ danger_will_robinson + else doc in + let doc = + match deprecation_notice flags with + | None -> doc + | Some txt -> doc ^ "\n\n" ^ txt in + let doc = pod2text ~width:60 name doc in + let doc = String.concat "\n * " doc in + let doc = trim doc in + + let args = List.map name_of_argt args in + let args = if optargs <> [] then args @ ["{optargs...}"] else args in + let args = String.concat ", " args in + + let ret = + match ret with + | RErr -> "nil" + | RBool _ -> "[True|False]" + | RInt _ -> "fixnum" + | RInt64 _ -> "fixnum" + | RConstString _ -> "string" + | RConstOptString _ -> "string" + | RString _ -> "string" + | RBufferOut _ -> "string" + | RStruct _ + | RHashtable _ -> "hash" + | RStringList _ + | RStructList _ -> "list" in + + pr "\ +/* + * call-seq: + * g.%s(%s) -> %s + * + * %s + * + * %s + * + * (For the C API documentation for this function, see + * +guestfs_%s+[http://libguestfs.org/guestfs.3.html#guestfs_%s]). + */ +" name args ret shortdesc doc name name + ); + + (* Generate the function. *) + pr "static VALUE\n"; + pr "ruby_guestfs_%s (VALUE gv" name; List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) args; (* XXX This makes the hash mandatory, meaning that you have * to specify {} for no arguments. We could make it so this @@ -256,11 +390,7 @@ get_all_event_callbacks (guestfs_h *g, size_t *len_rtn) function | Pathname n | Device n | Dev_or_Path n | String n | Key n | FileIn n | FileOut n -> - pr " Check_Type (%sv, T_STRING);\n" n; pr " const char *%s = StringValueCStr (%sv);\n" n n; - pr " if (!%s)\n" n; - pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n"; - pr " \"%s\", \"%s\");\n" n name | BufferIn n -> pr " Check_Type (%sv, T_STRING);\n" n; pr " const char *%s = RSTRING (%sv)->ptr;\n" n n; @@ -276,7 +406,7 @@ get_all_event_callbacks (guestfs_h *g, size_t *len_rtn) pr " {\n"; pr " size_t i, len;\n"; pr " len = RARRAY_LEN (%sv);\n" n; - pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n" + pr " %s = ALLOC_N (char *, len+1);\n" n; pr " for (i = 0; i < len; ++i) {\n"; pr " VALUE v = rb_ary_entry (%sv, i);\n" n; @@ -316,7 +446,6 @@ get_all_event_callbacks (guestfs_h *g, size_t *len_rtn) | Int64 n -> pr " optargs_s.%s = NUM2LL (v);\n" n; | String _ -> - pr " Check_Type (v, T_STRING);\n"; pr " optargs_s.%s = StringValueCStr (v);\n" n | _ -> assert false );