X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Fgenerator.ml;h=77bcc47e33245825cbf5119a734090f86baa97c8;hp=c0a47404b687217117f833a8083b7093075e4f6f;hb=1765330e07a48dc6f7bdef7007f69ebe606fa731;hpb=92804dec7c4982d2039f81586bc4a5cacb46217b diff --git a/src/generator.ml b/src/generator.ml index c0a4740..77bcc47 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -98,6 +98,16 @@ and argt = | StringList of string(* list of strings (each string cannot be NULL) *) | Bool of string (* boolean *) | Int of string (* int (smallish ints, signed, <= 31 bits) *) + (* These are treated as filenames (simple string parameters) in + * the C API and bindings. But in the RPC protocol, we transfer + * the actual file content up to or down from the daemon. + * FileIn: local machine -> daemon (in request) + * FileOut: daemon -> local machine (in reply) + * In guestfish (only), the special name "-" means read from + * stdin or write to stdout. + *) + | FileIn of string + | FileOut of string type flags = | ProtocolLimitWarning (* display warning about protocol size limits *) @@ -384,7 +394,7 @@ Return the contents of the file named C. Note that this function cannot correctly handle binary files (specifically, files containing C<\\0> character which is treated -as end of string). For those you need to use the C +as end of string). For those you need to use the C function which has a more complex interface."); ("ll", (RString "listing", [String "directory"]), 5, [], @@ -1198,6 +1208,30 @@ Reread the partition table on C. This uses the L command."); +(* + ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [], + [], + "upload a file from the local machine", + "\ +Upload local file C to C on the +filesystem. + +C can also be a named pipe. + +See also C."); + + ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [], + [], + "download a file to the local machine", + "\ +Download file C and save it as C +on the local machine. + +C can also be a named pipe. + +See also C, C."); +*) + ] let all_functions = non_daemon_functions @ daemon_functions @@ -1410,7 +1444,8 @@ let mapi f xs = loop 0 xs let name_of_argt = function - | String n | OptString n | StringList n | Bool n | Int n -> n + | String n | OptString n | StringList n | Bool n | Int n + | FileIn n | FileOut n -> n let seq_of_test = function | TestRun s | TestOutput (s, _) | TestOutputList (s, _) @@ -1765,6 +1800,7 @@ and generate_xdr () = | StringList n -> pr " str %s<>;\n" n | Bool n -> pr " bool %s;\n" n | Int n -> pr " int %s;\n" n + | FileIn _ | FileOut _ -> () ) args; pr "};\n\n" ); @@ -1830,7 +1866,7 @@ and generate_xdr () = fun (shortname, _, proc_nr, _, _, _, _) -> pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr ) daemon_functions; - pr " GUESTFS_PROC_dummy\n"; (* so we don't have a "hanging comma" *) + pr " GUESTFS_PROC_NR_PROCS\n"; pr "};\n"; pr "\n"; @@ -1864,6 +1900,19 @@ struct guestfs_message_error { string error; /* error message */ }; +/* For normal requests and replies (not involving any FileIn or + * FileOut parameters), the protocol is: + * + * For requests: + * total length (header + args, but not including length word itself) + * header + * guestfs_foo_args struct + * For replies: + * total length (as above) + * header + * guestfs_foo_ret struct + */ + struct guestfs_message_header { unsigned prog; /* GUESTFS_PROGRAM */ unsigned vers; /* GUESTFS_PROTOCOL_VERSION */ @@ -1872,6 +1921,31 @@ struct guestfs_message_header { unsigned serial; /* message serial number */ guestfs_message_status status; }; + +/* Chunked encoding used to transfer files, for FileIn and FileOut + * parameters. + * + * For requests which have >= 1 FileIn parameter: + * length of header + args (but not length word itself, and not chunks) + * header + * guestfs_foo_args struct + * sequence of chunks for FileIn param #0 + * sequence of chunks for FileIn param #1 etc + * + * For replies which have >= 1 FileOut parameter: + * length of header + ret (but not length word itself, and not chunks) + * header + * guestfs_foo_ret struct + * sequence of chunks for FileOut param #0 + * sequence of chunks for FileOut param #1 etc + */ +const GUESTFS_MAX_CHUNK_SIZE = 8192; + +struct guestfs_chunk { + int cancel; /* if non-zero, transfer is cancelled */ + /* data size is 0 bytes if the transfer has finished successfully */ + opaque data; +}; " (* Generate the guestfs-structs.h file. *) @@ -1953,9 +2027,14 @@ and generate_client_actions () = fun (shortname, style, _, _, _, _, _) -> let name = "guestfs_" ^ shortname in - (* Generate the return value struct. *) - pr "struct %s_rv {\n" shortname; - pr " int cb_done; /* flag to indicate callback was called */\n"; + (* Generate the state struct which stores the high-level + * state between callback functions. The callback(s) are: + * _cb_header_sent header was sent + * _cb_file_sent FileIn file was sent + * _cb_reply_received reply received + *) + pr "struct %s_state {\n" shortname; + pr " int cb_done;\n"; pr " struct guestfs_message_header hdr;\n"; pr " struct guestfs_message_error err;\n"; (match fst style with @@ -1970,19 +2049,20 @@ and generate_client_actions () = | RHashtable _ -> pr " struct %s_ret ret;\n" name ); - pr "};\n\n"; + pr "};\n"; + pr "\n"; (* Generate the callback function. *) pr "static void %s_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname; pr "{\n"; - pr " struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname; + pr " struct %s_state *state = (struct %s_state *) data;\n" shortname shortname; pr "\n"; - pr " if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {\n"; + pr " if (!xdr_guestfs_message_header (xdr, &state->hdr)) {\n"; pr " error (g, \"%s: failed to parse reply header\");\n" name; pr " return;\n"; pr " }\n"; - pr " if (rv->hdr.status == GUESTFS_STATUS_ERROR) {\n"; - pr " if (!xdr_guestfs_message_error (xdr, &rv->err)) {\n"; + pr " if (state->hdr.status == GUESTFS_STATUS_ERROR) {\n"; + pr " if (!xdr_guestfs_message_error (xdr, &state->err)) {\n"; pr " error (g, \"%s: failed to parse reply error\");\n" name; pr " return;\n"; pr " }\n"; @@ -1999,15 +2079,15 @@ and generate_client_actions () = | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _ | RHashtable _ -> - pr " if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name; + pr " if (!xdr_%s_ret (xdr, &state->ret)) {\n" name; pr " error (g, \"%s: failed to parse reply\");\n" name; pr " return;\n"; pr " }\n"; ); pr " done:\n"; - pr " rv->cb_done = 1;\n"; - pr " main_loop.main_loop_quit (g);\n"; + pr " state->cb_done = 1;\n"; + pr " g->main_loop->main_loop_quit (g->main_loop, g);\n"; pr "}\n\n"; (* Generate the action stub. *) @@ -2032,19 +2112,26 @@ and generate_client_actions () = | _ -> pr " struct %s_args args;\n" name ); - pr " struct %s_rv rv;\n" shortname; + pr " struct %s_state state;\n" shortname; pr " int serial;\n"; pr "\n"; pr " if (g->state != READY) {\n"; - pr " error (g, \"%s called from the wrong state, %%d != READY\",\n" - name; - pr " g->state);\n"; + pr " if (g->state == CONFIG)\n"; + pr " error (g, \"%%s: call launch() before using this function\",\n"; + pr " \"%s\");\n" name; + pr " else if (g->state == LAUNCHING)\n"; + pr " error (g, \"%%s: call wait_ready() before using this function\",\n"; + pr " \"%s\");\n" name; + pr " else\n"; + pr " error (g, \"%%s called from the wrong state, %%d != READY\",\n"; + pr " \"%s\", g->state);\n" name; pr " return %s;\n" error_code; pr " }\n"; pr "\n"; - pr " memset (&rv, 0, sizeof rv);\n"; + pr " memset (&state, 0, sizeof state);\n"; pr "\n"; + (* Dispatch the main header and arguments. *) (match snd style with | [] -> pr " serial = dispatch (g, GUESTFS_PROC_%s, NULL, NULL);\n" @@ -2063,6 +2150,7 @@ and generate_client_actions () = pr " args.%s = %s;\n" n n | Int n -> pr " args.%s = %s;\n" n n + | FileIn _ | FileOut _ -> () ) args; pr " serial = dispatch (g, GUESTFS_PROC_%s,\n" (String.uppercase shortname); @@ -2073,52 +2161,73 @@ and generate_client_actions () = pr " return %s;\n" error_code; pr "\n"; - pr " rv.cb_done = 0;\n"; + (* Send any additional files requested. *) + List.iter ( + function + | FileIn n -> + pr " if (send_file (g, %s) == -1)\n" n; + pr " return %s;\n" error_code; + pr "\n"; + | _ -> () + ) (snd style); + + (* Wait for the reply from the remote end. *) + pr " state.cb_done = 0;\n"; pr " g->reply_cb_internal = %s_cb;\n" shortname; - pr " g->reply_cb_internal_data = &rv;\n"; - pr " main_loop.main_loop_run (g);\n"; + pr " g->reply_cb_internal_data = &state;\n"; + pr " (void) g->main_loop->main_loop_run (g->main_loop, g);\n"; pr " g->reply_cb_internal = NULL;\n"; pr " g->reply_cb_internal_data = NULL;\n"; - pr " if (!rv.cb_done) {\n"; + pr " if (!state.cb_done) {\n"; pr " error (g, \"%s failed, see earlier error messages\");\n" name; pr " return %s;\n" error_code; pr " }\n"; pr "\n"; - pr " if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_%s, serial) == -1)\n" + pr " if (check_reply_header (g, &state.hdr, GUESTFS_PROC_%s, serial) == -1)\n" (String.uppercase shortname); pr " return %s;\n" error_code; pr "\n"; - pr " if (rv.hdr.status == GUESTFS_STATUS_ERROR) {\n"; - pr " error (g, \"%%s\", rv.err.error);\n"; + pr " if (state.hdr.status == GUESTFS_STATUS_ERROR) {\n"; + pr " error (g, \"%%s\", state.err.error);\n"; pr " return %s;\n" error_code; pr " }\n"; pr "\n"; + (* Expecting to receive further files (FileOut)? *) + List.iter ( + function + | FileOut n -> + pr " if (receive_file (g, %s) == -1)\n" n; + pr " return %s;\n" error_code; + pr "\n"; + | _ -> () + ) (snd style); + (match fst style with | RErr -> pr " return 0;\n" | RInt n | RInt64 n | RBool n -> - pr " return rv.ret.%s;\n" n + pr " return state.ret.%s;\n" n | RConstString _ -> failwithf "RConstString cannot be returned from a daemon function" | RString n -> - pr " return rv.ret.%s; /* caller will free */\n" n + pr " return state.ret.%s; /* caller will free */\n" n | RStringList n | RHashtable n -> pr " /* caller will free this, but we need to add a NULL entry */\n"; - pr " rv.ret.%s.%s_val =" n n; - pr " safe_realloc (g, rv.ret.%s.%s_val,\n" n n; - pr " sizeof (char *) * (rv.ret.%s.%s_len + 1));\n" + pr " state.ret.%s.%s_val =" n n; + pr " safe_realloc (g, state.ret.%s.%s_val,\n" n n; + pr " sizeof (char *) * (state.ret.%s.%s_len + 1));\n" n n; - pr " rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n; - pr " return rv.ret.%s.%s_val;\n" n n + pr " state.ret.%s.%s_val[state.ret.%s.%s_len] = NULL;\n" n n n n; + pr " return state.ret.%s.%s_val;\n" n n | RIntBool _ -> pr " /* caller with free this */\n"; - pr " return safe_memdup (g, &rv.ret, sizeof (rv.ret));\n" + pr " return safe_memdup (g, &state.ret, sizeof (state.ret));\n" | RPVList n | RVGList n | RLVList n | RStat n | RStatVFS n -> pr " /* caller will free this */\n"; - pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n + pr " return safe_memdup (g, &state.ret.%s, sizeof (state.ret.%s));\n" n n ); pr "}\n\n" @@ -2189,6 +2298,7 @@ and generate_daemon_actions () = | StringList n -> pr " char **%s;\n" n | Bool n -> pr " int %s;\n" n | Int n -> pr " int %s;\n" n + | FileIn _ | FileOut _ -> () ) args ); pr "\n"; @@ -2212,12 +2322,19 @@ and generate_daemon_actions () = pr " %s = args.%s.%s_val;\n" n n n | Bool n -> pr " %s = args.%s;\n" n n | Int n -> pr " %s = args.%s;\n" n n + | FileIn _ | FileOut _ -> () ) args; pr "\n" ); + (* Don't want to call the impl with any FileIn or FileOut + * parameters, since these go "outside" the RPC protocol. + *) + let argsnofile = + List.filter (function FileIn _ | FileOut _ -> false | _ -> true) + (snd style) in pr " r = do_%s " name; - generate_call_args style; + generate_call_args argsnofile; pr ";\n"; pr " if (r == %s)\n" error_code; @@ -2225,34 +2342,48 @@ and generate_daemon_actions () = pr " goto done;\n"; pr "\n"; - (match fst style with - | RErr -> pr " reply (NULL, NULL);\n" - | RInt n | RInt64 n | RBool n -> - pr " struct guestfs_%s_ret ret;\n" name; - pr " ret.%s = r;\n" n; - pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name - | RConstString _ -> - failwithf "RConstString cannot be returned from a daemon function" - | RString n -> - pr " struct guestfs_%s_ret ret;\n" name; - pr " ret.%s = r;\n" n; - pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name; - pr " free (r);\n" - | RStringList n | RHashtable n -> - pr " struct guestfs_%s_ret ret;\n" name; - pr " ret.%s.%s_len = count_strings (r);\n" n n; - pr " ret.%s.%s_val = r;\n" n n; - pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name; - pr " free_strings (r);\n" - | RIntBool _ -> - pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name; - pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name - | RPVList n | RVGList n | RLVList n - | RStat n | RStatVFS n -> - pr " struct guestfs_%s_ret ret;\n" name; - pr " ret.%s = *r;\n" n; - pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name; - pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name + (* If there are any FileOut parameters, then the impl must + * send its own reply. + *) + let no_reply = + List.exists (function FileOut _ -> true | _ -> false) (snd style) in + if no_reply then + pr " /* do_%s has already sent a reply */\n" name + else ( + match fst style with + | RErr -> pr " reply (NULL, NULL);\n" + | RInt n | RInt64 n | RBool n -> + pr " struct guestfs_%s_ret ret;\n" name; + pr " ret.%s = r;\n" n; + pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" + name + | RConstString _ -> + failwithf "RConstString cannot be returned from a daemon function" + | RString n -> + pr " struct guestfs_%s_ret ret;\n" name; + pr " ret.%s = r;\n" n; + pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" + name; + pr " free (r);\n" + | RStringList n | RHashtable n -> + pr " struct guestfs_%s_ret ret;\n" name; + pr " ret.%s.%s_len = count_strings (r);\n" n n; + pr " ret.%s.%s_val = r;\n" n n; + pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" + name; + pr " free_strings (r);\n" + | RIntBool _ -> + pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" + name; + pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name + | RPVList n | RVGList n | RLVList n + | RStat n | RStatVFS n -> + pr " struct guestfs_%s_ret ret;\n" name; + pr " ret.%s = *r;\n" n; + pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" + name; + pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" + name ); (* Free the args. *) @@ -2890,6 +3021,7 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd = | OptString _, _ | Int _, _ | Bool _, _ -> () + | FileIn _, _ | FileOut _, _ -> () | StringList n, arg -> pr " char *%s[] = {\n" n; let strs = string_split " " arg in @@ -2929,7 +3061,9 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd = (* Generate the parameters. *) List.iter ( function - | String _, arg -> pr ", \"%s\"" (c_quote arg) + | String _, arg + | FileIn _, arg | FileOut _, arg -> + pr ", \"%s\"" (c_quote arg) | OptString _, arg -> if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg) | StringList n, _ -> @@ -3151,7 +3285,9 @@ and generate_fish_cmds () = List.iter ( function | String n - | OptString n -> pr " const char *%s;\n" n + | OptString n + | FileIn n + | FileOut n -> pr " const char *%s;\n" n | StringList n -> pr " char **%s;\n" n | Bool n -> pr " int %s;\n" n | Int n -> pr " int %s;\n" n @@ -3172,6 +3308,12 @@ and generate_fish_cmds () = | OptString name -> pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n" name i i + | FileIn name -> + pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n" + name i i + | FileOut name -> + pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n" + name i i | StringList name -> pr " %s = parse_string_list (argv[%d]);\n" name i | Bool name -> @@ -3185,7 +3327,7 @@ and generate_fish_cmds () = try find_map (function FishAction n -> Some n | _ -> None) flags with Not_found -> sprintf "guestfs_%s" name in pr " r = %s " fn; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; (* Check return value for errors and display command results. *) @@ -3394,11 +3536,16 @@ and generate_fish_actions_pod () = | StringList n -> pr " %s,..." n | Bool _ -> pr " true|false" | Int n -> pr " %s" n + | FileIn n | FileOut n -> pr " (%s|-)" n ) (snd style); pr "\n"; pr "\n"; pr "%s\n\n" longdesc; + if List.exists (function FileIn _ | FileOut _ -> true + | _ -> false) (snd style) then + pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n"; + if List.mem ProtocolLimitWarning flags then pr "%s\n\n" protocol_limit_warning; @@ -3457,11 +3604,14 @@ and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true) in List.iter ( function - | String n -> next (); pr "const char *%s" n + | String n | OptString n -> next (); pr "const char *%s" n | StringList n -> next (); pr "char * const* const %s" n | Bool n -> next (); pr "int %s" n | Int n -> next (); pr "int %s" n + | FileIn n + | FileOut n -> + if not in_daemon then (next (); pr "const char *%s" n) ) (snd style); ); pr ")"; @@ -3469,7 +3619,7 @@ and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true) if newline then pr "\n" (* Generate C call arguments, eg "(handle, foo, bar)" *) -and generate_call_args ?handle style = +and generate_call_args ?handle args = pr "("; let comma = ref false in (match handle with @@ -3480,13 +3630,8 @@ and generate_call_args ?handle style = fun arg -> if !comma then pr ", "; comma := true; - match arg with - | String n - | OptString n - | StringList n - | Bool n - | Int n -> pr "%s" n - ) (snd style); + pr "%s" (name_of_argt arg) + ) args; pr ")" (* Generate the OCaml bindings interface. *) @@ -3715,7 +3860,9 @@ copy_table (char * const * argv) List.iter ( function - | String n -> + | String n + | FileIn n + | FileOut n -> pr " const char *%s = String_val (%sv);\n" n n | OptString n -> pr " const char *%s =\n" n; @@ -3760,7 +3907,7 @@ copy_table (char * const * argv) pr " caml_enter_blocking_section ();\n"; pr " r = guestfs_%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; pr " caml_leave_blocking_section ();\n"; @@ -3768,7 +3915,7 @@ copy_table (char * const * argv) function | StringList n -> pr " ocaml_guestfs_free_strings (%s);\n" n; - | String _ | OptString _ | Bool _ | Int _ -> () + | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> () ) (snd style); pr " if (r == %s)\n" error_code; @@ -3864,7 +4011,7 @@ and generate_ocaml_prototype ?(is_external = false) name style = pr "%s : t -> " name; List.iter ( function - | String _ -> pr "string -> " + | String _ | FileIn _ | FileOut _ -> pr "string -> " | OptString _ -> pr "string option -> " | StringList _ -> pr "string array -> " | Bool _ -> pr "bool -> " @@ -4003,12 +4150,12 @@ DESTROY (g) ); (* Call and arguments. *) pr "%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr "\n"; pr " guestfs_h *g;\n"; List.iter ( function - | String n -> pr " char *%s;\n" n + | String n | FileIn n | FileOut n -> pr " char *%s;\n" n | OptString n -> pr " char *%s;\n" n | StringList n -> pr " char **%s;\n" n | Bool n -> pr " int %s;\n" n @@ -4018,10 +4165,8 @@ DESTROY (g) let do_cleanups () = List.iter ( function - | String _ - | OptString _ - | Bool _ - | Int _ -> () + | String _ | OptString _ | Bool _ | Int _ + | FileIn _ | FileOut _ -> () | StringList n -> pr " free (%s);\n" n ) (snd style) in @@ -4033,7 +4178,7 @@ DESTROY (g) pr " int r;\n"; pr " PPCODE:\n"; pr " r = guestfs_%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (r == -1)\n"; @@ -4044,7 +4189,7 @@ DESTROY (g) pr " int %s;\n" n; pr " CODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == -1)\n" n; @@ -4057,7 +4202,7 @@ DESTROY (g) pr " int64_t %s;\n" n; pr " CODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == -1)\n" n; @@ -4070,7 +4215,7 @@ DESTROY (g) pr " const char *%s;\n" n; pr " CODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == NULL)\n" n; @@ -4083,7 +4228,7 @@ DESTROY (g) pr " char *%s;\n" n; pr " CODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == NULL)\n" n; @@ -4098,7 +4243,7 @@ DESTROY (g) pr " int i, n;\n"; pr " PPCODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == NULL)\n" n; @@ -4115,7 +4260,7 @@ DESTROY (g) pr " struct guestfs_int_bool *r;\n"; pr " PPCODE:\n"; pr " r = guestfs_%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (r == NULL)\n"; @@ -4147,7 +4292,7 @@ and generate_perl_lvm_code typ cols name style n do_cleanups = pr " HV *hv;\n"; pr " PPCODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == NULL)\n" n; @@ -4182,7 +4327,7 @@ and generate_perl_stat_code typ cols name style n do_cleanups = pr " struct guestfs_%s *%s;\n" typ n; pr " PPCODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == NULL)\n" n; @@ -4338,7 +4483,7 @@ and generate_perl_prototype name style = if !comma then pr ", "; comma := true; match arg with - | String n | OptString n | Bool n | Int n -> + | String n | OptString n | Bool n | Int n | FileIn n | FileOut n -> pr "$%s" n | StringList n -> pr "\\@%s" n @@ -4434,7 +4579,6 @@ put_table (char * const * const argv) list = PyList_New (argc >> 1); for (i = 0; i < argc; i += 2) { - PyObject *item; item = PyTuple_New (2); PyTuple_SetItem (item, 0, PyString_FromString (argv[i])); PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1])); @@ -4590,7 +4734,7 @@ py_guestfs_close (PyObject *self, PyObject *args) List.iter ( function - | String n -> pr " const char *%s;\n" n + | String n | FileIn n | FileOut n -> pr " const char *%s;\n" n | OptString n -> pr " const char *%s;\n" n | StringList n -> pr " PyObject *py_%s;\n" n; @@ -4605,7 +4749,7 @@ py_guestfs_close (PyObject *self, PyObject *args) pr " if (!PyArg_ParseTuple (args, (char *) \"O"; List.iter ( function - | String _ -> pr "s" + | String _ | FileIn _ | FileOut _ -> pr "s" | OptString _ -> pr "z" | StringList _ -> pr "O" | Bool _ -> pr "i" (* XXX Python has booleans? *) @@ -4615,7 +4759,7 @@ py_guestfs_close (PyObject *self, PyObject *args) pr " &py_g"; List.iter ( function - | String n -> pr ", &%s" n + | String n | FileIn n | FileOut n -> pr ", &%s" n | OptString n -> pr ", &%s" n | StringList n -> pr ", &py_%s" n | Bool n -> pr ", &%s" n @@ -4628,7 +4772,7 @@ py_guestfs_close (PyObject *self, PyObject *args) pr " g = get_handle (py_g);\n"; List.iter ( function - | String _ | OptString _ | Bool _ | Int _ -> () + | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> () | StringList n -> pr " %s = get_string_list (py_%s);\n" n n; pr " if (!%s) return NULL;\n" n @@ -4637,12 +4781,12 @@ py_guestfs_close (PyObject *self, PyObject *args) pr "\n"; pr " r = guestfs_%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; List.iter ( function - | String _ | OptString _ | Bool _ | Int _ -> () + | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> () | StringList n -> pr " free (%s);\n" n ) (snd style); @@ -4826,11 +4970,11 @@ class GuestFS: let doc = String.concat "\n " doc in pr " def %s " name; - generate_call_args ~handle:"self" style; + generate_call_args ~handle:"self" (snd style); pr ":\n"; pr " u\"\"\"%s\"\"\"\n" doc; pr " return libguestfsmod.%s " name; - generate_call_args ~handle:"self._o" style; + generate_call_args ~handle:"self._o" (snd style); pr "\n"; pr "\n"; ) all_functions @@ -4932,7 +5076,7 @@ static VALUE ruby_guestfs_close (VALUE gv) List.iter ( function - | String n -> + | String n | FileIn n | FileOut 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"; @@ -4972,12 +5116,12 @@ static VALUE ruby_guestfs_close (VALUE gv) pr "\n"; pr " r = guestfs_%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; List.iter ( function - | String _ | OptString _ | Bool _ | Int _ -> () + | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> () | StringList n -> pr " free (%s);\n" n ) (snd style);