[svn:PHP-Sandwich] rev 1074 - PHP-Sandwich/trunk

[email protected] 7 Jun 2005 18:16:54 -0000
Newsgroups perl.php.sandwich.dev
Message-ID <[email protected]>
Author: gschlossnagle
Date: Tue Jun  7 11:16:54 2005
New Revision: 1074

Modified:
   PHP-Sandwich/trunk/PHP.xs
   PHP-Sandwich/trunk/phpfuncs.c
Log:
fixes galore to perl object passing, implement iterator interface
for wrapped SVs


Modified: PHP-Sandwich/trunk/PHP.xs
==============================================================================
--- PHP-Sandwich/trunk/PHP.xs	(original)
+++ PHP-Sandwich/trunk/PHP.xs	Tue Jun  7 11:16:54 2005
@@ -121,6 +121,9 @@ zval *SvZval(SV *sv TSRMLS_DC)
           // handle non-PHP classes
         }
       }
+      else if(sv_isobject(orig_sv)) {
+        plsv_wrap_sv(retval, orig_sv TSRMLS_CC);
+      }
       else {
         int i = 0;
         SV *element;

Modified: PHP-Sandwich/trunk/phpfuncs.c
==============================================================================
--- PHP-Sandwich/trunk/phpfuncs.c	(original)
+++ PHP-Sandwich/trunk/phpfuncs.c	Tue Jun  7 11:16:54 2005
@@ -4,6 +4,8 @@
 
 #include "phpinterp.h"
 #include "phpfuncs.h"
+#include "zend_interfaces.h"
+
 
 ZEND_DECLARE_MODULE_GLOBALS(sandwich);
 zend_class_entry *pl_ce;
@@ -360,6 +362,115 @@ PHP_METHOD(perl, eval)
   }
 }
 
+
+static zval *
+sv_prop_read(zval *obj, zval *member, int type TSRMLS_DC)
+{
+  SV           *sv, **value;
+  HV           *hash;
+  zval         *return_value;
+  struct plsv  *pl;
+  char         *key;
+  long         keylen;
+  pTHX;
+
+  pl = zend_object_store_get_object(obj TSRMLS_CC);
+#ifdef USE_ITHREADS
+  aTHX = pl->perl;
+#endif
+  value = NULL;
+  sv = pl->sv;
+  if(!SvROK(sv)) RETURN_FALSE;
+  sv = SvRV(sv);
+  if(SvTYPE(sv) == SVt_PVHV) {
+    hash = (HV *) sv;
+  } else if(SvTYPE(sv) == SVt_PVGV) {
+    hash =  SvSTASH(sv);
+  } else {
+    goto err_out;
+  }
+  key = Z_STRVAL_P(member);
+  keylen = Z_STRLEN_P(member);
+
+  value = hv_fetch(hash, key, keylen, 1);
+  if (!value) {
+    goto err_out;
+  }
+  if(SvMAGICAL(*value)){
+    mg_get(*value);
+  }
+  return_value = SvZval(*value TSRMLS_CC);
+  return return_value;
+  
+err_out:
+  MAKE_STD_ZVAL(return_value);
+  ZVAL_NULL(return_value);
+  return return_value;
+}
+
+static void
+sv_prop_write(zval *object, zval *member, zval *value TSRMLS_DC)
+{
+  SV           *sv, **svpp;
+  HV           *hash;
+  zval         *return_value;
+  struct plsv  *pl;
+  char         *key;
+  long         keylen;
+  pTHX;
+
+  pl = zend_object_store_get_object(object TSRMLS_CC);
+#ifdef USE_ITHREADS
+  aTHX = pl->perl;
+#endif
+  value = NULL;
+  sv = pl->sv;
+  if(!SvROK(sv)) RETURN_FALSE;
+  sv = SvRV(sv);
+  if(SvTYPE(sv) == SVt_PVHV) {
+    hash = (HV *) sv;
+  } else if(SvTYPE(sv) == SVt_PVGV) {
+    hash =  SvSTASH(sv);
+  } else {
+    return;
+  }
+  key = Z_STRVAL_P(member);
+  keylen = Z_STRLEN_P(member);
+  svpp = hv_store(hash, key, keylen, newSVzval(value, SandwichG(php)), 0);
+  if(svpp && SvMAGICAL(*svpp)) {
+    mg_set(*svpp);
+  }
+}
+
+static int
+sv_prop_exists(zval *object, zval *member, int has_set_exists TSRMLS_DC)
+{
+  SV           *sv, **value;
+  HV           *hash;
+  zval         *return_value;
+  struct plsv  *pl;
+  char         *key;
+  long         keylen;
+  pTHX;
+
+  pl = zend_object_store_get_object(object TSRMLS_CC);
+#ifdef USE_ITHREADS
+  aTHX = pl->perl;
+#endif
+  value = NULL;
+  sv = pl->sv;
+  if(!SvROK(sv)) RETURN_FALSE;
+  sv = SvRV(sv);
+  if(SvTYPE(sv) == SVt_PVHV) {
+    hash = (HV *) sv;
+  } else {
+    return FAILURE;
+  }
+  key = Z_STRVAL_P(member);
+  keylen = Z_STRLEN_P(member);
+  return hv_exists(hash, key, keylen);
+}
+
 static int _sv_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS, int offset)
 {
   struct plsv *pl;
@@ -380,7 +491,7 @@ static int _sv_call_method(char *method,
 #endif
   {
     dSP;
-  
+ 
     argc = ZEND_NUM_ARGS();
     args = (zval ***) safe_emalloc(sizeof(zval **), argc, 0);
     if(zend_get_parameters_array_ex(argc, args) == FAILURE) {
@@ -464,7 +575,8 @@ static union _zend_function *sv_get_meth
   return func;
 }
 
-int sv_get_class_name(zval *obj, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC) {
+int sv_get_class_name(zval *obj, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC) 
+{
   if(parent) {
     *class_name_len = strlen("PerlSV") + 1;
     *class_name = estrndup("PerlSV", *class_name_len);
@@ -482,6 +594,143 @@ int sv_get_class_name(zval *obj, char **
   }
 }
 
+struct plsv_iterator {
+  zend_object_iterator iter;
+  SV *sv;
+  HV *hv;
+  char *key;
+  uint keylen;
+  zval *fetch_ahead;
+};
+
+static void plsv_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
+{
+  dTHX;
+  struct plsv_iterator *I = (struct plsv_iterator*)iter->data;
+  if (I->fetch_ahead) {
+    ZVAL_DELREF(I->fetch_ahead);
+    I->fetch_ahead = NULL;
+  }
+  if (I->key) {
+    efree(I->key);
+  }
+  if(I->sv) {
+    SvREFCNT_dec(I->sv);
+  }
+  efree(I);
+}
+
+static int plsv_iter_valid(zend_object_iterator *iter TSRMLS_DC)
+{
+  struct plsv_iterator *I = (struct plsv_iterator*)iter->data;
+  if(!I->hv) return FAILURE;
+  return I->fetch_ahead ? SUCCESS : FAILURE;
+}
+
+static void plsv_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
+{
+  struct plsv_iterator *I = (struct plsv_iterator*)iter->data;
+  zval **ptr_ptr;
+
+  /* sanity */
+  if (!I->fetch_ahead) {
+      *data = NULL;
+      return;
+  }
+
+  ptr_ptr = emalloc(sizeof(*ptr_ptr)); /* leaks somewhere */
+  *ptr_ptr = I->fetch_ahead;
+  ZVAL_ADDREF(I->fetch_ahead);
+  *data = ptr_ptr;
+}
+
+static int plsv_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
+    ulong *int_key TSRMLS_DC)
+{
+  struct plsv_iterator *I = (struct plsv_iterator*)iter->data;
+
+  if (!I->key) {
+      return HASH_KEY_NON_EXISTANT;
+  }
+  *str_key_len = I->keylen;
+  *str_key = estrndup(I->key, I->keylen);
+  return HASH_KEY_IS_STRING;
+}
+
+static void plsv_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
+{
+  struct plsv_iterator *I = (struct plsv_iterator*)iter->data;
+  SV *value;
+  char *key;
+  long keylen;
+  pTHX;
+  if(!I->hv) return;
+  if (I->fetch_ahead) {
+      ZVAL_DELREF(I->fetch_ahead);
+      I->fetch_ahead = NULL;
+  }
+  if(I->key) {
+    efree(I->key);
+    I->key = NULL;
+    I->keylen = 0;
+  }
+  if((value = hv_iternextsv(I->hv, &key, &keylen)) != NULL) {
+      zval *foo;
+      MAKE_STD_ZVAL(foo);
+      ZVAL_STRING(foo, "test", 1);
+      I->key = estrndup(key, keylen);
+      I->keylen = keylen + 1;
+      I->fetch_ahead = foo; // SvZval(value TSRMLS_CC);
+  }
+}
+
+static void plsv_iter_rewind(zend_object_iterator *iter TSRMLS_DC)
+{
+  pTHX;
+  struct plsv_iterator *I = (struct plsv_iterator*)iter->data;
+  if(!I->hv) return;
+  hv_iterinit(I->hv);
+  plsv_iter_move_forwards(iter TSRMLS_CC);
+}
+
+static zend_object_iterator_funcs plsv_iter_funcs = {
+    plsv_iter_dtor,
+    plsv_iter_valid,
+    plsv_iter_get_data,
+    plsv_iter_get_key,
+    plsv_iter_move_forwards,
+    plsv_iter_rewind,
+    NULL
+};
+
+static zend_object_iterator *plsv_iter_get(zend_class_entry *ce, zval *object TSRMLS_DC)
+{
+  struct plsv *pl;
+  struct plsv_iterator *I;
+  SV *sv;
+  pTHX;
+
+  pl = (struct plsv *) zend_object_store_get_object(object TSRMLS_CC);
+
+  I = ecalloc(1, sizeof(*I));
+  I->iter.funcs = &plsv_iter_funcs;
+  I->iter.data = I;
+  SvREFCNT_inc(pl->sv);
+  sv = pl->sv;
+  I->sv = pl->sv;
+  if(SvROK(sv)) { sv = SvRV(sv); }
+  if(SvTYPE(sv) == SVt_PVHV) {
+    I->hv = (HV *) sv;
+  } else {
+    I->hv = NULL;
+    I->fetch_ahead = NULL;
+    I->key = NULL;
+    SvREFCNT_dec(pl->sv);
+    return &I->iter;
+  }
+  return &I->iter;
+}
+
 static function_entry pl_functions[] = {
   PHP_ME(perl, getinstance, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
   {NULL, NULL, NULL}
@@ -688,21 +937,23 @@ PHP_MINIT_FUNCTION(sandwich)
   plobj_handlers.call_method = sandwich_call_method;
 
   INIT_CLASS_ENTRY(plsv, "PerlSV", plsv_functions);
-  
-  plsv.create_object = plsv_create_object;
   plsv_ce = zend_register_internal_class(&plsv TSRMLS_CC);
+  plsv_ce->create_object = plsv_create_object;
+  plsv_ce->get_iterator = plsv_iter_get;
+  zend_class_implements(plsv_ce TSRMLS_CC, 1, zend_ce_traversable);
   if (!plsv_ce) {
     return FAILURE;
   }
-
   memcpy(&plsv_handlers, zend_get_std_object_handlers(), 
       sizeof(plsv_handlers));
 
-  plsv_handlers.read_dimension = sandwich_dim_read;
-  plsv_handlers.write_dimension = sandwich_dim_write;
+  plsv_handlers.read_property = sv_prop_read;
+  plsv_handlers.write_property = sv_prop_write;
+  plsv_handlers.has_property = sv_prop_exists;
   plsv_handlers.get_method = sv_get_method;
   plsv_handlers.call_method = sv_call_method;
   plsv_handlers.get_class_name = sv_get_class_name;
+  
   return SUCCESS;
 }