X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Fgenerator.ml;h=0b3f263ab5024e995c4b4d92331a0e9803afee79;hp=743118be17733a1836f27dfb699dc9ae4e172c4e;hb=0e422c0f590caf1d5f182c9b22f0b16e2a31b02b;hpb=8ff17e1c9cf348c93ac731281b1e4a0d5fa7caf3 diff --git a/src/generator.ml b/src/generator.ml index 743118b..0b3f263 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -1812,9 +1812,9 @@ See also C, C, C."); [["is_file"; "/known-1"]]); InitISOFS, Always, TestOutputFalse ( [["is_file"; "/directory"]])], - "test if file exists", + "test if a regular file", "\ -This returns C if and only if there is a file +This returns C if and only if there is a regular file with the given C name. Note that it returns false for other objects like directories. @@ -1825,7 +1825,7 @@ See also C."); [["is_dir"; "/known-3"]]); InitISOFS, Always, TestOutputTrue ( [["is_dir"; "/directory"]])], - "test if file exists", + "test if a directory", "\ This returns C if and only if there is a directory with the given C name. Note that it returns false for @@ -5356,6 +5356,68 @@ filesystem can be found. To find the label of a filesystem, use C."); + ("is_chardev", (RBool "flag", [Pathname "path"]), 267, [], + [InitISOFS, Always, TestOutputFalse ( + [["is_chardev"; "/directory"]]); + InitBasicFS, Always, TestOutputTrue ( + [["mknod_c"; "0o777"; "99"; "66"; "/test"]; + ["is_chardev"; "/test"]])], + "test if character device", + "\ +This returns C if and only if there is a character device +with the given C name. + +See also C."); + + ("is_blockdev", (RBool "flag", [Pathname "path"]), 268, [], + [InitISOFS, Always, TestOutputFalse ( + [["is_blockdev"; "/directory"]]); + InitBasicFS, Always, TestOutputTrue ( + [["mknod_b"; "0o777"; "99"; "66"; "/test"]; + ["is_blockdev"; "/test"]])], + "test if block device", + "\ +This returns C if and only if there is a block device +with the given C name. + +See also C."); + + ("is_fifo", (RBool "flag", [Pathname "path"]), 269, [], + [InitISOFS, Always, TestOutputFalse ( + [["is_fifo"; "/directory"]]); + InitBasicFS, Always, TestOutputTrue ( + [["mkfifo"; "0o777"; "/test"]; + ["is_fifo"; "/test"]])], + "test if FIFO (named pipe)", + "\ +This returns C if and only if there is a FIFO (named pipe) +with the given C name. + +See also C."); + + ("is_symlink", (RBool "flag", [Pathname "path"]), 270, [], + [InitISOFS, Always, TestOutputFalse ( + [["is_symlink"; "/directory"]]); + InitISOFS, Always, TestOutputTrue ( + [["is_symlink"; "/abssymlink"]])], + "test if symbolic link", + "\ +This returns C if and only if there is a symbolic link +with the given C name. + +See also C."); + + ("is_socket", (RBool "flag", [Pathname "path"]), 271, [], + (* XXX Need a positive test for sockets. *) + [InitISOFS, Always, TestOutputFalse ( + [["is_socket"; "/directory"]])], + "test if socket", + "\ +This returns C if and only if there is a Unix domain socket +with the given C name. + +See also C."); + ] let all_functions = non_daemon_functions @ daemon_functions @@ -5619,6 +5681,89 @@ type callt = | CallBool of bool | CallBuffer of string +(* Used for the guestfish -N (prepared disk images) option. + * Note that the longdescs are indented by 2 spaces. + *) +let prepopts = [ + ("disk", + "create a blank disk", + [ "size", "100M", "the size of the disk image" ], + " Create a blank disk, size 100MB (by default). + + The default size can be changed by supplying an optional parameter."); + + ("part", + "create a partitioned disk", + [ "size", "100M", "the size of the disk image"; + "partition", "mbr", "partition table type" ], + " Create a disk with a single partition. By default the size of the disk + is 100MB (the available space in the partition will be a tiny bit smaller) + and the partition table will be MBR (old DOS-style). + + These defaults can be changed by supplying optional parameters."); + + ("fs", + "create a filesystem", + [ "filesystem", "ext2", "the type of filesystem to use"; + "size", "100M", "the size of the disk image"; + "partition", "mbr", "partition table type" ], + " Create a disk with a single partition, with the partition containing + an empty filesystem. This defaults to creating a 100MB disk (the available + space in the filesystem will be a tiny bit smaller) with an MBR (old + DOS-style) partition table and an ext2 filesystem. + + These defaults can be changed by supplying optional parameters."); + + ("lv", + "create a disk with logical volume", + [ "name", "/dev/VG/LV", "the name of the VG and LV to use"; + "size", "100M", "the size of the disk image"; + "partition", "mbr", "partition table type" ], + " Create a disk with a single partition, set up the partition as an + LVM2 physical volume, and place a volume group and logical volume + on there. This defaults to creating a 100MB disk with the VG and + LV called /dev/VG/LV. You can change the name of the VG and LV + by supplying an alternate name as the first optional parameter. + + Note this does not create a filesystem. Use 'lvfs' to do that."); + + ("lvfs", + "create a disk with logical volume and filesystem", + [ "name", "/dev/VG/LV", "the name of the VG and LV to use"; + "filesystem", "ext2", "the type of filesystem to use"; + "size", "100M", "the size of the disk image"; + "partition", "mbr", "partition table type" ], + " Create a disk with a single partition, set up the partition as an + LVM2 physical volume, and place a volume group and logical volume + on there. Then format the LV with a filesystem. This defaults to + creating a 100MB disk with the VG and LV called /dev/VG/LV, with an + ext2 filesystem."); + + ("bootroot", + "create a boot and root filesystem", + [ "bootfs", "ext2", "the type of filesystem to use for boot"; + "rootfs", "ext2", "the type of filesystem to use for root"; + "size", "100M", "the size of the disk image"; + "bootsize", "32M", "the size of the boot filesystem"; + "partition", "mbr", "partition table type" ], + " Create a disk with two partitions, for boot and root filesystem. + Format the two filesystems independently. There are several optional + parameters which control the exact layout and filesystem types."); + + ("bootrootlv", + "create a boot and root filesystem using LVM", + [ "name", "/dev/VG/LV", "the name of the VG and LV for root"; + "bootfs", "ext2", "the type of filesystem to use for boot"; + "rootfs", "ext2", "the type of filesystem to use for root"; + "size", "100M", "the size of the disk image"; + "bootsize", "32M", "the size of the boot filesystem"; + "partition", "mbr", "partition table type" ], + " This is the same as 'bootroot' but the root filesystem (only) is + placed on a logical volume, named by default '/dev/VG/LV'. There are + several optional parameters which control the exact layout."); + +] + (* Used to memoize the result of pod2text. *) let pod2text_memo_filename = "src/.pod2text.data" let pod2text_memo : ((int * string * string), string list) Hashtbl.t = @@ -6451,11 +6596,21 @@ and generate_structs_h () = and generate_actions_h () = generate_header CStyle LGPLv2plus; List.iter ( - fun (shortname, style, _, _, _, _, _) -> + fun (shortname, style, _, flags, _, _, _) -> let name = "guestfs_" ^ shortname in + + let deprecated = + List.exists (function DeprecatedBy _ -> true | _ -> false) flags in + let test0 = + String.length shortname >= 5 && String.sub shortname 0 5 = "test0" in + let debug = + String.length shortname >= 5 && String.sub shortname 0 5 = "debug" in + if not deprecated && not test0 && not debug then + pr "#define LIBGUESTFS_HAVE_%s 1\n" (String.uppercase shortname); + generate_prototype ~single_line:true ~newline:true ~handle:"g" name style - ) all_functions + ) all_functions_sorted (* Generate the guestfs-internal-actions.h file. *) and generate_internal_actions_h () = @@ -8800,6 +8955,84 @@ Guestfish will prompt for these separately.\n\n"; | Some txt -> pr "%s\n\n" txt ) all_functions_sorted +and generate_fish_prep_options_h () = + generate_header CStyle GPLv2plus; + + pr "#ifndef PREPOPTS_H\n"; + pr "\n"; + + pr "\ +struct prep { + const char *name; /* eg. \"fs\" */ + + size_t nr_params; /* optional parameters */ + struct prep_param *params; + + const char *shortdesc; /* short description */ + const char *longdesc; /* long description */ + + /* functions to implement it */ + void (*prelaunch) (const char *filename, prep_data *); + void (*postlaunch) (const char *filename, prep_data *, const char *device); +}; + +struct prep_param { + const char *pname; /* parameter name */ + const char *pdefault; /* parameter default */ + const char *pdesc; /* parameter description */ +}; + +extern const struct prep preps[]; +#define NR_PREPS %d + +" (List.length prepopts); + + List.iter ( + fun (name, shortdesc, args, longdesc) -> + pr "\ +extern void prep_prelaunch_%s (const char *filename, prep_data *data); +extern void prep_postlaunch_%s (const char *filename, prep_data *data, const char *device); + +" name name; + ) prepopts; + + pr "\n"; + pr "#endif /* PREPOPTS_H */\n" + +and generate_fish_prep_options_c () = + generate_header CStyle GPLv2plus; + + pr "\ +#include \"fish.h\" +#include \"prepopts.h\" + +"; + + List.iter ( + fun (name, shortdesc, args, longdesc) -> + pr "static struct prep_param %s_args[] = {\n" name; + List.iter ( + fun (n, default, desc) -> + pr " { \"%s\", \"%s\", \"%s\" },\n" n default desc + ) args; + pr "};\n"; + pr "\n"; + ) prepopts; + + pr "const struct prep preps[] = {\n"; + List.iter ( + fun (name, shortdesc, args, longdesc) -> + pr " { \"%s\", %d, %s_args, + \"%s\", + \"%s\", + prep_prelaunch_%s, prep_postlaunch_%s }, +" + name (List.length args) name + (c_quote shortdesc) (c_quote longdesc) + name name; + ) prepopts; + pr "};\n" + (* Generate a C function prototype. *) and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true) ?(single_line = false) ?(newline = false) ?(in_daemon = false) @@ -9950,6 +10183,55 @@ the handle. =back +=head1 AVAILABILITY + +From time to time we add new libguestfs APIs. Also some libguestfs +APIs won't be available in all builds of libguestfs (the Fedora +build is full-featured, but other builds may disable features). +How do you test whether the APIs that your Perl program needs are +available in the version of C that you are using? + +To test if a particular function is available in the C +class, use the ordinary Perl UNIVERSAL method C +(see L). For example: + + use Sys::Guestfs; + if (defined (Sys::Guestfs->can (\"set_verbose\"))) { + print \"\\$h->set_verbose is available\\n\"; + } + +To test if particular features are supported by the current +build, use the L method like the example below. Note +that the appliance must be launched first. + + $h->available ( [\"augeas\"] ); + +Since the L method croaks if the feature is not supported, +you might also want to wrap this in an eval and return a boolean. +In fact this has already been done for you: use +L. + +For further discussion on this topic, refer to +L. + +=head1 STORING DATA IN THE HANDLE + +The handle returned from L is a hash reference. The hash +normally contains a single element: + + { + _g => [private data used by libguestfs] + } + +Callers can add other elements to this hash to store data for their own +purposes. The data lasts for the lifetime of the handle. + +Any fields whose names begin with an underscore are reserved +for private use by libguestfs. We may add more in future. + +It is recommended that callers prefix the name of their field(s) +with some unique string, to avoid conflicts with other users. + =head1 COPYRIGHT Copyright (C) %s Red Hat Inc. @@ -10786,6 +11068,10 @@ void Init__guestfs () c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject); e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError); +#ifdef HAVE_RB_DEFINE_ALLOC_FUNC + rb_define_alloc_func (c_guestfs, ruby_guestfs_create); +#endif + rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0); rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0); @@ -11915,6 +12201,431 @@ namespace Guestfs } " +and generate_php_h () = + generate_header CStyle LGPLv2plus; + + pr "\ +#ifndef PHP_GUESTFS_PHP_H +#define PHP_GUESTFS_PHP_H 1 + +#ifdef ZTS +#include \"TSRM.h\" +#endif + +#define PHP_GUESTFS_PHP_EXTNAME \"guestfs_php\" +#define PHP_GUESTFS_PHP_VERSION \"1.0\" + +PHP_MINIT_FUNCTION (guestfs_php); + +#define PHP_GUESTFS_HANDLE_RES_NAME \"guestfs_h\" + +PHP_FUNCTION (guestfs_create); +PHP_FUNCTION (guestfs_last_error); +"; + + List.iter ( + fun (shortname, style, _, _, _, _, _) -> + pr "PHP_FUNCTION (guestfs_%s);\n" shortname + ) all_functions_sorted; + + pr "\ + +extern zend_module_entry guestfs_php_module_entry; +#define phpext_guestfs_php_ptr &guestfs_php_module_entry + +#endif /* PHP_GUESTFS_PHP_H */ +" + +and generate_php_c () = + generate_header CStyle LGPLv2plus; + + pr "\ +/* NOTE: Be very careful with all macros in PHP header files. The + * morons who wrote them aren't good at making them safe for inclusion + * in arbitrary places in C code, eg. not using 'do ... while(0)' + * or parenthesizing any of the arguments. + */ + +/* NOTE (2): Some parts of the API can't be used on 32 bit platforms. + * Any 64 bit numbers will be truncated. There's no easy way around + * this in PHP. + */ + +#include + +#include +#include + +#include +#include + +#include \"guestfs.h\" + +static int res_guestfs_h; + +static void +guestfs_php_handle_dtor (zend_rsrc_list_entry *rsrc TSRMLS_DC) +{ + guestfs_h *g = (guestfs_h *) rsrc->ptr; + if (g != NULL) + guestfs_close (g); +} + +PHP_MINIT_FUNCTION (guestfs_php) +{ + res_guestfs_h = + zend_register_list_destructors_ex (guestfs_php_handle_dtor, + NULL, PHP_GUESTFS_HANDLE_RES_NAME, module_number); +} + +static function_entry guestfs_php_functions[] = { + PHP_FE (guestfs_create, NULL) + PHP_FE (guestfs_last_error, NULL) +"; + + List.iter ( + fun (shortname, style, _, _, _, _, _) -> + pr " PHP_FE (guestfs_%s, NULL)\n" shortname + ) all_functions_sorted; + + pr " { NULL, NULL, NULL } +}; + +zend_module_entry guestfs_php_module_entry = { +#if ZEND_MODULE_API_NO >= 20010901 + STANDARD_MODULE_HEADER, +#endif + PHP_GUESTFS_PHP_EXTNAME, + guestfs_php_functions, + PHP_MINIT (guestfs_php), + NULL, + NULL, + NULL, + NULL, +#if ZEND_MODULE_API_NO >= 20010901 + PHP_GUESTFS_PHP_VERSION, +#endif + STANDARD_MODULE_PROPERTIES +}; + +#ifdef COMPILE_DL_GUESTFS_PHP +ZEND_GET_MODULE (guestfs_php) +#endif + +PHP_FUNCTION (guestfs_create) +{ + guestfs_h *g = guestfs_create (); + if (g == NULL) { + RETURN_FALSE; + } + + guestfs_set_error_handler (g, NULL, NULL); + + ZEND_REGISTER_RESOURCE (return_value, g, res_guestfs_h); +} + +PHP_FUNCTION (guestfs_last_error) +{ + zval *z_g; + guestfs_h *g; + + if (zend_parse_parameters (ZEND_NUM_ARGS() TSRMLS_CC, \"r\", + &z_g) == FAILURE) { + RETURN_FALSE; + } + + ZEND_FETCH_RESOURCE (g, guestfs_h *, &z_g, -1, PHP_GUESTFS_HANDLE_RES_NAME, + res_guestfs_h); + if (g == NULL) { + RETURN_FALSE; + } + + const char *err = guestfs_last_error (g); + if (err) { + RETURN_STRING (err, 1); + } else { + RETURN_NULL (); + } +} + +"; + + (* Now generate the PHP bindings for each action. *) + List.iter ( + fun (shortname, style, _, _, _, _, _) -> + pr "PHP_FUNCTION (guestfs_%s)\n" shortname; + pr "{\n"; + pr " zval *z_g;\n"; + pr " guestfs_h *g;\n"; + + List.iter ( + function + | String n | Device n | Pathname n | Dev_or_Path n + | FileIn n | FileOut n | Key n + | OptString n + | BufferIn n -> + pr " char *%s;\n" n; + pr " int %s_size;\n" n + | StringList n + | DeviceList n -> + pr " zval *z_%s;\n" n; + pr " char **%s;\n" n; + | Bool n -> + pr " zend_bool %s;\n" n + | Int n | Int64 n -> + pr " long %s;\n" n + ) (snd style); + + pr "\n"; + + (* Parse the parameters. *) + let param_string = String.concat "" ( + List.map ( + function + | String n | Device n | Pathname n | Dev_or_Path n + | FileIn n | FileOut n | BufferIn n | Key n -> "s" + | OptString n -> "s!" + | StringList n | DeviceList n -> "a" + | Bool n -> "b" + | Int n | Int64 n -> "l" + ) (snd style) + ) in + + pr " if (zend_parse_parameters (ZEND_NUM_ARGS() TSRMLS_CC, \"r%s\",\n" + param_string; + pr " &z_g"; + List.iter ( + function + | String n | Device n | Pathname n | Dev_or_Path n + | FileIn n | FileOut n | BufferIn n | Key n + | OptString n -> + pr ", &%s, &%s_size" n n + | StringList n | DeviceList n -> + pr ", &z_%s" n + | Bool n -> + pr ", &%s" n + | Int n | Int64 n -> + pr ", &%s" n + ) (snd style); + pr ") == FAILURE) {\n"; + pr " RETURN_FALSE;\n"; + pr " }\n"; + pr "\n"; + pr " ZEND_FETCH_RESOURCE (g, guestfs_h *, &z_g, -1, PHP_GUESTFS_HANDLE_RES_NAME,\n"; + pr " res_guestfs_h);\n"; + pr " if (g == NULL) {\n"; + pr " RETURN_FALSE;\n"; + pr " }\n"; + pr "\n"; + + List.iter ( + function + | String n | Device n | Pathname n | Dev_or_Path n + | FileIn n | FileOut n | Key n + | OptString n -> + (* Just need to check the string doesn't contain any ASCII + * NUL characters, which won't be supported by the C API. + *) + pr " if (strlen (%s) != %s_size) {\n" n n; + pr " fprintf (stderr, \"libguestfs: %s: parameter '%s' contains embedded ASCII NUL.\\n\");\n" shortname n; + pr " RETURN_FALSE;\n"; + pr " }\n"; + pr "\n" + | BufferIn n -> () + | StringList n + | DeviceList n -> + (* Convert array to list of strings. + * http://marc.info/?l=pecl-dev&m=112205192100631&w=2 + *) + pr " {\n"; + pr " HashTable *a;\n"; + pr " int n;\n"; + pr " HashPosition p;\n"; + pr " zval **d;\n"; + pr " size_t c = 0;\n"; + pr "\n"; + pr " a = Z_ARRVAL_P (z_%s);\n" n; + pr " n = zend_hash_num_elements (a);\n"; + pr " %s = safe_emalloc (n + 1, sizeof (char *), 0);\n" n; + pr " for (zend_hash_internal_pointer_reset_ex (a, &p);\n"; + pr " zend_hash_get_current_data_ex (a, (void **) &d, &p) == SUCCESS;\n"; + pr " zend_hash_move_forward_ex (a, &p)) {\n"; + pr " zval t = **d;\n"; + pr " zval_copy_ctor (&t);\n"; + pr " convert_to_string (&t);\n"; + pr " %s[c] = Z_STRVAL (t);\n" n; + pr " c++;\n"; + pr " }\n"; + pr " %s[c] = NULL;\n" n; + pr " }\n"; + pr "\n" + | Bool n | Int n | Int64 n -> () + ) (snd style); + + (* Return value. *) + let error_code = + match fst style with + | RErr -> pr " int r;\n"; "-1" + | RBool _ + | RInt _ -> pr " int r;\n"; "-1" + | RInt64 _ -> pr " int64_t r;\n"; "-1" + | RConstString _ -> pr " const char *r;\n"; "NULL" + | RConstOptString _ -> pr " const char *r;\n"; "NULL" + | RString _ -> + pr " char *r;\n"; "NULL" + | RStringList _ -> + pr " char **r;\n"; "NULL" + | RStruct (_, typ) -> + pr " struct guestfs_%s *r;\n" typ; "NULL" + | RStructList (_, typ) -> + pr " struct guestfs_%s_list *r;\n" typ; "NULL" + | RHashtable _ -> + pr " char **r;\n"; "NULL" + | RBufferOut _ -> + pr " char *r;\n"; + pr " size_t size;\n"; + "NULL" in + + (* Call the function. *) + pr " r = guestfs_%s " shortname; + generate_c_call_args ~handle:"g" style; + pr ";\n"; + pr "\n"; + + (* Free up parameters. *) + List.iter ( + function + | String n | Device n | Pathname n | Dev_or_Path n + | FileIn n | FileOut n | Key n + | OptString n -> () + | BufferIn n -> () + | StringList n + | DeviceList n -> + pr " {\n"; + pr " size_t c = 0;\n"; + pr "\n"; + pr " for (c = 0; %s[c] != NULL; ++c)\n" n; + pr " efree (%s[c]);\n" n; + pr " efree (%s);\n" n; + pr " }\n"; + pr "\n" + | Bool n | Int n | Int64 n -> () + ) (snd style); + + (* Check for errors. *) + pr " if (r == %s) {\n" error_code; + pr " RETURN_FALSE;\n"; + pr " }\n"; + pr "\n"; + + (* Convert the return value. *) + (match fst style with + | RErr -> + pr " RETURN_TRUE;\n" + | RBool _ -> + pr " RETURN_BOOL (r);\n" + | RInt _ -> + pr " RETURN_LONG (r);\n" + | RInt64 _ -> + pr " RETURN_LONG (r);\n" + | RConstString _ -> + pr " RETURN_STRING (r, 1);\n" + | RConstOptString _ -> + pr " if (r) { RETURN_STRING (r, 1); }\n"; + pr " else { RETURN_NULL (); }\n" + | RString _ -> + pr " char *r_copy = estrdup (r);\n"; + pr " free (r);\n"; + pr " RETURN_STRING (r_copy, 0);\n" + | RBufferOut _ -> + pr " char *r_copy = estrndup (r, size);\n"; + pr " free (r);\n"; + pr " RETURN_STRING (r_copy, 0);\n" + | RStringList _ -> + pr " size_t c = 0;\n"; + pr " array_init (return_value);\n"; + pr " for (c = 0; r[c] != NULL; ++c) {\n"; + pr " add_next_index_string (return_value, r[c], 1);\n"; + pr " free (r[c]);\n"; + pr " }\n"; + pr " free (r);\n"; + | RHashtable _ -> + pr " size_t c = 0;\n"; + pr " array_init (return_value);\n"; + pr " for (c = 0; r[c] != NULL; c += 2) {\n"; + pr " add_assoc_string (return_value, r[c], r[c+1], 1);\n"; + pr " free (r[c]);\n"; + pr " free (r[c+1]);\n"; + pr " }\n"; + pr " free (r);\n"; + | RStruct (_, typ) -> + let cols = cols_of_struct typ in + generate_php_struct_code typ cols + | RStructList (_, typ) -> + let cols = cols_of_struct typ in + generate_php_struct_list_code typ cols + ); + + pr "}\n"; + pr "\n" + ) all_functions_sorted + +and generate_php_struct_code typ cols = + pr " array_init (return_value);\n"; + List.iter ( + function + | name, FString -> + pr " add_assoc_string (return_value, \"%s\", r->%s, 1);\n" name name + | name, FBuffer -> + pr " add_assoc_stringl (return_value, \"%s\", r->%s, r->%s_len, 1);\n" + name name name + | name, FUUID -> + pr " add_assoc_stringl (return_value, \"%s\", r->%s, 32, 1);\n" + name name + | name, (FBytes|FUInt64|FInt64|FInt32|FUInt32) -> + pr " add_assoc_long (return_value, \"%s\", r->%s);\n" + name name + | name, FChar -> + pr " add_assoc_stringl (return_value, \"%s\", &r->%s, 1, 1);\n" + name name + | name, FOptPercent -> + pr " add_assoc_double (return_value, \"%s\", r->%s);\n" + name name + ) cols; + pr " guestfs_free_%s (r);\n" typ + +and generate_php_struct_list_code typ cols = + pr " array_init (return_value);\n"; + pr " size_t c = 0;\n"; + pr " for (c = 0; c < r->len; ++c) {\n"; + pr " zval *z_elem;\n"; + pr " ALLOC_INIT_ZVAL (z_elem);\n"; + pr " array_init (z_elem);\n"; + List.iter ( + function + | name, FString -> + pr " add_assoc_string (z_elem, \"%s\", r->val[c].%s, 1);\n" + name name + | name, FBuffer -> + pr " add_assoc_stringl (z_elem, \"%s\", r->val[c].%s, r->val[c].%s_len, 1);\n" + name name name + | name, FUUID -> + pr " add_assoc_stringl (z_elem, \"%s\", r->val[c].%s, 32, 1);\n" + name name + | name, (FBytes|FUInt64|FInt64|FInt32|FUInt32) -> + pr " add_assoc_long (z_elem, \"%s\", r->val[c].%s);\n" + name name + | name, FChar -> + pr " add_assoc_stringl (z_elem, \"%s\", &r->val[c].%s, 1, 1);\n" + name name + | name, FOptPercent -> + pr " add_assoc_double (z_elem, \"%s\", r->val[c].%s);\n" + name name + ) cols; + pr " add_next_index_zval (return_value, z_elem);\n"; + pr " }\n"; + pr " guestfs_free_%s_list (r);\n" typ + and generate_bindtests () = generate_header CStyle LGPLv2plus; @@ -11968,12 +12679,12 @@ print_strings (char *const *argv) | FileOut n | Key n -> pr " printf (\"%%s\\n\", %s);\n" n | BufferIn n -> - pr " {\n"; - pr " size_t i;\n"; + pr " {\n"; + pr " size_t i;\n"; pr " for (i = 0; i < %s_size; ++i)\n" n; pr " printf (\"<%%02x>\", %s[i]);\n" n; pr " printf (\"\\n\");\n"; - pr " }\n"; + pr " }\n"; | OptString n -> pr " printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n | StringList n | DeviceList n -> pr " print_strings (%s);\n" n | Bool n -> pr " printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n @@ -12427,6 +13138,8 @@ Run it from the top source directory using the command output_to "fish/cmds.c" generate_fish_cmds; output_to "fish/completion.c" generate_fish_completion; output_to "fish/guestfish-actions.pod" generate_fish_actions_pod; + output_to "fish/prepopts.c" generate_fish_prep_options_c; + output_to "fish/prepopts.h" generate_fish_prep_options_h; output_to "ocaml/guestfs.mli" generate_ocaml_mli; output_to "ocaml/guestfs.ml" generate_ocaml_ml; output_to "ocaml/guestfs_c_actions.c" generate_ocaml_c; @@ -12454,6 +13167,8 @@ Run it from the top source directory using the command output_to "haskell/Guestfs.hs" generate_haskell_hs; output_to "haskell/Bindtests.hs" generate_haskell_bindtests; output_to "csharp/Libguestfs.cs" generate_csharp; + output_to "php/extension/php_guestfs_php.h" generate_php_h; + output_to "php/extension/guestfs_php.c" generate_php_c; (* Always generate this file last, and unconditionally. It's used * by the Makefile to know when we must re-run the generator.