| Dev_or_Path of string (* /dev device name or Pathname, cannot be NULL *)
| OptString of string (* const char *name, may be NULL *)
| StringList of string(* list of strings (each string cannot be NULL) *)
+ | DeviceList of string(* list of Device names (each 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
* Apart from that, long descriptions are just perldoc paragraphs.
*)
+(* Generate a random UUID (used in tests). *)
+let uuidgen () =
+ let chan = Unix.open_process_in "uuidgen" in
+ let uuid = input_line chan in
+ (match Unix.close_process_in chan with
+ | Unix.WEXITED 0 -> ()
+ | Unix.WEXITED _ ->
+ failwith "uuidgen: process exited with non-zero status"
+ | Unix.WSIGNALED _ | Unix.WSTOPPED _ ->
+ failwith "uuidgen: process signalled or stopped by signal"
+ );
+ uuid
+
(* These test functions are used in the language binding tests. *)
let test_all_args = [
as end of string). For those you need to use the C<guestfs_read_file>
or C<guestfs_download> functions which have a more complex interface.");
- ("ll", (RString "listing", [String "directory"]), 5, [],
+ ("ll", (RString "listing", [Pathname "directory"]), 5, [],
[], (* XXX Tricky to test because it depends on the exact format
* of the 'ls -l' command, which changes between F10 and F11.
*)
This command is mostly useful for interactive sessions. It
is I<not> intended that you try to parse the output string.");
- ("ls", (RStringList "listing", [String "directory"]), 6, [],
+ ("ls", (RStringList "listing", [Pathname "directory"]), 6, [],
[InitBasicFS, Always, TestOutputList (
[["touch"; "/new"];
["touch"; "/newer"];
where C<device> should usually be a partition name such
as C</dev/sda1>.");
- ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
+ ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [],
[InitEmpty, Always, TestOutputList (
[["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
["pvcreate"; "/dev/sda1"];
To upload an uncompressed tarball, use C<guestfs_tar_in>.");
- ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
+ ("tgz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 72, [],
[],
"pack directory into compressed tarball",
"\
C<device>.");
("set_e2uuid", (RErr, [Device "device"; String "uuid"]), 82, [],
- [InitBasicFS, Always, TestOutput (
- [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
- ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
- InitBasicFS, Always, TestOutput (
- [["set_e2uuid"; "/dev/sda1"; "clear"];
- ["get_e2uuid"; "/dev/sda1"]], "");
- (* We can't predict what UUIDs will be, so just check the commands run. *)
- InitBasicFS, Always, TestRun (
- [["set_e2uuid"; "/dev/sda1"; "random"]]);
- InitBasicFS, Always, TestRun (
- [["set_e2uuid"; "/dev/sda1"; "time"]])],
+ (let uuid = uuidgen () in
+ [InitBasicFS, Always, TestOutput (
+ [["set_e2uuid"; "/dev/sda1"; uuid];
+ ["get_e2uuid"; "/dev/sda1"]], uuid);
+ InitBasicFS, Always, TestOutput (
+ [["set_e2uuid"; "/dev/sda1"; "clear"];
+ ["get_e2uuid"; "/dev/sda1"]], "");
+ (* We can't predict what UUIDs will be, so just check the commands run. *)
+ InitBasicFS, Always, TestRun (
+ [["set_e2uuid"; "/dev/sda1"; "random"]]);
+ InitBasicFS, Always, TestRun (
+ [["set_e2uuid"; "/dev/sda1"; "time"]])]),
"set the ext2/3/4 filesystem UUID",
"\
This sets the ext2/3/4 filesystem UUID of the filesystem on
It is an interface to the L<scrub(1)> program. See that
manual page for more details.");
- ("scrub_file", (RErr, [String "file"]), 115, [],
+ ("scrub_file", (RErr, [Pathname "file"]), 115, [],
[InitBasicFS, Always, TestRun (
[["write_file"; "/file"; "content"; "0"];
["scrub_file"; "/file"]])],
It is an interface to the L<scrub(1)> program. See that
manual page for more details.");
- ("scrub_freespace", (RErr, [String "dir"]), 116, [],
+ ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [],
[], (* XXX needs testing *)
"scrub (securely wipe) free space",
"\
filesystem as initrd. We I<only> support the newer initramfs
format (compressed cpio files).");
- ("mount_loop", (RErr, [String "file"; String "mountpoint"]), 129, [],
+ ("mount_loop", (RErr, [Pathname "file"; Pathname "mountpoint"]), 129, [],
[],
"mount a file using the loop device",
"\
a limitation of the kernel or swap tools.");
("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [],
- [InitEmpty, Always, TestRun (
- [["sfdiskM"; "/dev/sda"; ","];
- ["mkswap_U"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"; "/dev/sda1"]])],
+ (let uuid = uuidgen () in
+ [InitEmpty, Always, TestRun (
+ [["sfdiskM"; "/dev/sda"; ","];
+ ["mkswap_U"; uuid; "/dev/sda1"]])]),
"create a swap partition with an explicit UUID",
"\
Create a swap partition on C<device> with UUID C<uuid>.");
This call returns the previous umask.");
- ("readdir", (RStructList ("entries", "dirent"), [String "dir"]), 138, [],
+ ("readdir", (RStructList ("entries", "dirent"), [Pathname "dir"]), 138, [],
[],
"read directories entries",
"\
device or partition named C<device>.
See C<guestfs_swapon_device>.");
- ("swapon_file", (RErr, [String "file"]), 172, [],
+ ("swapon_file", (RErr, [Pathname "file"]), 172, [],
[InitBasicFS, Always, TestRun (
[["fallocate"; "/swap"; "8388608"];
["mkswap_file"; "/swap"];
This command enables swap to a file.
See C<guestfs_swapon_device> for other notes.");
- ("swapoff_file", (RErr, [String "file"]), 173, [],
+ ("swapoff_file", (RErr, [Pathname "file"]), 173, [],
[], (* XXX tested by swapon_file *)
"disable swap on file",
"\
labeled swap partition.");
("swapon_uuid", (RErr, [String "uuid"]), 176, [],
- [InitEmpty, Always, TestRun (
- [["mkswap_U"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"; "/dev/sdb"];
- ["swapon_uuid"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
- ["swapoff_uuid"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"]])],
+ (let uuid = uuidgen () in
+ [InitEmpty, Always, TestRun (
+ [["mkswap_U"; uuid; "/dev/sdb"];
+ ["swapon_uuid"; uuid];
+ ["swapoff_uuid"; uuid]])]),
"enable swap on swap partition by UUID",
"\
This command enables swap to a swap partition with the given UUID.
See the documentation about SELINUX in L<guestfs(3)>,
and C<guestfs_setcon>");
+ ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [],
+ [InitEmpty, Always, TestOutput (
+ [["sfdiskM"; "/dev/sda"; ","];
+ ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"];
+ ["mount"; "/dev/sda1"; "/"];
+ ["write_file"; "/new"; "new file contents"; "0"];
+ ["cat"; "/new"]], "new file contents")],
+ "make a filesystem with block size",
+ "\
+This call is similar to C<guestfs_mkfs>, but it allows you to
+control the block size of the resulting filesystem. Supported
+block sizes depend on the filesystem type, but typically they
+are C<1024>, C<2048> or C<4096> only.");
+
+ ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [],
+ [InitEmpty, Always, TestOutput (
+ [["sfdiskM"; "/dev/sda"; ",100 ,"];
+ ["mke2journal"; "4096"; "/dev/sda1"];
+ ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"];
+ ["mount"; "/dev/sda2"; "/"];
+ ["write_file"; "/new"; "new file contents"; "0"];
+ ["cat"; "/new"]], "new file contents")],
+ "make ext2/3/4 external journal",
+ "\
+This creates an ext2 external journal on C<device>. It is equivalent
+to the command:
+
+ mke2fs -O journal_dev -b blocksize device");
+
+ ("mke2journal_L", (RErr, [Int "blocksize"; String "label"; Device "device"]), 189, [],
+ [InitEmpty, Always, TestOutput (
+ [["sfdiskM"; "/dev/sda"; ",100 ,"];
+ ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"];
+ ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"];
+ ["mount"; "/dev/sda2"; "/"];
+ ["write_file"; "/new"; "new file contents"; "0"];
+ ["cat"; "/new"]], "new file contents")],
+ "make ext2/3/4 external journal with label",
+ "\
+This creates an ext2 external journal on C<device> with label C<label>.");
+
+ ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [],
+ (let uuid = uuidgen () in
+ [InitEmpty, Always, TestOutput (
+ [["sfdiskM"; "/dev/sda"; ",100 ,"];
+ ["mke2journal_U"; "4096"; uuid; "/dev/sda1"];
+ ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid];
+ ["mount"; "/dev/sda2"; "/"];
+ ["write_file"; "/new"; "new file contents"; "0"];
+ ["cat"; "/new"]], "new file contents")]),
+ "make ext2/3/4 external journal with UUID",
+ "\
+This creates an ext2 external journal on C<device> with UUID C<uuid>.");
+
+ ("mke2fs_J", (RErr, [String "fstype"; Int "blocksize"; Device "device"; Device "journal"]), 191, [],
+ [],
+ "make ext2/3/4 filesystem with external journal",
+ "\
+This creates an ext2/3/4 filesystem on C<device> with
+an external journal on C<journal>. It is equivalent
+to the command:
+
+ mke2fs -t fstype -b blocksize -J device=<journal> <device>
+
+See also C<guestfs_mke2journal>.");
+
+ ("mke2fs_JL", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "label"]), 192, [],
+ [],
+ "make ext2/3/4 filesystem with external journal",
+ "\
+This creates an ext2/3/4 filesystem on C<device> with
+an external journal on the journal labeled C<label>.
+
+See also C<guestfs_mke2journal_L>.");
+
+ ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [],
+ [],
+ "make ext2/3/4 filesystem with external journal",
+ "\
+This creates an ext2/3/4 filesystem on C<device> with
+an external journal on the journal with UUID C<uuid>.
+
+See also C<guestfs_mke2journal_U>.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
"inotify_event", "INotifyEvent";
]
+(* What structs are actually returned. *)
+type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
+
+(* Returns a list of RStruct/RStructList structs that are returned
+ * by any function. Each element of returned list is a pair:
+ *
+ * (structname, RStructOnly)
+ * == there exists function which returns RStruct (_, structname)
+ * (structname, RStructListOnly)
+ * == there exists function which returns RStructList (_, structname)
+ * (structname, RStructAndList)
+ * == there are functions returning both RStruct (_, structname)
+ * and RStructList (_, structname)
+ *)
+let rstructs_used =
+ (* ||| is a "logical OR" for rstructs_used_t *)
+ let (|||) a b =
+ match a, b with
+ | RStructAndList, _
+ | _, RStructAndList -> RStructAndList
+ | RStructOnly, RStructListOnly
+ | RStructListOnly, RStructOnly -> RStructAndList
+ | RStructOnly, RStructOnly -> RStructOnly
+ | RStructListOnly, RStructListOnly -> RStructListOnly
+ in
+
+ let h = Hashtbl.create 13 in
+
+ (* if elem->oldv exists, update entry using ||| operator,
+ * else just add elem->newv to the hash
+ *)
+ let update elem newv =
+ try let oldv = Hashtbl.find h elem in
+ Hashtbl.replace h elem (newv ||| oldv)
+ with Not_found -> Hashtbl.add h elem newv
+ in
+
+ List.iter (
+ fun (_, style, _, _, _, _, _) ->
+ match fst style with
+ | RStruct (_, structname) -> update structname RStructOnly
+ | RStructList (_, structname) -> update structname RStructListOnly
+ | _ -> ()
+ ) all_functions;
+
+ (* return key->values as a list of (key,value) *)
+ Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
+
+(* debug:
+let () =
+ List.iter (
+ function
+ | sn, RStructOnly -> printf "%s RStructOnly\n" sn
+ | sn, RStructListOnly -> printf "%s RStructListOnly\n" sn
+ | sn, RStructAndList -> printf "%s RStructAndList\n" sn
+ ) rstructs_used
+*)
+
(* Used for testing language bindings. *)
type callt =
| CallString of string
loop 0 xs
let name_of_argt = function
- | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | Bool n | Int n
+ | Pathname n | Device n | Dev_or_Path n | String n | OptString n
+ | StringList n | DeviceList n | Bool n | Int n
| FileIn n | FileOut n -> n
let java_name_of_struct typ =
function
| Pathname n | Device n | Dev_or_Path n | String n -> pr " string %s<>;\n" n
| OptString n -> pr " str *%s;\n" n
- | StringList n -> pr " str %s<>;\n" n
+ | StringList n | DeviceList n -> pr " str %s<>;\n" n
| Bool n -> pr " bool %s;\n" n
| Int n -> pr " int %s;\n" n
| FileIn _ | FileOut _ -> ()
pr " args.%s = (char *) %s;\n" n n
| OptString n ->
pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
- | StringList n ->
+ | StringList n | DeviceList n ->
pr " args.%s.%s_val = (char **) %s;\n" n n n;
pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
| Bool n ->
| Pathname n
| String n -> ()
| OptString n -> pr " char *%s;\n" n
- | StringList n -> pr " char **%s;\n" n
+ | StringList n | DeviceList n -> pr " char **%s;\n" n
| Bool n -> pr " int %s;\n" n
| Int n -> pr " int %s;\n" n
| FileIn _ | FileOut _ -> ()
let pr_args n =
pr " char *%s = args.%s;\n" n n
in
+ let pr_list_handling_code n =
+ pr " %s = realloc (args.%s.%s_val,\n" n n n;
+ pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n;
+ pr " if (%s == NULL) {\n" n;
+ pr " reply_with_perror (\"realloc\");\n";
+ pr " goto done;\n";
+ pr " }\n";
+ pr " %s[args.%s.%s_len] = NULL;\n" n n n;
+ pr " args.%s.%s_val = %s;\n" n n n;
+ in
List.iter (
function
| Pathname n ->
pr " ABS_PATH (%s, goto done);\n" n;
| Device n ->
pr_args n;
- pr " RESOLVE_DEVICE (%s, goto done);" n;
+ pr " RESOLVE_DEVICE (%s, goto done);\n" n;
| Dev_or_Path n ->
pr_args n;
- pr " REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, goto done);" n;
+ pr " REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, goto done);\n" n;
| String n -> pr_args n
| OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
| StringList n ->
- pr " %s = realloc (args.%s.%s_val,\n" n n n;
- pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n;
- pr " if (%s == NULL) {\n" n;
- pr " reply_with_perror (\"realloc\");\n";
- pr " goto done;\n";
+ pr_list_handling_code n;
+ | DeviceList n ->
+ pr_list_handling_code n;
+ pr " /* Ensure that each is a device,\n";
+ pr " * and perform device name translation. */\n";
+ pr " { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
+ pr " RESOLVE_DEVICE (physvols[pvi], goto done);\n";
pr " }\n";
- pr " %s[args.%s.%s_len] = NULL;\n" n n n;
- pr " args.%s.%s_val = %s;\n" n n n;
| Bool n -> pr " %s = args.%s;\n" n n
| Int n -> pr " %s = args.%s;\n" n n
| FileIn _ | FileOut _ -> ()
pr "\n"
);
+
(* this is used at least for do_equal *)
if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
(* Emit NEED_ROOT just once, even when there are two or
fprintf (stderr, \"%%s\\n\", msg);
}
-static void print_strings (char * const * const argv)
+/* FIXME: nearly identical code appears in fish.c */
+static void print_strings (char const *const *argv)
{
int argc;
}
/*
-static void print_table (char * const * const argv)
+static void print_table (char const *const *argv)
{
int i;
| Int _, _
| Bool _, _
| FileIn _, _ | FileOut _, _ -> ()
- | StringList n, arg ->
+ | StringList n, arg | DeviceList n, arg ->
let strs = string_split " " arg in
iteri (
fun i str ->
pr ", %s" n
| FileIn _, arg | FileOut _, arg ->
pr ", \"%s\"" (c_quote arg)
- | StringList n, _ ->
+ | StringList n, _ | DeviceList n, _ ->
pr ", %s" n
| Int _, arg ->
let i =
| OptString n
| FileIn n
| FileOut n -> pr " const char *%s;\n" n
- | StringList n -> pr " char **%s;\n" n
+ | StringList n | DeviceList n -> pr " char *const *%s;\n" n
| Bool n -> pr " int %s;\n" n
| Int n -> pr " int %s;\n" n
) (snd style);
| FileOut name ->
pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
name i i
- | StringList name ->
+ | StringList name | DeviceList name ->
pr " %s = parse_string_list (argv[%d]);\n" name i
| Bool name ->
pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
function
| Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
| OptString n -> pr " %s" n
- | StringList n -> pr " '%s ...'" n
+ | StringList n | DeviceList n -> pr " '%s ...'" n
| Bool _ -> pr " true|false"
| Int n -> pr " %s" n
| FileIn n | FileOut n -> pr " (%s|-)" n
| OptString n ->
next ();
pr "const char *%s" n
- | StringList n ->
+ | StringList n | DeviceList n ->
next ();
- if not in_daemon then pr "char * const* const %s" n
- else pr "char **%s" n
+ pr "char *const *%s" n
| Bool n -> next (); pr "int %s" n
| Int n -> next (); pr "int %s" n
| FileIn n
pr " const char *%s =\n" n;
pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
n n
- | StringList n ->
+ | StringList n | DeviceList n ->
pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
| Bool n ->
pr " int %s = Bool_val (%sv);\n" n n
List.iter (
function
- | StringList n ->
+ | StringList n | DeviceList n ->
pr " ocaml_guestfs_free_strings (%s);\n" n;
| Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _ | Bool _ | Int _
| FileIn _ | FileOut _ -> ()
function
| Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
| OptString _ -> pr "string option -> "
- | StringList _ -> pr "string array -> "
+ | StringList _ | DeviceList _ -> pr "string array -> "
| Bool _ -> pr "bool -> "
| Int _ -> pr "int -> "
) (snd style);
* to add 1 to the ST(x) operator.
*)
pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
- | StringList n -> pr " char **%s;\n" n
+ | StringList n | DeviceList n -> pr " char **%s;\n" n
| Bool n -> pr " int %s;\n" n
| Int n -> pr " int %s;\n" n
) (snd style);
function
| Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _ | Bool _ | Int _
| FileIn _ | FileOut _ -> ()
- | StringList n -> pr " free (%s);\n" n
+ | StringList n | DeviceList n -> pr " free (%s);\n" n
) (snd style)
in
| Pathname n | Device n | Dev_or_Path n | String n
| OptString n | Bool n | Int n | FileIn n | FileOut n ->
pr "$%s" n
- | StringList n ->
+ | StringList n | DeviceList n ->
pr "\\@%s" n
) (snd style);
pr ");"
generate_header CStyle LGPLv2;
pr "\
+#include <Python.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
-#include <Python.h>
-
#include \"guestfs.h\"
typedef struct {
}
/* This list should be freed (but not the strings) after use. */
-static const char **
+static char **
get_string_list (PyObject *obj)
{
int i, len;
- const char **r;
+ char **r;
assert (obj);
";
+ let emit_put_list_function typ =
+ pr "static PyObject *\n";
+ pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
+ pr "{\n";
+ pr " PyObject *list;\n";
+ pr " int i;\n";
+ pr "\n";
+ pr " list = PyList_New (%ss->len);\n" typ;
+ pr " for (i = 0; i < %ss->len; ++i)\n" typ;
+ pr " PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
+ pr " return list;\n";
+ pr "};\n";
+ pr "\n"
+ in
+
(* Structures, turned into Python dictionaries. *)
List.iter (
fun (typ, cols) ->
typ name;
pr " else {\n";
pr " Py_INCREF (Py_None);\n";
- pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
+ pr " PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
pr " }\n"
| name, FChar ->
pr " PyDict_SetItemString (dict, \"%s\",\n" name;
pr "};\n";
pr "\n";
- pr "static PyObject *\n";
- pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
- pr "{\n";
- pr " PyObject *list;\n";
- pr " int i;\n";
- pr "\n";
- pr " list = PyList_New (%ss->len);\n" typ;
- pr " for (i = 0; i < %ss->len; ++i)\n" typ;
- pr " PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
- pr " return list;\n";
- pr "};\n";
- pr "\n"
) structs;
+ (* Emit a put_TYPE_list function definition only if that function is used. *)
+ List.iter (
+ function
+ | typ, (RStructListOnly | RStructAndList) ->
+ (* generate the function for typ *)
+ emit_put_list_function typ
+ | typ, _ -> () (* empty *)
+ ) rstructs_used;
+
(* Python wrapper functions. *)
List.iter (
fun (name, style, _, _, _, _, _) ->
| Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
pr " const char *%s;\n" n
| OptString n -> pr " const char *%s;\n" n
- | StringList n ->
+ | StringList n | DeviceList n ->
pr " PyObject *py_%s;\n" n;
- pr " const char **%s;\n" n
+ pr " char **%s;\n" n
| Bool n -> pr " int %s;\n" n
| Int n -> pr " int %s;\n" n
) (snd style);
function
| Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
| OptString _ -> pr "z"
- | StringList _ -> pr "O"
+ | StringList _ | DeviceList _ -> pr "O"
| Bool _ -> pr "i" (* XXX Python has booleans? *)
| Int _ -> pr "i"
) (snd style);
function
| Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
| OptString n -> pr ", &%s" n
- | StringList n -> pr ", &py_%s" n
+ | StringList n | DeviceList n -> pr ", &py_%s" n
| Bool n -> pr ", &%s" n
| Int n -> pr ", &%s" n
) (snd style);
function
| Pathname _ | Device _ | Dev_or_Path _ | String _
| FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
- | StringList n ->
+ | StringList n | DeviceList n ->
pr " %s = get_string_list (py_%s);\n" n n;
pr " if (!%s) return NULL;\n" n
) (snd style);
function
| Pathname _ | Device _ | Dev_or_Path _ | String _
| FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
- | StringList n ->
+ | StringList n | DeviceList n ->
pr " free (%s);\n" n
) (snd style);
pr " \"%s\", \"%s\");\n" n name
| OptString n ->
pr " const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
- | StringList n ->
+ | StringList n | DeviceList n ->
pr " char **%s;\n" n;
pr " Check_Type (%sv, T_ARRAY);\n" n;
pr " {\n";
function
| Pathname _ | Device _ | Dev_or_Path _ | String _
| FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
- | StringList n ->
+ | StringList n | DeviceList n ->
pr " free (%s);\n" n
) (snd style);
| FileIn n
| FileOut n ->
pr "String %s" n
- | StringList n ->
+ | StringList n | DeviceList n ->
pr "String[] %s" n
| Bool n ->
pr "boolean %s" n
| FileIn n
| FileOut n ->
pr ", jstring j%s" n
- | StringList n ->
+ | StringList n | DeviceList n ->
pr ", jobjectArray j%s" n
| Bool n ->
pr ", jboolean j%s" n
| FileIn n
| FileOut n ->
pr " const char *%s;\n" n
- | StringList n ->
+ | StringList n | DeviceList n ->
pr " int %s_len;\n" n;
pr " const char **%s;\n" n
| Bool n
* a NULL parameter.
*)
pr " %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
- | StringList n ->
+ | StringList n | DeviceList n ->
pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
pr " for (i = 0; i < %s_len; ++i) {\n" n;
| OptString n ->
pr " if (j%s)\n" n;
pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
- | StringList n ->
+ | StringList n | DeviceList n ->
pr " for (i = 0; i < %s_len; ++i) {\n" n;
pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
n;
| FileOut n
| Pathname n | Device n | Dev_or_Path n | String n -> pr "withCString %s $ \\%s -> " n n
| OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
- | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
+ | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
| Bool _ | Int _ -> ()
) (snd style);
(* Convert integer arguments. *)
| Bool n -> sprintf "(fromBool %s)" n
| Int n -> sprintf "(fromIntegral %s)" n
| FileIn n | FileOut n
- | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n -> n
+ | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
) (snd style) in
pr "withForeignPtr h (\\p -> c_%s %s)\n" name
(String.concat " " ("p" :: args));
(match arg with
| Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
| OptString _ -> if hs then pr "Maybe String" else pr "CString"
- | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
+ | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
| Bool _ -> pr "%s" bool
| Int _ -> pr "%s" int
| FileIn _ -> pr "%s" string
| FileIn n
| FileOut n -> pr " printf (\"%%s\\n\", %s);\n" n
| OptString n -> pr " printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
- | StringList n -> pr " print_strings (%s);\n" n
+ | StringList n | DeviceList n -> pr " print_strings (%s);\n" n
| Bool n -> pr " printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
| Int n -> pr " printf (\"%%d\\n\", %s);\n" n
) (snd style);