diff options
-rw-r--r-- | .gitignore | 18 | ||||
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | README | 4 | ||||
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | php/Makefile.am | 58 | ||||
-rw-r--r-- | php/README-PHP | 54 | ||||
-rw-r--r-- | php/extension/config.m4 | 24 | ||||
-rw-r--r-- | php/extension/guestfs_php_001.phpt | 17 | ||||
-rw-r--r-- | php/extension/guestfs_php_002.phpt | 36 | ||||
-rw-r--r-- | php/extension/guestfs_php_003.phpt | 39 | ||||
-rw-r--r-- | php/guestfs_php.ini | 2 | ||||
-rwxr-xr-x | php/run-php-tests.sh | 35 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rwxr-xr-x | src/generator.ml | 427 | ||||
-rw-r--r-- | src/guestfs.pod | 9 |
15 files changed, 733 insertions, 2 deletions
@@ -181,6 +181,24 @@ perl/Makefile-pl perl/Makefile-pl.old perl/Makefile.PL perl/pm_to_blib +php/extension/Makefile.fragments +php/extension/Makefile.global +php/extension/Makefile.objects +php/extension/acinclude.m4 +php/extension/build/ +php/extension/config.nice +php/extension/configure.in +php/extension/guestfs_php.c +php/extension/guestfs_php_*.diff +php/extension/guestfs_php_*.exp +php/extension/guestfs_php_*.log +php/extension/guestfs_php_*.out +php/extension/guestfs_php_*.php +php/extension/mkinstalldirs +php/extension/modules/ +php/extension/php_guestfs_php.h +php/extension/run-tests.php +php/extension/tmp-php.ini pod2htm?.tmp po/*.gmo po/Makevars.template diff --git a/Makefile.am b/Makefile.am index ce2f940c..e9b38eae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,6 +54,9 @@ endif if HAVE_HASKELL SUBDIRS += haskell endif +if HAVE_PHP +SUBDIRS += php +endif # Virt-inspector, tools and guestmount. if HAVE_INSPECTOR @@ -18,7 +18,7 @@ FUSE. Libguestfs is a library that can be linked with C and C++ management programs (or management programs written in OCaml, Perl, Python, Ruby, -Java, Haskell or C#). You can also use it from shell scripts or the +Java, PHP, Haskell or C#). You can also use it from shell scripts or the command line. Libguestfs was written by Richard W.M. Jones (rjones@redhat.com) and @@ -96,6 +96,8 @@ in virt-inspector). - (Optional) po4a for translating manpages and POD files. +- (Optional) PHP, phpize if you want to build the PHP bindings + Running ./configure will check you have all the requirements installed on your machine. diff --git a/configure.ac b/configure.ac index 935abdc7..5a44d8bc 100644 --- a/configure.ac +++ b/configure.ac @@ -772,6 +772,11 @@ dnl po4a for translating man pages and POD files (optional). AC_CHECK_PROG([PO4A],[po4a],[po4a],[no]) AM_CONDITIONAL([HAVE_PO4A], [test "x$PO4A" != "xno"]) +dnl PHP +AC_CHECK_PROG([PHP],[php],[php],[no]) +AC_CHECK_PROG([PHPIZE],[phpize],[phpize],[no]) +AM_CONDITIONAL([HAVE_PHP], [test "x$PHP" != "xno" -a "x$PHPIZE" != "xno"]) + dnl Library versioning. MAX_PROC_NR=`cat $srcdir/src/MAX_PROC_NR` AC_SUBST(MAX_PROC_NR) @@ -808,6 +813,7 @@ AC_CONFIG_FILES([Makefile fuse/Makefile po-docs/Makefile po-docs/ja/Makefile + php/Makefile ocaml/META perl/Makefile.PL]) AC_OUTPUT @@ -834,6 +840,8 @@ echo -n "Java bindings ....................... " if test "x$HAVE_JAVA_TRUE" = "x"; then echo "yes"; else echo "no"; fi echo -n "Haskell bindings .................... " if test "x$HAVE_HASKELL_TRUE" = "x"; then echo "yes"; else echo "no"; fi +echo -n "PHP bindings ........................ " +if test "x$HAVE_PHP_TRUE" = "x"; then echo "yes"; else echo "no"; fi echo -n "virt-inspector ...................... " if test "x$HAVE_INSPECTOR_TRUE" = "x"; then echo "yes"; else echo "no"; fi echo -n "virt-* tools ........................ " diff --git a/php/Makefile.am b/php/Makefile.am new file mode 100644 index 00000000..49efcde0 --- /dev/null +++ b/php/Makefile.am @@ -0,0 +1,58 @@ +# libguestfs PHP bindings +# Copyright (C) 2010 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +include $(top_srcdir)/subdir-rules.mk + +generator_built = \ + extension/php_guestfs_php.h \ + extension/guestfs_php.c + +EXTRA_DIST = \ + $(generator_built) \ + run-php-tests.sh \ + extension/guestfs_php_*.phpt \ + extension/config.m4 \ + README-PHP \ + guestfs_php.ini + +if HAVE_PHP + +phpdir = $(sysconfdir)/php.d +php_DATA = guestfs_php.ini + +# In theory: EXTRA_LIBS="-lguestfs" In fact this doesn't work +# and we need to add the library to EXTRA_LDFLAGS. +all: extension/config.h + $(MAKE) -C extension \ + EXTRA_INCLUDES="-I$(abs_srcdir)/../src" \ + EXTRA_LDFLAGS="-L$(abs_srcdir)/../src/.libs -lguestfs" \ + all + +extension/config.h: extension/config.m4 ../config.status + cd extension && phpize + cd extension && ./configure --prefix=$(prefix) --libdir=$(libdir) + test -f "$@" && touch -- $@ + +TESTS = run-php-tests.sh + +clean-local: + $(MAKE) -C extension clean + +install-data-hook: + $(MAKE) -C extension INSTALL_ROOT=$(DESTDIR) install + +endif diff --git a/php/README-PHP b/php/README-PHP new file mode 100644 index 00000000..b5ad3c3a --- /dev/null +++ b/php/README-PHP @@ -0,0 +1,54 @@ +NOTE: The PHP API is not complete on 32 bit architectures. PHP +doesn't offer any convenient 64 bit type (on 32 bit). Any 64 bit +parameters or return values will be truncated to 32 bits on these +platforms. You should always use these PHP bindings on a 64 bit +operating system. + +To install the extension manually, copy guestfs_php.so into the +modules directory (eg. /usr/local/lib/php/modules/) and copy +guestfs_php.ini into the config directory (eg. /etc/php.d/). +[Note: On packaged Linux distributions you don't need to do this] + +The PHP API follows the C API. Refer to guestfs(3) or +http://libguestfs.org/guestfs.3.html for the details of the C API. + +To create a handle, use guestfs_create() like this: + + <?php + $g = guestfs_create (); + if ($g == false) { + echo ("Failed to create guestfs_php handle.\n"); + exit; + } + ?> + +Handles are closed implicitly by the PHP dtor. + +All of the usual functions from the C API are available. By +convention these return 'false' for errors, so: + + <?php + //... + if (guestfs_launch ($g) == false) { + echo ("Error: ".guestfs_last_error ($g)."\n"); + exit; + } + ?> + +or: + + <?php + //... + $version = guestfs_version ($g); + if ($version == false) { + echo ("Error: ".guestfs_last_error ($g)."\n"); + exit; + } + echo ("libguestfs version = ". + $version["major"].".".$version["minor"].".".$version["release"]. + $version["extra"]."\n"); + ?> + +C API structs are mapped to associative arrays. C API lists of +structs are mapped to arrays of associative arrays. Other C API +parameters and return values are mapped to natural PHP types. diff --git a/php/extension/config.m4 b/php/extension/config.m4 new file mode 100644 index 00000000..2bac2ea5 --- /dev/null +++ b/php/extension/config.m4 @@ -0,0 +1,24 @@ +# libguestfs PHP bindings +# Copyright (C) 2010 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +PHP_ARG_ENABLE(guestfs_php, enable libguestfs PHP bindings, + [ --enable-guestfs-php Enable libguestfs support]) + +if test "$PHP_GUESTFS_PHP" = "yes"; then + AC_DEFINE(HAVE_GUESTFS_PHP, 1, [Whether you have libguestfs PHP bindings]) + PHP_NEW_EXTENSION(guestfs_php, guestfs_php.c, $ext_shared) +fi diff --git a/php/extension/guestfs_php_001.phpt b/php/extension/guestfs_php_001.phpt new file mode 100644 index 00000000..771592ff --- /dev/null +++ b/php/extension/guestfs_php_001.phpt @@ -0,0 +1,17 @@ +--TEST-- +Load the module and create a handle. +--FILE-- +<?php + +// See comment in php/run-php-tests.sh. +//putenv ('LIBGUESTFS_DEBUG=1'); + +$g = guestfs_create (); +if ($g == false) { + echo ("Failed to create guestfs_php handle.\n"); + exit; +} +echo ("Created guestfs_php handle.\n"); +?> +--EXPECT-- +Created guestfs_php handle. diff --git a/php/extension/guestfs_php_002.phpt b/php/extension/guestfs_php_002.phpt new file mode 100644 index 00000000..48ee0b60 --- /dev/null +++ b/php/extension/guestfs_php_002.phpt @@ -0,0 +1,36 @@ +--TEST-- +Launch the appliance. +--FILE-- +<?php + +// See comment in php/run-php-tests.sh. +//putenv ('LIBGUESTFS_DEBUG=1'); + +$g = guestfs_create (); +if ($g == false) { + echo ("Failed to create guestfs_php handle.\n"); + exit; +} +if (guestfs_add_drive ($g, "/dev/null") == false) { + echo ("Error: ".guestfs_last_error ($g)."\n"); + exit; +} +if (guestfs_launch ($g) == false) { + echo ("Error: ".guestfs_last_error ($g)."\n"); + exit; +} +$version = guestfs_version ($g); +if ($version == false) { + echo ("Error: ".guestfs_last_error ($g)."\n"); + exit; +} +if (!is_int ($version["major"]) || + !is_int ($version["minor"]) || + !is_int ($version["release"]) || + !is_string ($version["extra"])) { + echo ("Error: incorrect return type from guestfs_version\n"); +} +echo ("OK\n"); +?> +--EXPECT-- +OK diff --git a/php/extension/guestfs_php_003.phpt b/php/extension/guestfs_php_003.phpt new file mode 100644 index 00000000..c4eb5b0a --- /dev/null +++ b/php/extension/guestfs_php_003.phpt @@ -0,0 +1,39 @@ +--TEST-- +Create a disk containing LV and filesystem. +--FILE-- +<?php + +// See comment in php/run-php-tests.sh. +//putenv ('LIBGUESTFS_DEBUG=1'); + +$g = guestfs_create (); +if ($g == false) { + die ("Failed to create guestfs_php handle.\n"); +} + +$tmp = dirname(__FILE__)."/test.img"; +$size = 100 * 1024 * 1024; +if (! $fp = fopen ($tmp, 'r+')) { + die ("Error: cannot create file '".$tmp."'\n"); +} +ftruncate ($fp, $size); +fclose ($fp); + +if (! guestfs_add_drive ($g, "test.img") || + ! guestfs_launch ($g) || + ! guestfs_part_disk ($g, "/dev/sda", "mbr") || + ! guestfs_pvcreate ($g, "/dev/sda") || + ! guestfs_vgcreate ($g, "VG", array ("/dev/sda")) || + ! guestfs_lvcreate ($g, "LV", "VG", 64) || + ! guestfs_mkfs ($g, "ext2", "/dev/VG/LV")) { + die ("Error: ".guestfs_last_error ($g)."\n"); +} +echo ("OK\n"); +?> +--CLEAN-- +<?php +$tmp = dirname(__FILE__)."/test.img"; +unlink ($tmp); +?> +--EXPECT-- +OK diff --git a/php/guestfs_php.ini b/php/guestfs_php.ini new file mode 100644 index 00000000..b490a445 --- /dev/null +++ b/php/guestfs_php.ini @@ -0,0 +1,2 @@ +; Enable guestfs_php extension module +extension=guestfs_php.so diff --git a/php/run-php-tests.sh b/php/run-php-tests.sh new file mode 100755 index 00000000..38a5e38f --- /dev/null +++ b/php/run-php-tests.sh @@ -0,0 +1,35 @@ +#!/bin/sh - +# Copyright (C) 2010 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +set -e +cd extension + +TESTS=$(echo guestfs_php_*.phpt) +echo TESTS: $TESTS + +# The PHP test script cleans the environment, so LIBGUESTFS_DEBUG=1 +# won't get passed down to the script. Furthermore, setting +# LIBGUESTFS_DEBUG=1 isn't very useful anyway because the PHP test +# script mixes stdout and stderr together and compares this to the +# expected output, so you'd just get failures for every test. So +# there is no good way to debug libguestfs failures in PHP tests, but +# if an individual test fails locally then you can edit the +# guestfs_php_*.phpt and uncomment the putenv statement, then look at +# the output. +unset LIBGUESTFS_DEBUG + +make test TESTS="$TESTS" diff --git a/po/POTFILES.in b/po/POTFILES.in index 3faa1fbc..a06249ab 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -98,6 +98,7 @@ perl/Guestfs.c perl/bindtests.pl perl/lib/Sys/Guestfs.pm perl/lib/Sys/Guestfs/Lib.pm +php/extension/guestfs_php.c python/guestfs-py.c regressions/rhbz501893.c regressions/test-lvm-mapping.pl diff --git a/src/generator.ml b/src/generator.ml index 1d5707dd..2a5ecfbc 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -11978,6 +11978,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 <config.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <php.h> +#include <php_guestfs_php.h> + +#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; @@ -12517,6 +12942,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. diff --git a/src/guestfs.pod b/src/guestfs.pod index 24d5aef1..82fd7a1b 100644 --- a/src/guestfs.pod +++ b/src/guestfs.pod @@ -43,7 +43,7 @@ FUSE. Libguestfs is a library that can be linked with C and C++ management programs (or management programs written in OCaml, Perl, Python, Ruby, -Java, Haskell or C#). You can also use it from shell scripts or the +Java, PHP, Haskell or C#). You can also use it from shell scripts or the command line. You don't need to be root to use libguestfs, although obviously you do @@ -626,6 +626,13 @@ For documentation see the file C<guestfs.mli>. For documentation see L<Sys::Guestfs(3)>. +=item B<PHP> + +For documentation see C<README-PHP> supplied with libguestfs +sources or in the php-libguestfs package for your distribution. + +The PHP binding only works correctly on 64 bit machines. + =item B<Python> For documentation do: |