passing structs by value
authorMichael Wallner <mike@php.net>
Thu, 21 Jan 2016 08:59:52 +0000 (09:59 +0100)
committerMichael Wallner <mike@php.net>
Thu, 21 Jan 2016 09:00:35 +0000 (10:00 +0100)
13 files changed:
config.m4
m4/psi.m4
m4/psi_const.m4
m4/psi_type.m4
psi.d/glob.psi
psi.d/netdb.psi
psi.d/time.psi
src/libffi.c
src/module.c
src/parser.h
tests/idn/idn.psi
tests/ndbm/ndbm.psi [new file with mode: 0644]
tests/ndbm/ndbm001.phpt [new file with mode: 0644]

index 9cd22a334efd648f68665f1f34706ab076ba450d..9666b1b38f39dbd1c500a209ff44f078d13b1f0a 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -33,6 +33,7 @@ m4_foreach(incfile, [
        [sys_types.m4],
        [sys_uio.m4],
        [sys_utsname.m4],
+       [ndbm.m4],
        [netdb.m4],
        [netinet_in.m4],
        [netinet_tcp.m4],
@@ -75,6 +76,7 @@ if test "$PHP_PSI" != no; then
        PSI_CHECK_SYS_STAT
        PSI_CHECK_SYS_UIO
        PSI_CHECK_SYS_UTSNAME
+       PSI_CHECK_NDBM
        PSI_CHECK_NETDB
        PSI_CHECK_NETINET_IN
        PSI_CHECK_NETINET_TCP
index ae6c81a2ebdc6f3d5e933170f9f62aa840ad8f20..3853fa668374eb426bfe4879dcbdefcf71171c73 100644 (file)
--- a/m4/psi.m4
+++ b/m4/psi.m4
@@ -100,6 +100,9 @@ AC_DEFUN(PSI_INCLUDES, [AC_INCLUDES_DEFAULT()
 #ifdef HAVE_ARPA_NAMESER_H
 # include <arpa/nameser.h>
 #endif
+#ifdef HAVE_NDBM_H
+# include <ndbm.h>
+#endif
 #ifdef HAVE_NETDB_H
 # include <netdb.h>
 #endif
index 71adb03db7ac4571702feb1cf16362475eb1c25c..6b86d11e0b529106cad7810b0a8e0820cee1a38e 100644 (file)
@@ -1,13 +1,13 @@
 # psi_add_str_const(name, value)
 # Add a pre-defined string constant to $PSI_CONSTS
 psi_add_str_const() {
-       cat >>$PSI_CONSTS <<<"  {PSI_T_STRING, \"string\", \"psi\\\\$1\", $2, PSI_T_QUOTED_STRING}, "
+       grep -q "\"psi\\\\\\\\$1\"" $PSI_CONSTS || cat >>$PSI_CONSTS <<<"       {PSI_T_STRING, \"string\", \"psi\\\\$1\", $2, PSI_T_QUOTED_STRING}, "
 }
 
 # psi_add_int_const(name, value)
 # Add a pre-defined int constant to $PSI_CONSTS
 psi_add_int_const() {
-       cat >>$PSI_CONSTS <<<"  {PSI_T_INT, \"int\", \"psi\\\\$1\", \"$2\", PSI_T_NUMBER}, "
+       grep -q "\"psi\\\\\\\\$1\"" $PSI_CONSTS || cat >>$PSI_CONSTS <<<"       {PSI_T_INT, \"int\", \"psi\\\\$1\", \"$2\", PSI_T_NUMBER}, "
 }
 
 dnl PSI_CONST(const name, type)
index dad3b676d540ae2692895270f442580feed486d9..2936ef1e7eff07b047aa0862f6510bd171cdc8cb 100644 (file)
@@ -36,7 +36,7 @@ dnl "uint"), AX_CHECK_SIGN is used to discover signedness of the type.
 dnl Defines a pre-defined type in $PSI_TYPES.
 AC_DEFUN(PSI_TYPE, [
        ifdef(AS_TR_CPP(AC_TYPE_$1), AS_TR_CPP(AC_TYPE_$1))
-       PSI_CHECK_SIZEOF($1, PSI_INCLUDES)
+       PSI_CHECK_SIZEOF($1)
        psi_basic_type=AS_TR_SH($2)
        case $psi_basic_type in
        int)
@@ -60,7 +60,7 @@ dnl Defines a pre-defined type in $PSI_TYPES and a pre-defined struct in
 dnl $PSI_STRUCTS if the type is a struct.
 AC_DEFUN(PSI_OPAQUE_TYPE, [
        ifdef(AS_TR_CPP(AC_TYPE_$1), AS_TR_CPP(AC_TYPE_$1))
-       PSI_CHECK_SIZEOF($1, PSI_INCLUDES)
+       PSI_CHECK_SIZEOF($1)
        if PSI_SH_TEST_SIZEOF($1); then
                psi_type_class=
                AC_CACHE_CHECK(type class of $1, AS_TR_SH([psi_cv_type_class_]$1), [
index ce6f5a72c3510a2758c63e5533e3203b545952d3..72c0c76f9d48c2e9256405edd8004510a9aea84a 100644 (file)
@@ -2,7 +2,7 @@ function psi\glob(string $pattern, int $flags, array &$glob = NULL) : int {
        let path = strval($pattern);
        let flags = intval($flags);
        let err = NULL;
-       let buf = arrval($glob);
+       let buf = &arrval($glob);
        return to_int(glob);
        set $glob = to_array(*buf,
                to_int(gl_matchc),
index 259fcec6f436372c8ab3a23f8b5e1e1bb27f43d7..2b74b2db2e6c9b768f048d32aca03d0d0b93c6fe 100644 (file)
@@ -47,7 +47,7 @@ function psi\gai_strerror(int $errcode) : string {
 function psi\getaddrinfo(string $node, string $service, array $hints, object &$res = NULL) : int {
        let node = strval($node);
        let service = strval($service);
-       let hints = arrval($hints);
+       let hints = &arrval($hints);
        let res = &NULL;
        return to_int(getaddrinfo);
        set $res = to_array(**res,
@@ -60,7 +60,7 @@ function psi\getaddrinfo(string $node, string $service, array $hints, object &$r
                to_string(ai_canonname),
                to_array(*ai_next, ...)
        );
-       free freeaddrinfo(res);
+       free freeaddrinfo(*res);
 }
 
 // extern int getnameinfo(struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
index ff81e932c1c8bc0f73c8cb78604942d9c6d91c94..13959da809a39360888a6bac356f7c7682027ce8 100644 (file)
@@ -18,13 +18,13 @@ function psi\gettimeofday(array &$tv = NULL, array &$tz = NULL) : int {
 
 // extern char *asctime(struct tm *tm);
 function psi\asctime(array $tm = NULL) : string {
-       let tm = arrval($tm);
+       let tm = &arrval($tm);
        return to_string(asctime);
 }
 
 // extern char *asctime_r(struct tm *tm, char *buf);
 function psi\asctime_r(array $tm = NULL) : string {
-       let tm = arrval($tm);
+       let tm = &arrval($tm);
        let buf = calloc(32, psi\SIZEOF_CHAR);
        return to_string(asctime_r);
 }
@@ -64,7 +64,7 @@ function psi\gmtime_r(int $ts) : array {
 
 // extern int nanosleep(struct timespec *rqts, struct timespec *rmts);
 function psi\nanosleep(array $rq = NULL, array &$rm = NULL) : int {
-       let rqts = arrval($rq);
+       let rqts = &arrval($rq);
        let rmts = calloc(1, psi\SIZEOF_STRUCT_TIMESPEC);
        return to_int(nanosleep);
        set $rm = to_array(*rmts,
index 44c591bfdade94dcfb23a420413803da157308c5..d59712cd9a595abe30307e43e4fa85a4a5a8573b 100644 (file)
@@ -160,10 +160,10 @@ static ffi_type **psi_ffi_struct_type_elements(decl_struct *strct) {
 
                ZEND_ASSERT(nels + 1 < argc);
                els[nels++] = type;
-
+//fprintf(stderr, "%s o:%d, a:%d, p:%d l:%d\n", darg->var->name, offset, align, padding, darg->layout->len);
                offset += MAX(align, padding) + darg->layout->len;
        }
-
+//fprintf(stderr, "%s s:%d o=%d\n", strct->name, strct->size, offset);
        ZEND_ASSERT(offset <= strct->size);
        if (offset < strct->size) {
                padding = strct->size - offset;
@@ -186,7 +186,7 @@ static inline ffi_type *psi_ffi_decl_type(decl_type *type) {
                        ffi_type *strct = calloc(1, sizeof(ffi_type));
 
                        strct->type = FFI_TYPE_STRUCT;
-                       strct->size = real->strct->size;
+                       strct->size = 0;//real->strct->size;
                        strct->elements = psi_ffi_struct_type_elements(real->strct);
 
                        real->strct->engine.type = strct;
index 5c8634ac5d9864f79b903191ea2f1a1135d3a258..3e95970cca7cdf6babd0af1665d693d7ca772966 100644 (file)
@@ -23,6 +23,8 @@
 # define PSI_ENGINE "ffi"
 #endif
 
+#include <ndbm.h>
+
 ZEND_DECLARE_MODULE_GLOBALS(psi);
 
 PHP_INI_BEGIN()
@@ -350,6 +352,7 @@ void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
        case PSI_T_DOUBLE:
                mem->dval = zval_get_double(zv);
                break;
+       case PSI_T_VOID:
        case PSI_T_INT8:
        case PSI_T_UINT8:
                if (spec->var->pointer_level) {
@@ -609,7 +612,7 @@ static inline void *psi_do_calloc(let_calloc *alloc)
        return mem;
 }
 
-static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, impl_val *arg_val, decl_struct *strct, void **to_free)
+static inline impl_val *psi_let_val(token_t let_func, impl_arg *iarg, impl_val *arg_val, decl_struct *strct, void **to_free)
 {
        switch (let_func) {
        case PSI_T_BOOLVAL:
@@ -651,7 +654,7 @@ static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, imp
                if (PSI_T_PATHVAL == let_func) {
                        if (SUCCESS != php_check_open_basedir(arg_val->ptr)) {
                                efree(arg_val->ptr);
-                               return FAILURE;
+                               return NULL;
                        }
                }
                break;
@@ -670,8 +673,8 @@ static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, imp
                break;
        case PSI_T_ARRVAL:
                if (iarg->type->type == PSI_T_ARRAY) {
-                       arg_val->ptr = psi_array_to_struct(strct, HASH_OF(iarg->_zv));
-                       *to_free = arg_val->ptr;
+                       arg_val = psi_array_to_struct(strct, HASH_OF(iarg->_zv));
+                       *to_free = arg_val;
                }
                break;
        case PSI_T_OBJVAL:
@@ -679,7 +682,7 @@ static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, imp
                        psi_object *obj;
 
                        if (!instanceof_function(Z_OBJCE_P(iarg->_zv), psi_class_entry)) {
-                               return FAILURE;
+                               return NULL;
                        }
 
                        obj = PSI_OBJ(iarg->_zv, NULL);
@@ -688,7 +691,7 @@ static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, imp
                break;
        EMPTY_SWITCH_DEFAULT_CASE();
        }
-       return SUCCESS;
+       return arg_val;
 }
 
 static inline void *psi_do_let(let_stmt *let)
@@ -724,7 +727,7 @@ static inline void *psi_do_let(let_stmt *let)
        case PSI_LET_FUNC:
                iarg = let->val->data.func->arg;
 
-               if (SUCCESS != psi_let_val(let->val->data.func->type, iarg, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem)) {
+               if (!(darg->ptr = psi_let_val(let->val->data.func->type, iarg, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem))) {
                        return NULL;
                }
        }
@@ -759,8 +762,9 @@ static inline void psi_do_free(free_stmt *fre)
                for (j = 0; j < f->vars->count; ++j) {
                        decl_var *dvar = f->vars->vars[j];
                        decl_arg *darg = dvar->arg;
+                       impl_val *fval = darg->let ? darg->let->ptr : darg->ptr;
 
-                       f->decl->call.args[j] = &darg->val;
+                       f->decl->call.args[j] = deref_impl_val(fval, dvar);
                }
 
                /* FIXME: check in validate_* that free functions return scalar */
@@ -812,6 +816,7 @@ static inline void psi_do_clean(impl *impl)
                        efree(darg->mem);
                        darg->mem = NULL;
                }
+               darg->ptr = &darg->val;
        }
 
        if (impl->func->args->vararg.args) {
@@ -1123,7 +1128,10 @@ static inline impl_vararg *psi_do_varargs(impl *impl) {
                }
 
                va->types[i] = vatype;
-               psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free);
+               /* FIXME: varargs with struct-by-value :) */
+               if (!psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free)) {
+                       return NULL;
+               }
 
                if (to_free) {
                        if (!va->free_list) {
index d5ff8967b4ae2d343bfee026e9e1d7748896179a..19bea06429c90c35cebbf12f921f592d241da163 100644 (file)
@@ -1213,7 +1213,7 @@ static inline impl_val *enref_impl_val(void *ptr, decl_var *var) {
                        var->name, var->pointer_level, var->arg->var->pointer_level,
                        var->array_size, var->arg->var->array_size);
 #endif
-       if (!var->pointer_level && real_decl_type(var->arg->type)->type != PSI_T_STRUCT) {
+       if (!var->pointer_level ){//&& real_decl_type(var->arg->type)->type != PSI_T_STRUCT) {
                return ptr;
        }
 
index 2bed911651c95d2af4745eb8bf1fcd843bdf5913..7c585b793bb7c89ff6c0302813a7f6166845c948 100644 (file)
@@ -27,7 +27,7 @@ function idn\utf8_to_ascii(string $host, string &$result, int $flags = 0) : int
        let flags = intval($flags);
        set $result = to_string(*buffer);
        return to_int(idna_to_ascii_8z);
-       free free(buffer);
+       free free(*buffer);
 }
 default char *idna_strerror(int rc);
 function idn\strerror(int $rc) : string {
diff --git a/tests/ndbm/ndbm.psi b/tests/ndbm/ndbm.psi
new file mode 100644 (file)
index 0000000..e61ba2d
--- /dev/null
@@ -0,0 +1,28 @@
+function psi\dbm_open(string $file, int $open_flags, int $file_mode) : object {
+       let file = pathval($file);
+       let open_flags = intval($open_flags);
+       let file_mode = intval($file_mode);
+       return to_object(dbm_open);
+}
+
+function psi\dbm_store(object $db, array $key, array $data, int $mode) : int {
+       let db = objval($db);
+       let key = arrval($key);
+       let content = arrval($data);
+       let store_mode = intval($mode);
+       return to_int(dbm_store);
+}
+
+function psi\dbm_fetch(object $db, array $key) : array {
+       let db = objval($db);
+       let key = arrval($key);
+       return to_array(dbm_fetch,
+               to_string(dptr, dsize),
+               to_int(dsize)
+       );
+}
+
+function psi\dbm_close(object $db) : void {
+       let db = objval($db);
+       return void(dbm_close);
+}
diff --git a/tests/ndbm/ndbm001.phpt b/tests/ndbm/ndbm001.phpt
new file mode 100644 (file)
index 0000000..e14f3f1
--- /dev/null
@@ -0,0 +1,59 @@
+--TEST--
+ndbm
+--INI--
+psi.directory={PWD}:{PWD}/../../psi.d
+--SKIPIF--
+<?php 
+extension_loaded("psi") or die("skip - need ext/psi");
+function_exists("psi\\dbm_open") or die("skip - need nbdm support");
+?>
+--FILE--
+===TEST===
+<?php 
+class db {
+       private $db;
+       
+       function __construct($file = "ndbm001.db", $o = 0102, $m = 0640) {
+               if (!$this->db = psi\dbm_open($file, $o, $m)) {
+                       throw new Exception(psi\strerror(psi\errno()));
+               }
+       }
+       
+       function __destruct() {
+               psi\dbm_close($this->db);
+       }
+       
+       function __set($k, $v) {
+               return psi\dbm_store($this->db, [
+                               "dptr" => $k, 
+                               "dsize" => strlen($k)
+                       ], [
+                               "dptr" => $v,
+                               "dsize" => strlen($v)
+                       ], psi\DBM_REPLACE);
+       }
+       
+       function __get($k) {
+               $val = psi\dbm_fetch($this->db, [
+                       "dptr" => $k,
+                       "dsize" => strlen($k)
+               ]);
+               if ($val) {
+                       return $val["dptr"];
+               }
+       }
+}
+
+$db = new db();
+$db->key = "data";
+var_dump($db->key);
+?>
+===DONE===
+--CLEAN--
+<?php 
+@unlink("ndbm001.db");
+?>
+--EXPECT--
+===TEST===
+string(4) "data"
+===DONE===