[svn:PHP-Sandwich] rev 980 - in PHP-Sandwich/trunk: . PHP stuff t
[email protected] 14 Apr 2005 03:31:34 -0000
| Newsgroups | perl.php.sandwich.dev |
|---|---|
| Message-ID | <[email protected]> |
Author: gschlossnagle
Date: Wed Apr 13 20:31:34 2005
New Revision: 980
Added:
PHP-Sandwich/trunk/Makefile.PL
PHP-Sandwich/trunk/PHP/
PHP-Sandwich/trunk/PHP.pm
PHP-Sandwich/trunk/PHP.xs
PHP-Sandwich/trunk/PHP/Interpreter.pm
PHP-Sandwich/trunk/phpinterp.c
PHP-Sandwich/trunk/phpinterp.h
PHP-Sandwich/trunk/stuff/
PHP-Sandwich/trunk/stuff/TSRM.patch
PHP-Sandwich/trunk/t/
PHP-Sandwich/trunk/t/1.pl (contents, props changed)
PHP-Sandwich/trunk/t/2.pl (contents, props changed)
PHP-Sandwich/trunk/typemap
Modified:
PHP-Sandwich/trunk/README
Log:
initial commit
Added: PHP-Sandwich/trunk/Makefile.PL
==============================================================================
--- (empty file)
+++ PHP-Sandwich/trunk/Makefile.PL Wed Apr 13 20:31:34 2005
@@ -0,0 +1,26 @@
+use ExtUtils::MakeMaker 5.16 ;
+use Config ;
+use POSIX;
+
+#push @libs, `/usr/local/bin/php-config --libs`;
+push @libs, '-lphp5';
+
+use Data::Dumper;
+print Dumper(@libs);
+
+@lddlflags = ($Config{lddlflags});
+push @lddlflags, `/usr/local/bin/php-config --ldflags`;
+
+@ofiles = ('PHP.o', 'phpinterp.o');
+
+WriteMakefile(
+ CC => $ENV{CC},
+ CCFLAGS => '-g',
+ OBJECT => join(' ',@ofiles),
+ NAME => 'PHP',
+ VERSION_FROM => 'PHP.pm',
+ PMLIBDIRS => ['PHP'],
+ LIBS => join(' ',@libs),
+ LDDLFLAGS => join(' ',@lddlflags),
+ INC => "-I/usr/local/include ".`/usr/local/bin/php-config --includes`
+ );
Added: PHP-Sandwich/trunk/PHP.pm
==============================================================================
--- (empty file)
+++ PHP-Sandwich/trunk/PHP.pm Wed Apr 13 20:31:34 2005
@@ -0,0 +1,15 @@
+package PHP;
+
+require Exporter;
+require DynaLoader;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $AUTOLOAD);
+$VERSION = "0.9";
+
+@ISA = qw(Exporter DynaLoader);
+
+bootstrap PHP;
+
+1;
+__END__
Added: PHP-Sandwich/trunk/PHP.xs
==============================================================================
--- (empty file)
+++ PHP-Sandwich/trunk/PHP.xs Wed Apr 13 20:31:34 2005
@@ -0,0 +1,273 @@
+/* vim: set sts=2 ts=2 expandtab bs=2 ai : */
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#ifndef PERL_VERSION
+#include "patchlevel.h"
+#define PERL_REVISION 5
+#define PERL_VERSION PATCHLEVEL
+#define PERL_SUBVERSION SUBVERSION
+#endif
+
+#include "phpinterp.h"
+
+#if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 ))
+
+# define PL_sv_undef sv_undef
+# define PL_na na
+# define PL_curcop curcop
+# define PL_compiling compiling
+
+#endif
+
+#define PHP_Interpreter sandwich_per_interp *
+#define PHP_Var_Scalar zval *
+
+zval *SvZval(SV *sv)
+{
+ zval *retval;
+ MAKE_STD_ZVAL(retval);
+ switch(SvTYPE(sv)) {
+ case SVt_IV: /* int */
+ ZVAL_LONG(retval, SvIV(sv));
+ break;
+ case SVt_NV: /* double */
+ ZVAL_DOUBLE(retval, SvNV(sv));
+ break;
+ case SVt_PV: /* string */
+ {
+ STRLEN strlen;
+ char *str = SvPV(sv, strlen);
+ ZVAL_STRINGL(retval, str, strlen, 1);
+ fprintf(stderr, "SvPV %s\n", str);
+ }
+ break;
+ case SVt_RV: /* reference */
+ break;
+ case SVt_PVAV: /* indexed array */
+ break;
+ case SVt_PVHV: /* assoc. array */
+ break;
+ case SVt_PVCV: /* code */
+ break;
+ case SVt_PVGV: /* glob */
+ break;
+ case SVt_PVMG: /* magic */
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
+void assign_to_zval(zval *zptr, SV *sv)
+{
+ zval_dtor(zptr);
+ switch(SvTYPE(sv)) {
+ case SVt_IV: /* int */
+ ZVAL_LONG(zptr, SvIV(sv));
+ break;
+ case SVt_NV: /* double */
+ ZVAL_DOUBLE(zptr, SvNV(sv));
+ break;
+ case SVt_PV: /* string */
+ {
+ STRLEN strlen;
+ char *str = SvPV(sv, strlen);
+ ZVAL_STRINGL(zptr, str, strlen, 1);
+ fprintf(stderr, "SvPV %s\n", str);
+ }
+ break;
+ case SVt_RV: /* reference */
+ break;
+ case SVt_PVAV: /* indexed array */
+ break;
+ case SVt_PVHV: /* assoc. array */
+ break;
+ case SVt_PVCV: /* code */
+ break;
+ case SVt_PVGV: /* glob */
+ break;
+ case SVt_PVMG: /* magic */
+ break;
+ default:
+ break;
+ }
+}
+
+SV *newSVzval(zval *zptr)
+{
+ switch( zptr->type) {
+ case IS_NULL:
+ fprintf(stderr, "IS_NULL\n");
+ return &PL_sv_undef;
+ break;
+ case IS_LONG:
+ fprintf(stderr, "IS_LONG\n");
+ return newSViv(Z_LVAL_P(zptr));
+ break;
+ case IS_DOUBLE:
+ fprintf(stderr, "IS_ODUBLE\n");
+ return newSVnv(Z_DVAL_P(zptr));
+ break;
+ case IS_BOOL:
+ fprintf(stderr, "IS_BOOL\n");
+ return Z_BVAL_P(zptr) ? &PL_sv_yes : &PL_sv_no;
+ break;
+ case IS_ARRAY:
+ /* FIXME: return by copy, not by reference */
+ fprintf(stderr, "IS_ARRAY\n");
+ return &PL_sv_undef;
+ break;
+ case IS_OBJECT:
+ /* FIXME: return by reference as a PHP::DataType::Object, not by copy */
+ fprintf(stderr, "IS_OBJECT\n");
+ return &PL_sv_undef;
+ break;
+ case IS_STRING:
+ fprintf(stderr, "IS_STRING\n");
+ return newSVpv(Z_STRVAL_P(zptr), Z_STRLEN_P(zptr));
+ break;
+ case IS_RESOURCE:
+ /* FIXME: return by reference as a PHP::DataType::Reference, not by copy */
+ fprintf(stderr, "IS_RESOURCE\n");
+ return &PL_sv_undef;
+ break;
+ case IS_CONSTANT:
+ fprintf(stderr, "IS_CONSTANT\n");
+ return newSVpv(Z_STRVAL_P(zptr), Z_STRLEN_P(zptr));
+ break;
+ case IS_CONSTANT_ARRAY:
+ fprintf(stderr, "IS_CONSTANT_ARRAY\n");
+ /* FIXME: return by copy, not by reference */
+ return &PL_sv_undef;
+ break;
+ default:
+ fprintf(stderr, "Unknown type in newSVzval()\n");
+ return &PL_sv_undef;
+ break;
+ }
+}
+
+MODULE = PHP PACKAGE = PHP::Interpreter PREFIX=SAND_
+
+REQUIRE: 1.9505
+PROTOTYPES: DISABLE
+
+SV* SAND_new(classname)
+ char *classname;
+ CODE:
+ {
+ PHP_Interpreter interp;
+ if(sandwich_php_interpreter_create() == -1) {
+ fprintf(stderr, "Error creating Zend Runtime\n");
+ RETVAL = &PL_sv_undef;
+ return;
+ }
+ interp = sandwich_per_interp_setup();
+ RETVAL = newSV(0);
+ sv_setref_pv(RETVAL, classname, (void *)interp);
+ }
+ OUTPUT:
+ RETVAL
+
+void SAND_eval(interp, code)
+ PHP_Interpreter interp;
+ char *code;
+ CODE:
+ {
+ sandwich_eval(interp, code);
+ }
+
+void SAND_include(interp, file)
+ PHP_Interpreter interp;
+ char *file;
+ CODE:
+ {
+ sandwich_include(interp, file);
+ }
+
+SV *SAND_call(interp, method_name, ...)
+ PHP_Interpreter interp;
+ char *method_name;
+ CODE:
+ {
+ zval method;
+ zval **params = NULL;
+ int i;
+ int param_count = 0;
+ zval *retval;
+ INIT_ZVAL(method);
+ ZVAL_STRING(&method, method_name, 1);
+ if(items > 2) {
+ params = emalloc(sizeof(zval *) * (items - 2));
+ for(i = 2; i< items; i++) {
+ params[i - 2] = SvZval(ST(i));
+ }
+ param_count = items - 2;
+ }
+ retval = sandwich_call_function(interp, &method, params, param_count);
+ if(retval == NULL) {
+ fprintf(stderr, "an error occured calling %s\n", method_name);
+ RETVAL = &PL_sv_undef;
+ } else {
+ SV * c1 = sv_newmortal();
+ switch(retval->type) {
+ case IS_LONG:
+ case IS_BOOL:
+ case IS_DOUBLE:
+ case IS_STRING:
+ RETVAL = NEWSV(0,0);
+ sv_setref_pv(c1, "PHP::Var::Scalar", (void *) retval);
+ sv_magic(RETVAL, c1, PERL_MAGIC_tiedscalar, NULL, 0);
+ break;
+ default:
+ break;
+ }
+ fprintf(stderr, "worked!\n");
+ }
+ zval_dtor(&method);
+ }
+ OUTPUT:
+ RETVAL
+
+void SAND_DESTROY(interp)
+ PHP_Interpreter interp;
+ CODE:
+ {
+ sandwich_per_interp_shutdown(interp);
+ }
+
+MODULE = PHP PACKAGE = PHP::Var::Scalar PREFIX=PHP_V_S_
+
+REQUIRE: 1.9505
+PROTOTYPES: DISABLE
+
+SV* PHP_V_S_FETCH(zptr)
+ PHP_Var_Scalar zptr;
+ CODE:
+ {
+ fprintf(stderr, "PHP::Var::Scalar::FETCH\n");
+ RETVAL = newSVzval(zptr);
+ }
+ OUTPUT:
+ RETVAL
+
+void PHP_V_S_STORE(zptr, new)
+ PHP_Var_Scalar zptr;
+ SV *new;
+ CODE:
+ {
+ fprintf(stderr, "PHP::Var::Scalar::STORE\n");
+ assign_to_zval(zptr, new);
+ }
+
+void PHP_V_S_DESTROY(zptr)
+ PHP_Var_Scalar zptr;
+ CODE:
+ {
+ fprintf(stderr, "PHP::Var::Scalar::DESTROY\n");
+ zval_dtor(zptr);
+ }
+
Added: PHP-Sandwich/trunk/PHP/Interpreter.pm
==============================================================================
--- (empty file)
+++ PHP-Sandwich/trunk/PHP/Interpreter.pm Wed Apr 13 20:31:34 2005
@@ -0,0 +1,19 @@
+package PHP::Interpreter;
+
+use AutoLoader;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $AUTOLOAD);
+
+@ISA = qw(AutoLoader);
+
+sub AUTOLOAD {
+ my $self = shift;
+ my $sub = $AUTOLOAD;
+ $sub =~ s/.*:://;
+ return $self->call($sub, @_);
+}
+
+1;
+
+__END__
Modified: PHP-Sandwich/trunk/README
==============================================================================
--- PHP-Sandwich/trunk/README (original)
+++ PHP-Sandwich/trunk/README Wed Apr 13 20:31:34 2005
@@ -6,4 +6,11 @@
variables loaded into Perl. So PHP executed from Perl can use any Perl
modules.
+BUILD INSTRUCTIONS
+==================
+
+1) Apply stuff/TSRM.patch to a PHP 5.x source tree
+2) Build/install PHP with --enable-maintainer-zts and --enable-embed
+3) Build/Install PHP sources HERE. See non-tests in t/ for examples.
+
Added: PHP-Sandwich/trunk/phpinterp.c
==============================================================================
--- (empty file)
+++ PHP-Sandwich/trunk/phpinterp.c Wed Apr 13 20:31:34 2005
@@ -0,0 +1,221 @@
+#include "phpinterp.h"
+
+static pthread_key_t sandwich_per_thread_info_key;
+
+/* {{{ sandwich SAPI Details */
+
+static int sandwich_sapi_ub_write(const char *str, uint str_length TSRMLS_DC)
+{
+ // FIXME - call out to Perl's selected fh
+ fwrite(str, 1, str_length, stdout);
+ return str_length;
+}
+
+static void sandwich_sapi_reg_server_vars(zval *track_vars_array TSRMLS_DC)
+{
+ // FIXME - register $php here?
+}
+
+static char *sandwich_sapi_read_cookies(TSRMLS_D)
+{
+ return NULL;
+}
+
+static int sandwich_sapi_header_handler(sapi_header_struct *sapi_header,
+ sapi_headers_struct *sapi_headers TSRMLS_DC)
+{
+ // FIXME - call out to perl
+ return SAPI_HEADER_ADD;
+}
+
+static int sandwich_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
+{
+ // FIXME set headers back through perl
+ return SAPI_HEADER_SENT_SUCCESSFULLY;
+}
+
+static void sandwich_sapi_log_message(char *message)
+{
+ // allow this to be overridden nicely?
+ Perl_croak("%s\n", message);
+}
+
+
+
+static sapi_module_struct sandwich_sapi = {
+ "sandwich",
+ "Ham and Cheese",
+ NULL, /* startup */
+ NULL, /* shutdown */
+ NULL, /* activate */
+ NULL, /* deactivate */
+ sandwich_sapi_ub_write,
+ NULL, /* flush */
+ NULL, /* get uid */
+ NULL, /* getenv */
+ zend_error,
+ sandwich_sapi_header_handler,
+ sandwich_sapi_send_headers,
+ NULL, /* send header */
+ NULL, /* read POST */
+ sandwich_sapi_read_cookies,
+ sandwich_sapi_reg_server_vars,
+ sandwich_sapi_log_message,
+ STANDARD_SAPI_MODULE_PROPERTIES
+};
+
+static int ze_started = 0;
+
+int sandwich_php_interpreter_create()
+{
+ zend_compiler_globals *compiler_globals;
+ zend_executor_globals *executor_globals;
+ php_core_globals *core_globals;
+ sapi_globals_struct *sapi_globals;
+ void ***tsrm_ls;
+
+ if(ze_started) {
+ return 0;
+ }
+ pthread_key_create(&sandwich_per_thread_info_key, NULL);
+
+ if (!tsrm_startup(128, 32, TSRM_ERROR_LEVEL_CORE, "/opt/ecelerity/var/log/TSRM.log")) {
+ Perl_croak("Failed to init PHP TSRM!\n");
+ return -1;
+ }
+
+ compiler_globals = ts_resource(compiler_globals_id);
+ executor_globals = ts_resource(executor_globals_id);
+ core_globals = ts_resource(core_globals_id);
+ sapi_globals = ts_resource(sapi_globals_id);
+ tsrm_ls = ts_resource(0);
+
+ sandwich_sapi.php_ini_path_override = "/opt/ecelerity/3rdParty/lib/php.ini";
+ sapi_startup(&sandwich_sapi);
+ ze_started = 1;
+ /* if (FAILURE == php_module_startup(&sandwich_sapi, &ec_php_ext_module, 1)) { */
+ if (FAILURE == php_module_startup(&sandwich_sapi, NULL, 0)) {
+ fprintf(stderr, "Failed to initialize PHP\n");
+ return -1;
+ }
+ return 0;
+}
+
+sandwich_per_interp *sandwich_per_interp_setup()
+{
+ /* if (!conf->eval_ok) return NULL; */
+ sandwich_per_interp *info;
+ void *old_ctx = NULL;
+
+ info = calloc(sizeof(*info), 1);
+
+ if (!info->ctx) {
+ info->ctx = tsrm_new_interpreter_context();
+ old_ctx = tsrm_set_interpreter_context(info->ctx);
+ {
+ TSRMLS_FETCH();
+
+ zend_alter_ini_entry("register_argc_argv", 19, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+ zend_alter_ini_entry("html_errors", 12, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+ zend_alter_ini_entry("implicit_flush", 15, "1", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+ zend_alter_ini_entry("max_execution_time", 19, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+
+ SG(headers_sent) = 1;
+ SG(request_info).no_headers = 1;
+ SG(server_context) = info;
+ SG(options) = SAPI_OPTION_NO_CHDIR;
+ php_request_startup(TSRMLS_C);
+ PG(during_request_startup) = 0;
+ tsrm_set_interpreter_context(old_ctx);
+ }
+ }
+ return info;
+}
+
+void sandwich_per_interp_shutdown(sandwich_per_interp *interp)
+{
+ void *old_ctx = NULL;
+ old_ctx = tsrm_set_interpreter_context(interp->ctx);
+ {
+ TSRMLS_FETCH();
+ php_request_shutdown(NULL);
+ tsrm_free_interpreter_context(interp->ctx);
+ free(interp);
+ }
+ tsrm_set_interpreter_context(old_ctx);
+}
+
+void sandwich_eval(sandwich_per_interp *interp, char *code)
+{
+ void *old_ctx = NULL;
+ old_ctx = tsrm_set_interpreter_context(interp->ctx);
+ {
+ TSRMLS_FETCH();
+ zend_try {
+ if (FAILURE == zend_eval_string_ex(code, NULL, "PHP::eval", 1 TSRMLS_CC)) {
+ Perl_croak("Failed to eval your PHP code\n");
+ goto cleanup;
+ }
+ } zend_catch {
+ Perl_croak("Failed to eval your PHP code\n");
+ goto cleanup;
+ } zend_end_try() {
+ }
+ }
+cleanup:
+ tsrm_set_interpreter_context(old_ctx);
+ return;
+}
+
+void sandwich_include(sandwich_per_interp *interp, char *file)
+{
+ void *old_ctx = NULL;
+ old_ctx = tsrm_set_interpreter_context(interp->ctx);
+ {
+ zend_file_handle file_handle;
+ TSRMLS_FETCH();
+ zend_try {
+ SG(request_info).path_translated = file;
+ file_handle.type = ZEND_HANDLE_FILENAME;
+ file_handle.handle.fd = 0;
+ file_handle.filename = SG(request_info).path_translated;
+ file_handle.opened_path = NULL;
+ file_handle.free_filename = 0;
+fprintf(stderr, "executing %s\n", file_handle.filename);
+ php_execute_script(&file_handle TSRMLS_CC);
+ } zend_catch {
+ Perl_croak("Failed to eval your PHP code\n");
+ goto cleanup;
+ } zend_end_try() {
+ }
+ }
+cleanup:
+ tsrm_set_interpreter_context(old_ctx);
+ return;
+}
+
+zval *sandwich_call_function(sandwich_per_interp *interp, zval *method, zval **params, zend_uint param_count)
+{
+ void *old_ctx = NULL;
+ old_ctx = tsrm_set_interpreter_context(interp->ctx);
+ {
+ TSRMLS_FETCH();
+ zend_try {
+ zval *retval;
+ MAKE_STD_ZVAL(retval);
+ if(call_user_function(EG(function_table), NULL, method, retval, param_count, params TSRMLS_CC) == FAILURE) {
+ return NULL;
+ }
+ return retval;
+ } zend_catch {
+ Perl_croak("Failed to eval your PHP code\n");
+ goto cleanup;
+ } zend_end_try() {
+ }
+ }
+cleanup:
+ tsrm_set_interpreter_context(old_ctx);
+ return;
+}
+
+/* vim: set ts=2 sts=2 ai bs=2 expandtab : */
Added: PHP-Sandwich/trunk/phpinterp.h
==============================================================================
--- (empty file)
+++ PHP-Sandwich/trunk/phpinterp.h Wed Apr 13 20:31:34 2005
@@ -0,0 +1,29 @@
+#undef module_name
+#undef API_EXPORT
+#include <main/php_config.h>
+#include <main/php.h>
+#include <main/php_ini.h>
+#include <main/php_main.h>
+#include <zend.h>
+#include <zend_API.h>
+#include <zend_compile.h>
+#include <zend_ini.h>
+#include <SAPI.h>
+#include <TSRM.h>
+
+
+typedef struct {
+ void *ctx;
+} sandwich_per_interp;
+
+int sandwich_php_interpreter_create();
+
+sandwich_per_interp *sandwich_per_interp_setup();
+
+void sandwhich_per_interp_shutdown(sandwich_per_interp *interp);
+
+void sandwich_eval(sandwich_per_interp *interp, char *code);
+void sandwich_include(sandwich_per_interp *interp, char *file);
+zval *sandwich_call_function(sandwich_per_interp *interp, zval *method, zval **params, zend_uint param_count);
+
+
Added: PHP-Sandwich/trunk/stuff/TSRM.patch
==============================================================================
--- (empty file)
+++ PHP-Sandwich/trunk/stuff/TSRM.patch Wed Apr 13 20:31:34 2005
@@ -0,0 +1,124 @@
+Index: TSRM.c
+===================================================================
+RCS file: /repository/TSRM/TSRM.c,v
+retrieving revision 1.64
+diff -u -p -r1.64 TSRM.c
+--- TSRM.c 20 Mar 2005 09:03:40 -0000 1.64
++++ TSRM.c 8 Apr 2005 16:01:17 -0000
+@@ -379,6 +379,97 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id
+ #endif
+ }
+
++/* frees and interpreter context. You are responsible for making sure that
++ * it is not linked into the TSRM hash, and not marked as the current interpreter */
++void tsrm_free_interpreter_context(void *context)
++{
++ tsrm_tls_entry *next, *thread_resources = (tsrm_tls_entry*)context;
++ int i;
++
++ while (thread_resources) {
++ next = thread_resources->next;
++
++ for (i=0; i<thread_resources->count; i++) {
++ if (resource_types_table[i].dtor) {
++ resource_types_table[i].dtor(thread_resources->storage[i], &thread_resources->storage);
++ }
++ }
++ for (i=0; i<thread_resources->count; i++) {
++ free(thread_resources->storage[i]);
++ }
++ free(thread_resources->storage);
++ free(thread_resources);
++ thread_resources = next;
++ }
++ free(context);
++}
++
++void *tsrm_set_interpreter_context(void *new_ctx)
++{
++ tsrm_tls_entry *current;
++
++#if defined(PTHREADS)
++ current = pthread_getspecific(tls_key);
++#elif defined(TSRM_ST)
++ current = st_thread_getspecific(tls_key);
++#elif defined(TSRM_WIN32)
++ current = TlsGetValue(tls_key);
++#elif defined(BETHREADS)
++ current = (tsrm_tls_entry*)tls_get(tls_key);
++#else
++#warning tsrm_set_interpreter_context is probably broken on this platform
++ current = NULL;
++#endif
++
++ /* TODO: unlink current from the global linked list, and replace it
++ * it with the new context, protected by mutex where appropriate */
++
++ /* Set thread local storage to this new thread resources structure */
++#if defined(PTHREADS)
++ pthread_setspecific(tls_key, new_ctx);
++#elif defined(TSRM_ST)
++ st_thread_setspecific(tls_key, new_ctx);
++#elif defined(TSRM_WIN32)
++ TlsSetValue(tls_key, new_ctx);
++#elif defined(BETHREADS)
++ tls_set(tls_key, new_ctx);
++#endif
++
++ /* return old context, so caller can restore it when they're done */
++ return current;
++}
++
++
++/* allocates a new interpreter context */
++void *tsrm_new_interpreter_context(void)
++{
++ tsrm_tls_entry *new_ctx, *current;
++ THREAD_T thread_id;
++
++ thread_id = tsrm_thread_id();
++ tsrm_mutex_lock(tsmm_mutex);
++
++#if defined(PTHREADS)
++ current = pthread_getspecific(tls_key);
++#elif defined(TSRM_ST)
++ current = st_thread_getspecific(tls_key);
++#elif defined(TSRM_WIN32)
++ current = TlsGetValue(tls_key);
++#elif defined(BETHREADS)
++ current = (tsrm_tls_entry*)tls_get(tls_key);
++#else
++#warning tsrm_new_interpreter_context is probably broken on this platform
++ current = NULL;
++#endif
++
++ new_ctx = malloc(sizeof(*new_ctx));
++ allocate_new_resource(&new_ctx, thread_id);
++
++ /* switch back to the context that was in use prior to our creation
++ * of the new one */
++ return tsrm_set_interpreter_context(current);
++}
++
+
+ /* frees all resources allocated for the current thread */
+ void ts_free_thread(void)
+Index: TSRM.h
+===================================================================
+RCS file: /repository/TSRM/TSRM.h,v
+retrieving revision 1.48
+diff -u -p -r1.48 TSRM.h
+--- TSRM.h 17 Mar 2005 08:15:22 -0000 1.48
++++ TSRM.h 8 Apr 2005 16:01:17 -0000
+@@ -132,6 +132,12 @@ TSRM_API int tsrm_mutex_unlock(MUTEX_T m
+ TSRM_API void *tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler);
+ TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler);
+
++/* these 3 APIs should only be used by people that fully understand the threading model
++ * used by PHP/Zend and the select SAPI. */
++TSRM_API void *tsrm_new_interpreter_context(void);
++TSRM_API void *tsrm_set_interpreter_context(void *new_ctx);
++TSRM_API void tsrm_free_interpreter_context(void *context);
++
+ #define TSRM_SHUFFLE_RSRC_ID(rsrc_id) ((rsrc_id)+1)
+ #define TSRM_UNSHUFFLE_RSRC_ID(rsrc_id) ((rsrc_id)-1)
Added: PHP-Sandwich/trunk/t/1.pl
==============================================================================
--- (empty file)
+++ PHP-Sandwich/trunk/t/1.pl Wed Apr 13 20:31:34 2005
@@ -0,0 +1,10 @@
+#!/opt/ecelerity/3rdParty/bin/perl
+use PHP;
+$p = new PHP::Interpreter();
+$p2 = new PHP::Interpreter();
+$p->eval('$name = "george"; echo "hello $name";');
+$p->eval('echo "hello $name";');
+
+$p2->eval('echo "hello $name";');
+
+$p->include("/home/george/a.php");
Added: PHP-Sandwich/trunk/t/2.pl
==============================================================================
--- (empty file)
+++ PHP-Sandwich/trunk/t/2.pl Wed Apr 13 20:31:34 2005
@@ -0,0 +1,13 @@
+#!/opt/ecelerity/3rdParty/bin/perl
+use PHP;
+use PHP::Interpreter;
+
+$p = new PHP::Interpreter();
+$p->eval('function hello($a) { return "hello $a\n"; }');
+$arg = $p->hello('george');
+use Data::Dumper;
+
+print "REF: ".ref($arg);
+print Dumper $arg;
+
+
Added: PHP-Sandwich/trunk/typemap
==============================================================================
--- (empty file)
+++ PHP-Sandwich/trunk/typemap Wed Apr 13 20:31:34 2005
@@ -0,0 +1,17 @@
+PHP_Interpreter T_PTROBJ_SPECIAL
+PHP_Var_Scalar T_PTROBJ_SPECIAL
+
+INPUT
+T_PTROBJ_SPECIAL
+ if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")) {
+ IV tmp = SvIV((SV*)SvRV($arg));
+ $var = ($type) tmp;
+ }
+ else
+ croak(\"$var is not of type ${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")
+
+OUTPUT
+T_PTROBJ_SPECIAL
+ sv_setref_pv($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\",
+ (void*)$var);
+