]> granicus.if.org Git - php/commitdiff
Add an experimental version of the new XSLT extension. This is by no means
authorSterling Hughes <sterling@php.net>
Thu, 26 Apr 2001 00:13:26 +0000 (00:13 +0000)
committerSterling Hughes <sterling@php.net>
Thu, 26 Apr 2001 00:13:26 +0000 (00:13 +0000)
to be used on anything production, if you want to test it, beware, it may or
may not work (feel free to complain to me if it doesn't work, or shower
praise if it does work)...

Mainly in PHP's CVS so that work on the other backends can take place.
The api (function_entry) is what I'm thinking of for all backends.  Every
backend simply needs to define these functions, I'll send an e-mail describing
all this in a bit....

ext/xslt/EXPERIMENTAL [new file with mode: 0644]
ext/xslt/Makefile.in [new file with mode: 0644]
ext/xslt/config.m4 [new file with mode: 0644]
ext/xslt/php_sablot.h [new file with mode: 0644]
ext/xslt/php_xslt.h [new file with mode: 0644]
ext/xslt/sablot.c [new file with mode: 0644]
ext/xslt/tests/001.phpt [new file with mode: 0644]
ext/xslt/xslt.c [new file with mode: 0644]

diff --git a/ext/xslt/EXPERIMENTAL b/ext/xslt/EXPERIMENTAL
new file mode 100644 (file)
index 0000000..6443e99
--- /dev/null
@@ -0,0 +1,5 @@
+this extension is experimental,
+its functions may change their names 
+or move to extension all together 
+so do not rely to much on them 
+you have been warned!
diff --git a/ext/xslt/Makefile.in b/ext/xslt/Makefile.in
new file mode 100644 (file)
index 0000000..df6a07d
--- /dev/null
@@ -0,0 +1,8 @@
+# $Id$
+
+LTLIBRARY_NAME        = libxslt.la
+LTLIBRARY_SOURCES     = xslt.c sablot.c
+LTLIBRARY_SHARED_NAME = xslt.la
+LTLIBRARY_SHARED_LIBADD  = $(XSLT_SHARED_LIBADD)
+
+include $(top_srcdir)/build/dynlib.mk
diff --git a/ext/xslt/config.m4 b/ext/xslt/config.m4
new file mode 100644 (file)
index 0000000..f168506
--- /dev/null
@@ -0,0 +1,81 @@
+dnl config.m4 for extension xslt
+dnl +------------------------------------------------------------------------------+
+dnl |  This is where the magic of the extension reallly is.  Depending on what     |
+dnl |  backend the user chooses, this script performs the magic                    |
+dnl +------------------------------------------------------------------------------+
+dnl   $Id$
+
+PHP_ARG_ENABLE(xslt, whether to enable xslt support,
+[  --enable-xslt           Enable xslt support])
+
+PHP_ARG_WITH(xslt-sablot, whether to enable the sablotron backend,
+[  --with-xslt-sablot      Enable the sablotron backend])
+
+PHP_ARG_WITH(expat-dir, for Sablotron XSL support,
+[  --with-expat-dir=DIR    Sablotron: libexpat dir for Sablotron 0.50])
+
+if test "$PHP_XSLT" != "no"; then
+       if test "$PHP_XSLT_SABLOT" != "no"; then
+               XSLT_CHECK_DIR=$PHP_XSLT_SABLOT
+               XSLT_TEST_FILE=/include/sablot.h
+               XSLT_BACKEND_NAME=Sablotron
+               XSLT_LIBNAME=sablot
+       fi
+
+       condition="$XSLT_CHECK_DIR$XSLT_TEST_FILE"
+
+       if test -r $condition; then
+               XSLT_DIR=$XSLT_CHECK_DIR
+       else
+               AC_MSG_CHECKING(for $XSLT_BACKEND_NAME libraries in the default path)
+               for i in /usr /usr/local; do
+                       condition="$i$XSLT_TEST_FILE"
+                       if test -r $condition; then
+                               XSLT_DIR=$i
+                               AC_MSG_RESULT(found $XSLT_BACKEND_NAME in $i)
+                       fi
+               done
+       fi
+
+       if test -z "$XSLT_DIR"; then
+               AC_MSG_RESULT(not found)
+               AC_MSG_ERROR(Please re-install the $XSLT_BACKEND_NAME distribution)
+       fi
+                                       
+
+       if test -z "$XSLT_DIR"; then
+               AC_MSG_RESULT(not found)
+               AC_MSG_ERROR(Please re-install the $XSLT_BACKEND distribution)
+       fi
+
+       PHP_ADD_INCLUDE($XSLT_DIR/include)
+
+       PHP_SUBST(XSLT_SHARED_LIBADD)
+       PHP_ADD_LIBRARY_WITH_PATH($XSLT_LIBNAME, $XSLT_DIR/lib, XSLT_SHARED_LIBADD)
+
+       if test "$PHP_XSLT_SABLOT" != "no"; then
+               if test -z "$PHP_EXPAT_DIR"; then
+                       PHP_EXPAT_DIR=""
+               fi
+
+               found_expat=no
+               for i in $PHP_EXPAT_DIR $XSLT_DIR; do
+                       if test -f $i/lib/libexpat.a -o -f $i/lib/libexpat.so; then
+                               AC_DEFINE(HAVE_LIBEXPAT2, 1, [ ])
+                               PHP_ADD_LIBRARY_WITH_PATH(expat, $i/lib)
+                               found_expat=yes
+                       fi
+               done
+
+               if test "$found_expat" = "no"; then
+                       PHP_ADD_LIBRARY(xmlparse)
+                       PHP_ADD_LIBRARY(xmltok)
+               fi
+
+               AC_DEFINE(HAVE_SABLOT, 1, [ ])
+               AC_CHECK_LIB(sablot, SablotSetEncoding, AC_DEFINE(HAVE_SABLOT_SET_ENCODING, 1, [ ]))
+       fi
+
+       AC_DEFINE(HAVE_XSLT, 1, [ ])
+       PHP_EXTENSION(xslt, $ext_shared)
+fi
diff --git a/ext/xslt/php_sablot.h b/ext/xslt/php_sablot.h
new file mode 100644 (file)
index 0000000..0f02352
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP version 4.0                                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.02 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available at through the world-wide-web at                           |
+   | http://www.php.net/license/2_02.txt.                                 |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Sterling Hughes <sterling@php.net>                          |
+   +----------------------------------------------------------------------+
+ */
+
+#ifndef PHP_XSLT_H
+#define PHP_XSLT_H
+
+#include "php.h"
+
+#if HAVE_SABLOT
+
+#include "php_xslt.h"
+
+#include <sablot.h>
+
+extern zend_module_entry xslt_module_entry;
+#define phpext_xslt_ptr &xslt_module_entry
+
+#ifdef PHP_WIN32
+#define PHP_XSLT_API __declspec(dllexport)
+#else
+#define PHP_XSLT_API
+#endif
+
+#define XSLT_SCHEME(handle)    ((handle)->handlers->scheme)
+#define XSLT_SAX(handle)       ((handle)->handlers->sax)
+#define XSLT_ERROR(handle)     ((handle)->handlers->error)
+
+#define XSLT_PROCESSOR(handle) ((handle)->processor.ptr)
+
+#define XSLT_ERRNO(handle)     ((handle)->err->no)
+#define XSLT_ERRSTR(handle)    ((handle)->err->str)
+#define XSLT_LOG(handle)       ((handle)->err->log)
+
+PHP_MINIT_FUNCTION(xslt);
+PHP_MINFO_FUNCTION(xslt);
+
+PHP_FUNCTION(xslt_create);
+PHP_FUNCTION(xslt_set_sax_handlers);
+PHP_FUNCTION(xslt_set_scheme_handlers);
+PHP_FUNCTION(xslt_set_error_handler);
+PHP_FUNCTION(xslt_set_base);
+PHP_FUNCTION(xslt_set_encoding);
+PHP_FUNCTION(xslt_set_log);
+PHP_FUNCTION(xslt_process);
+PHP_FUNCTION(xslt_error);
+PHP_FUNCTION(xslt_errno);
+PHP_FUNCTION(xslt_free);
+
+struct scheme_handlers {
+       struct xslt_function *get_all;
+       struct xslt_function *open;
+       struct xslt_function *get;
+       struct xslt_function *put;
+       struct xslt_function *close;
+};
+
+struct sax_handlers {
+       struct xslt_function *doc_start;
+       struct xslt_function *element_start;
+       struct xslt_function *element_end;
+       struct xslt_function *namespace_start;
+       struct xslt_function *namespace_end;
+       struct xslt_function *comment;
+       struct xslt_function *pi;
+       struct xslt_function *characters;
+       struct xslt_function *doc_end;
+};
+
+struct xslt_handlers {
+       struct scheme_handlers   scheme;
+       struct sax_handlers      sax;
+       struct xslt_function    *error;
+};
+
+struct xslt_processor {
+       SablotHandle ptr;
+       long         idx;
+};
+
+struct xslt_log {
+       char *path;
+       int   fd;
+};
+
+struct xslt_error {
+       struct xslt_log  log;
+       char            *str;
+       int              no;
+};
+
+typedef struct {
+       struct xslt_handlers  *handlers;
+       struct xslt_processor  processor;
+       struct xslt_error     *err;
+} php_xslt;
+
+#else
+#define phpext_xslt_ptr NULL
+#endif
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/ext/xslt/php_xslt.h b/ext/xslt/php_xslt.h
new file mode 100644 (file)
index 0000000..1e717ab
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP version 4.0                                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.02 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available at through the world-wide-web at                           |
+   | http://www.php.net/license/2_02.txt.                                 |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Sterling Hughes <sterling@php.net>                          |
+   +----------------------------------------------------------------------+
+ */
+
+#ifndef _PHP_XSLT_H
+#define _PHP_XSLT_H
+
+#include "php.h"
+
+#ifdef HAVE_XSLT
+
+#define XSLT_OBJ(__func)       (&(__func)->obj)
+#define XSLT_FUNC(__func)      ((__func)->func)
+
+struct xslt_function {
+       zval *obj;
+       zval *func;
+};
+
+
+extern void assign_xslt_handler(struct xslt_function **, zval **);
+extern void free_xslt_handler(struct xslt_function *);
+extern void call_xslt_function(char *, struct xslt_function *, int, zval **, zval **);
+
+extern void xslt_debug(char *, char *, ...);
+
+#endif
+
+#endif
diff --git a/ext/xslt/sablot.c b/ext/xslt/sablot.c
new file mode 100644 (file)
index 0000000..12d5f8c
--- /dev/null
@@ -0,0 +1,1568 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP version 4.0                                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.02 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available at through the world-wide-web at                           |
+   | http://www.php.net/license/2_02.txt.                                 |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Sterling Hughes <sterling@php.net>                          |
+   +----------------------------------------------------------------------+
+ */
+
+
+#include "php.h"
+#include "php_xslt.h"
+#include "php_sablot.h"
+#include "ext/standard/info.h"
+
+#if HAVE_SABLOT
+
+#include <sablot.h>
+
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* functions relating to handlers */
+static void register_sax_handler_pair(struct xslt_function **, struct xslt_function **, zval **);
+
+/* Free processor */
+static void free_processor(zend_rsrc_list_entry *);
+
+/* Create an XSLT array */
+static void make_xslt_array(zval **, char ***);
+static void free_xslt_array(char **);
+
+/* Scheme handler functions */
+static int  scheme_getall(void *, SablotHandle, const char *, const char *, char **, int *);
+static int  scheme_freememory(void *, SablotHandle, char *);
+static int  scheme_open(void *, SablotHandle, const char *, const char *, int *);
+static int  scheme_get(void *, SablotHandle, int, char *, int *);
+static int  scheme_put(void *, SablotHandle, int, const char *, int *);
+static int  scheme_close(void *, SablotHandle, int);
+
+/* Sax handler functions */
+static SAX_RETURN sax_startdoc(void *);
+static SAX_RETURN sax_startelement(void *, const char *, const char **);
+static SAX_RETURN sax_endelement(void *, const char *);
+static SAX_RETURN sax_startnamespace(void *, const char *, const char *);
+static SAX_RETURN sax_endnamespace(void *, const char *);
+static SAX_RETURN sax_comment(void *, const char *);
+static SAX_RETURN sax_pi(void *, const char *, const char *);
+static SAX_RETURN sax_characters(void *, const char *, int);
+static SAX_RETURN sax_enddoc(void *);
+
+/* Error handlers */
+static MH_ERROR error_makecode(void *, SablotHandle, int, unsigned short, unsigned short);
+static MH_ERROR error_log(void *, SablotHandle, MH_ERROR, MH_LEVEL, char **);
+static MH_ERROR error_print(void *, SablotHandle, MH_ERROR, MH_LEVEL, char **);
+
+/* Resource related */
+static char le_xslt_name[] = "XSLT Processor";
+static int  le_xslt;
+
+function_entry xslt_functions[] = {
+       PHP_FE(xslt_create,              NULL)
+       PHP_FE(xslt_set_sax_handlers,    NULL)
+       PHP_FE(xslt_set_scheme_handlers, NULL)
+       PHP_FE(xslt_set_error_handler,   NULL)
+       PHP_FE(xslt_set_base,            NULL)
+#ifdef HAVE_SABLOT_SET_ENCODING
+       PHP_FE(xslt_set_encoding,        NULL)
+#else
+       PHP_FALIAS(xslt_set_encoding, warn_not_available, NULL)
+#endif
+       PHP_FE(xslt_set_log,             NULL)
+       PHP_FE(xslt_process,             NULL)
+       PHP_FE(xslt_error,               NULL)
+       PHP_FE(xslt_errno,               NULL)
+       PHP_FE(xslt_free,                NULL)
+};
+
+zend_module_entry xslt_module_entry = {
+       "xslt",
+       xslt_functions,
+       PHP_MINIT(xslt),
+       NULL,
+       NULL,   
+       NULL,
+       PHP_MINFO(xslt),
+       STANDARD_MODULE_PROPERTIES
+};
+
+#ifdef COMPILE_DL_XSLT
+ZEND_GET_MODULE(xslt)
+#endif
+
+/* A structure containing the sax handlers, automatically 
+   registered whether the user defines them or not */
+static SAXHandler sax_handlers = 
+{
+       sax_startdoc,
+       sax_startelement,
+       sax_endelement,
+       sax_startnamespace,
+       sax_endnamespace,
+       sax_comment,
+       sax_pi,
+       sax_characters,
+       sax_enddoc
+};
+
+/* Error handlers, automatically registered */
+static MessageHandler message_handler = {
+       error_makecode,
+       error_log,
+       error_print
+};
+
+/* Scheme handlers automatically registered */
+static SchemeHandler scheme_handler = {
+       scheme_getall,
+       scheme_freememory,
+       scheme_open,
+       scheme_get,
+       scheme_put,
+       scheme_close
+};
+
+
+PHP_MINIT_FUNCTION(xslt)
+{
+       le_xslt = zend_register_list_destructors_ex(free_processor, NULL, le_xslt_name, module_number);
+
+       return SUCCESS;
+}
+
+PHP_MINFO_FUNCTION(xslt)
+{
+       php_info_print_table_start();
+       php_info_print_table_header(2, "XSLT support", "enabled");
+       php_info_print_table_end();
+}
+
+/* {{{ proto resource xslt_create(void) 
+   Create a new XSLT processor */
+PHP_FUNCTION(xslt_create)
+{
+       php_xslt     *handle;      /* The php -> sablotron handle */
+       SablotHandle  processor;   /* The sablotron processor */
+       int           error;       /* The error container */
+
+       /* Allocate the php-sablotron handle */
+       handle                   = emalloc(sizeof(php_xslt));
+       handle->handlers         = emalloc(sizeof(struct xslt_handlers));
+       handle->err              = emalloc(sizeof(struct xslt_error));
+
+       XSLT_LOG(handle).path = NULL;
+
+       /* Allocate the actual processor itself, via sablotron */
+       error = SablotCreateProcessor(&processor);
+       if (error) {
+               XSLT_ERRNO(handle) = error;
+               RETURN_FALSE;
+       }
+
+       /* Save the processor and set the default handlers */
+       XSLT_PROCESSOR(handle) = processor;
+       SablotRegHandler(XSLT_PROCESSOR(handle), HLR_SAX,     (void *) &sax_handlers,    (void *) handle);
+       SablotRegHandler(XSLT_PROCESSOR(handle), HLR_MESSAGE, (void *) &message_handler, (void *) handle);
+       SablotRegHandler(XSLT_PROCESSOR(handle), HLR_SCHEME,  (void *) &scheme_handler,  (void *) handle);
+
+       /* Register the processor as a resource and return it to the user */
+       ZEND_REGISTER_RESOURCE(return_value, handle, le_xslt);
+       
+       /* The resource index, save it for later use */
+       handle->processor.idx = Z_LVAL_P(return_value);
+}
+/* }}} */
+
+/* {{{ proto void xslt_set_sax_handlers(resource processor, array handlers)
+   Set the SAX handlers to be called when the XML document gets processed */
+PHP_FUNCTION(xslt_set_sax_handlers)
+{
+       zval       **processor_p,      /* Resource pointer to the php->sablotron handle */
+                  **sax_handlers_p,   /* Pointer to the sax handlers php array */
+                  **handler;          /* Individual handler, or handler pair */
+       HashTable   *sax_handlers;     /* PHP array of sax handlers */
+       php_xslt    *handle;           /* Pointer to a php_xslt handle */
+       char        *string_key;       /* String key for the hash */
+       ulong        num_key;          /* (unused) hash's numerical key */
+
+       if (ZEND_NUM_ARGS() != 2 ||
+           zend_get_parameters_ex(2, &processor_p, &sax_handlers_p) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_xslt *, processor_p, -1, le_xslt_name, le_xslt);
+       
+       /* Convert the sax_handlers_p zval ** to a hash table we can process */
+       sax_handlers = HASH_OF(*sax_handlers_p);
+       if (!sax_handlers) {
+               php_error(E_WARNING, "Expecting an array as the second argument to xslt_set_sax_handlers()");
+               RETURN_NULL();
+       }
+
+       /* Loop through the HashTable containing the SAX handlers */
+       for (zend_hash_internal_pointer_reset(sax_handlers);
+            zend_hash_get_current_data(sax_handlers, (void **) &handler) == SUCCESS;
+                zend_hash_move_forward(sax_handlers)) {
+
+               /* Allocate the handler */
+               SEPARATE_ZVAL(handler);
+
+               zend_hash_get_current_key(sax_handlers, &string_key, &num_key, 0);
+
+               /* Document handlers (document start, document end) */
+               if (strcasecmp(string_key, "document") == 0) {
+                       register_sax_handler_pair(&XSLT_SAX(handle).doc_start, 
+                                                 &XSLT_SAX(handle).doc_end, 
+                                                 handler);
+               }
+               /* Element handlers, start of an element, and end of an element */
+               else if (strcasecmp(string_key, "element") == 0) {
+                       register_sax_handler_pair(&XSLT_SAX(handle).element_start, 
+                                                 &XSLT_SAX(handle).element_end, 
+                                                 handler);
+               }
+               /* Namespace handlers, start of a namespace, end of a namespace */
+               else if (strcasecmp(string_key, "namespace") == 0) {
+                       register_sax_handler_pair(&XSLT_SAX(handle).namespace_start, 
+                                                 &XSLT_SAX(handle).namespace_end, 
+                                                 handler);
+               }
+               /* Comment handlers, called when a comment is reached */
+               else if (strcasecmp(string_key, "comment") == 0) {
+                       assign_xslt_handler(&XSLT_SAX(handle).comment, handler);
+               }
+               /* Processing instructions handler called when processing instructions
+                  (<? ?>) */
+               else if (strcasecmp(string_key, "pi") == 0) {
+                       assign_xslt_handler(&XSLT_SAX(handle).pi, handler);
+               }
+               /* Character handler, called when data is found */
+               else if (strcasecmp(string_key, "character") == 0) {
+                       assign_xslt_handler(&XSLT_SAX(handle).characters, handler);
+               }
+               /* Invalid handler name, tsk, tsk, tsk :) */
+               else {
+                       php_error(E_WARNING, "Invalid option to xslt_set_sax_handlers(): %s", string_key);
+               }
+       }
+}
+/* }}} */
+
+/* {{{ proto void xslt_set_scheme_handlers(resource processor, array handlers)
+   Set the scheme handlers for the XSLT processor */
+PHP_FUNCTION(xslt_set_scheme_handlers)
+{
+       zval                   **processor_p,       /* Resource pointer to the php->sablotron handle */
+                              **scheme_handlers_p, /* Pointer to the scheme handler array */
+                              **handler;           /* Individual scheme handler */
+       struct xslt_function               *assign_handle;     /* The handler to assign to */
+       HashTable               *scheme_handlers;   /* Scheme handler array */
+       php_xslt                *handle;            /* php->sablotron handle */
+       char                    *string_key;        /* Hash key (string) */
+       ulong                    num_key;           /* (unused) Hash key (number) */
+
+       if (ZEND_NUM_ARGS() != 2 ||
+           zend_get_parameters_ex(2, &processor_p, &scheme_handlers_p) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_xslt *, processor_p, -1, le_xslt_name, le_xslt);
+
+       /* Loop through the scheme handlers array, setting the given
+          scheme handlers */
+       for (zend_hash_internal_pointer_reset(scheme_handlers);
+            zend_hash_get_current_data(scheme_handlers, (void **) &handler) == SUCCESS;
+            zend_hash_move_forward(scheme_handlers)) {
+
+               zend_hash_get_current_key(scheme_handlers, &string_key, &num_key, 0);
+
+               /* Open the URI and return the whole string */
+               if (strcasecmp(string_key, "get_all") == 0) {
+                       assign_handle = XSLT_SCHEME(handle).get_all;
+               }
+               /* Open the URI and return a handle */
+               else if (strcasecmp(string_key, "open") == 0) {
+                       assign_handle = XSLT_SCHEME(handle).open;
+               }
+               /* Retrieve data from the URI */
+               else if (strcasecmp(string_key, "get") == 0) {
+                       assign_handle = XSLT_SCHEME(handle).get;
+               }
+               /* Save data to the URI */
+               else if (strcasecmp(string_key, "put") == 0) {
+                       assign_handle = XSLT_SCHEME(handle).put;
+               }
+               /* Close the URI */
+               else if (strcasecmp(string_key, "close") == 0) {
+                       assign_handle = XSLT_SCHEME(handle).close;
+               }
+               /* Invalid handler name */
+               else {
+                       php_error(E_WARNING, "Invalid option to xslt_set_scheme_handlers(): %s", string_key);
+               }
+
+               /* Actually assign the handlers, yippy! */
+               assign_xslt_handler(&assign_handle, handler);
+       }
+}
+/* }}} */
+
+/* {{{ proto void xslt_set_error_handler(resource processor, mixed error_func)
+   Set the error handler, to be called when an XSLT error happens */
+PHP_FUNCTION(xslt_set_error_handler)
+{
+       zval      **processor_p,   /* Resource Pointer to a PHP-XSLT processor */
+                 **error_func;    /* Name of the user defined error function */
+       php_xslt   *handle;        /* A PHP-XSLT processor */
+       
+       if (ZEND_NUM_ARGS() != 2 ||
+           zend_get_parameters_ex(2, &processor_p, &error_func) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_xslt *, processor_p, -1, le_xslt_name, le_xslt);
+
+       assign_xslt_handler(&XSLT_ERROR(handle), error_func);
+}
+/* }}} */
+
+/* {{{ proto void xslt_set_base(resource processor, string base)
+   Sets the base URI for all XSLT transformations */
+PHP_FUNCTION(xslt_set_base)
+{
+       zval     **processor_p,  /* Resource Pointer to a PHP-XSLT processor */
+                **base;         /* The base URI for the transformation */
+       php_xslt  *handle;       /* A PHP-XSLT processor */
+
+       if (ZEND_NUM_ARGS() != 2 ||
+           zend_get_parameters_ex(2, &processor_p, &base) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_xslt *, processor_p, -1, le_xslt_name, le_xslt);
+       convert_to_string_ex(base);
+
+       /* Set the base */
+       SablotSetBase(XSLT_PROCESSOR(handle), Z_STRVAL_PP(base));
+}
+/* }}} */
+
+/* {{{ proto void xslt_set_encoding(resource processor, string encoding)
+   Set the output encoding for the current stylesheet */
+PHP_FUNCTION(xslt_set_encoding)
+{
+/* The user has to explicitly compile sablotron with sablotron 
+   encoding functions in order for SablotSetEncoding to be 
+   enabled.  config.m4 automatically checks for this... */
+
+#ifdef HAVE_SABLOT_SET_ENCODING
+       zval       **processor_p,  /* Resource Pointer to a PHP-XSLT processor */
+                  **encoding;     /* The encoding to use for the output */
+       php_xslt    *handle;       /* A PHP-XSLT processor */
+
+       if (ZEND_NUM_ARGS() != 2 ||
+           zend_get_parameters_ex(2, &processor_p, &encoding) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_xslt *, processor_p, -1, le_xslt_name, le_xslt);
+       convert_to_string_ex(encoding);
+
+       /* Set the encoding */
+       SablotSetEncoding(XSLT_PROCESSOR(handle), Z_STRVAL_PP(encoding));
+#endif
+
+}
+/* }}} */
+
+/* {{{ proto void xslt_set_log(resource processor, string logfile)
+   Set the log file to write the errors to (defaults to stderr) */
+PHP_FUNCTION(xslt_set_log)
+{
+       zval      **processor_p,             /* Resource pointer to a PHP-XSLT processor */
+                 **logfile;                 /* Path to the logfile */
+       php_xslt   *handle;                  /* A PHP-XSLT processor */
+       int         argc = ZEND_NUM_ARGS();  /* Argument count */
+
+       if (argc < 1 || argc > 2 ||
+           zend_get_parameters_ex(argc, &processor_p, &logfile) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_xslt *, processor_p, -1, le_xslt_name, le_xslt);
+       convert_to_string_ex(logfile);
+       
+       /* If the log file already exists, free it */
+       if (XSLT_LOG(handle).path) {
+               efree(XSLT_LOG(handle).path);
+       }
+       
+       /* Copy the path */
+       XSLT_LOG(handle).path = estrndup(Z_STRVAL_PP(logfile),
+                                        Z_STRLEN_PP(logfile));
+}
+/* }}} */
+
+
+/* {{{ proto string xslt_process(resource processor, string xml, string xslt[, mixed result[, array args[, array params]]])
+   Perform the xslt transformation */
+PHP_FUNCTION(xslt_process)
+{
+       zval       **processor_p,             /* Resource Pointer to a PHP-XSLT processor */
+                  **xml_p,                   /* A zval pointer to the XML data */
+                  **xslt_p,                  /* A zval pointer to the XSLT data */
+                  **result_p,                /* A zval pointer to the transformation results */
+                  **params_p,                /* A zval pointer to the XSLT parameters array */
+                  **args_p;                  /* A zval pointer to the XSLT arguments array */
+       php_xslt    *handle;                  /* A PHP-XSLT processor */
+       char       **params = NULL;           /* A Sablotron parameter array (derived from the zval parameter array) */
+       char       **args   = NULL;           /* A Sablotron argument array (derived from the zval argument array) */
+       char        *xslt;                    /* The XSLT stylesheet or argument buffer (pointer to xslt_p) */
+       char        *xml;                     /* The XML stylesheet or argument buffer (pointer to xml_p) */
+       char        *result;                  /* The result file or argument buffer */
+       int          argc = ZEND_NUM_ARGS();  /* The number of arguments given */
+       int          error;                   /* Our error container */
+
+       if (argc < 3 || argc > 6 ||
+           zend_get_parameters_ex(argc, &processor_p, &xml_p, &xslt_p, &result_p, &args_p, &params_p) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+
+       ZEND_FETCH_RESOURCE(handle, php_xslt *, processor_p, -1, le_xslt_name, le_xslt);
+       convert_to_string_ex(xml_p);
+       convert_to_string_ex(xslt_p);
+
+       xml  = Z_STRVAL_PP(xml_p);
+       xslt = Z_STRVAL_PP(xslt_p);
+
+       /* Well, no result file was given or result buffer, that means (guess what?)
+          we're returning the result yipp di doo! */
+       if (argc < 4 || Z_TYPE_PP(result_p) == IS_NULL) {
+               result = "arg:/_result";
+       }
+       /* The result buffer to place the data into, either a file or an argument buffer, etc. */
+       else {
+               convert_to_string_ex(result_p);
+               result = Z_STRVAL_PP(result_p);
+       }
+
+       /* Translate a PHP array into a Sablotron array */
+       if (argc > 4) {
+               char **p;
+               make_xslt_array(args_p,   &args);
+               
+               for (p = args; *p != NULL; p += 2) {
+                       php_printf("%s: %s\n\n\n", *p, *(p + 1));
+               }
+       }
+       
+       if (argc > 5) {
+               make_xslt_array(params_p, &params);
+       }
+       
+       /* Perform transformation */
+       error = SablotRunProcessor(XSLT_PROCESSOR(handle), xslt, xml, result, params, args);
+       if (error) {
+               XSLT_ERRNO(handle) = error;
+
+               if (params) free_xslt_array(params);
+               if (args) free_xslt_array(args);
+
+               RETURN_FALSE;
+       }
+
+       /* If the result buffer is specified, then we return the results of the XSLT
+          transformation */
+       if (!strcmp(result, "arg:/_result")) {
+               char *trans_result;
+
+               /* Fetch the result buffer into trans_result */
+               error = SablotGetResultArg(handle->processor.ptr, "arg:/_result", &trans_result);
+               if (error) {
+                       /* Save the error number */
+                       XSLT_ERRNO(handle) = error;
+                       
+                       /* Cleanup */
+                       if (params) free_xslt_array(params);
+                       if (args) free_xslt_array(args);
+                       
+                       RETURN_FALSE;
+               }
+
+               RETVAL_STRING(trans_result, 1);
+               SablotFree(trans_result);
+       }
+       else {
+               RETVAL_TRUE;
+       }
+       
+       /* Cleanup */
+       if (params) free_xslt_array(params);
+       if (args) free_xslt_array(args);
+}
+/* }}} */
+
+/* {{{ proto int xslt_errno(resource processor)
+   Error number */
+PHP_FUNCTION(xslt_errno)
+{
+       zval        **processor_p;   /* Resource pointer to a PHP-XSLT processor */
+       php_xslt     *handle;        /* A PHP-XSLT processor */
+
+       if (ZEND_NUM_ARGS() != 1 ||
+           zend_get_parameters_ex(1, &processor_p) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_xslt *, processor_p, -1, le_xslt_name, le_xslt);
+
+       RETURN_LONG(XSLT_ERRNO(handle));
+}
+/* }}} */
+
+/* {{{ proto string xslt_error(resource processor)
+   Error string */
+PHP_FUNCTION(xslt_error)
+{
+       zval      **processor_p;  /* Resource pointer to a PHP-XSLT processor */
+       php_xslt   *handle;       /* A PHP-XSLT processor */
+
+       if (ZEND_NUM_ARGS() != 1 ||
+           zend_get_parameters_ex(1, &processor_p) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_xslt *, processor_p, -1, le_xslt_name, le_xslt);
+
+       RETURN_STRING(XSLT_ERRSTR(handle), 1);  
+}
+/* }}} */
+
+/* {{{ proto void xslt_free(resource processor)
+   Free the xslt processor up */
+PHP_FUNCTION(xslt_free)
+{
+       zval     **processor_p;   /* Resource pointer to a php-xslt processor */
+       php_xslt  *handle;        /* A PHP-XSLT processor */
+       
+       if (ZEND_NUM_ARGS() != 1 ||
+           zend_get_parameters_ex(1, &processor_p) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_xslt *, processor_p, -1, le_xslt_name, le_xslt);
+       
+       /* Remove the entry from the list */
+       zend_list_delete(Z_LVAL_PP(processor_p));
+}
+/* }}} */
+
+/* {{{ free_processor()
+   Free an XSLT processor */
+static void free_processor(zend_rsrc_list_entry *rsrc)
+{
+       php_xslt *handle = (php_xslt *) rsrc->ptr;     /* A PHP-XSLT processor */
+       
+       /* Free the processor */
+       if (XSLT_PROCESSOR(handle)) {
+               SablotUnregHandler(XSLT_PROCESSOR(handle), HLR_MESSAGE, NULL, NULL);
+               SablotUnregHandler(XSLT_PROCESSOR(handle), HLR_SAX,     NULL, NULL);
+               SablotUnregHandler(XSLT_PROCESSOR(handle), HLR_SCHEME,  NULL, NULL);
+               SablotDestroyProcessor(XSLT_PROCESSOR(handle));
+       }
+
+       /* Free Scheme handlers */
+       free_xslt_handler(XSLT_SCHEME(handle).get_all);
+       free_xslt_handler(XSLT_SCHEME(handle).open);
+       free_xslt_handler(XSLT_SCHEME(handle).get);
+       free_xslt_handler(XSLT_SCHEME(handle).put);
+       free_xslt_handler(XSLT_SCHEME(handle).close);
+       /* Free SAX handlers */
+       free_xslt_handler(XSLT_SAX(handle).doc_start);
+       free_xslt_handler(XSLT_SAX(handle).element_start);
+       free_xslt_handler(XSLT_SAX(handle).element_end);
+       free_xslt_handler(XSLT_SAX(handle).namespace_start);
+       free_xslt_handler(XSLT_SAX(handle).namespace_end);
+       free_xslt_handler(XSLT_SAX(handle).comment);
+       free_xslt_handler(XSLT_SAX(handle).pi);
+       free_xslt_handler(XSLT_SAX(handle).characters);
+       free_xslt_handler(XSLT_SAX(handle).doc_end);
+       /* Free error handler */
+       free_xslt_handler(XSLT_ERROR(handle));
+
+       /* Free error message, if any */
+       if (XSLT_ERRSTR(handle)) {
+               efree(XSLT_ERRSTR(handle));
+       }
+
+       /* Close log file */
+       if (XSLT_LOG(handle).fd) {
+               close(XSLT_LOG(handle).fd);
+       }
+       
+       /* Free log file path */
+       if (XSLT_LOG(handle).path) {
+               efree(XSLT_LOG(handle).path);
+       }
+
+       /* Free up the handle */
+       efree(handle->handlers);
+       efree(handle->err);
+       efree(handle);
+}
+/* }}} */
+
+
+/* {{{ register_sax_handler_pair()
+   Register a pair of sax handlers */
+static void register_sax_handler_pair(struct xslt_function **handler1, struct xslt_function **handler2, zval **handler)
+{
+       zval **current;   /* The current handler we're grabbing */
+       
+       /* Grab handler 1 */
+       if (zend_hash_index_find(Z_ARRVAL_PP(handler), 0, (void **) &current) == SUCCESS) {
+               assign_xslt_handler(handler1, current);
+       }
+       else {
+               php_error(E_WARNING, "Wrong format of arguments to xslt_set_sax_handlers()");
+               return;
+       }
+       
+       /* Grab handler 2 */
+       if (zend_hash_index_find(Z_ARRVAL_PP(handler), 1, (void **) &current) == SUCCESS) {
+               assign_xslt_handler(handler2, current);
+       }
+       else {
+               php_error(E_WARNING, "Wrong format of arguments to xslt_set_sax_handlers()");
+               return;
+       }
+}
+/* }}} */
+
+/* {{{ free_xslt_array()
+   Free an XSLT-Sablotron array */
+static void free_xslt_array(char **arr)
+{
+       char **p;
+       
+       /* Free the individual elements */
+       for (p = arr; *p != NULL; p++) {
+               efree(*p);
+       }
+
+       /* Free the entire array */
+       efree(arr);
+}
+/* }}} */
+
+/* {{{ make_xslt_array()
+   Translate a PHP array into an xslt (char **) array */
+static void make_xslt_array(zval **zval_ar, char ***xslt_ar)
+{
+       zval         **current;      /* The current element we are processing */
+       HashTable     *php_ar;       /* The actual array to loop through (derived from the passed zval) */
+       int            idx = 0;      /* The current element of the xslt_ar to assign data to */
+
+       /* Grab the PHP array from the zval */
+       php_ar = HASH_OF(*zval_ar);
+       if (!php_ar) {
+               php_error(E_WARNING, "Array expected");
+               return;
+       }
+
+       /* Allocate the xslt array */
+       *xslt_ar = emalloc(sizeof(char *) * (zend_hash_num_elements(php_ar) + 2));
+
+       /* Loop through the array element by element */
+       for (zend_hash_internal_pointer_reset(php_ar);
+            zend_hash_get_current_data(php_ar, (void **) &current) == SUCCESS;
+                zend_hash_move_forward(php_ar)) {
+               char  *string_key = NULL;
+               ulong  num_key;
+               
+               SEPARATE_ZVAL(current);
+               convert_to_string_ex(current);
+               
+               zend_hash_get_current_key(php_ar, &string_key, &num_key, 1);
+
+               /* Akin to an associative array, first element key, second element is
+                  the value */
+               (*xslt_ar)[idx++] = estrdup(string_key);
+               (*xslt_ar)[idx++] = estrndup(Z_STRVAL_PP(current), Z_STRLEN_PP(current));
+       }
+
+       (*xslt_ar)[idx] = NULL;
+}
+/* }}} */
+
+/* {{{ scheme_getall()
+   The getall scheme handler */
+static int scheme_getall(void *user_data, SablotHandle proc, const char *scheme, const char *rest, char **buffer, int *byte_count)
+{
+       zval       *argv[3];                           /* Arguments to the scheme getall function */
+       zval       *retval;                            /* Return value from the scheme getall function */
+       php_xslt   *handle = (php_xslt *) user_data;   /* A PHP-XSLT processor */
+
+       /* If the scheme handler get all function doesn't
+          exist, exit out */
+       if (!XSLT_SCHEME(handle).get_all) {
+               return 0;
+       }
+
+       /* Allocate and initialize */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+       MAKE_STD_ZVAL(argv[2]);
+
+       /* Argument 1: XSLT processor (resource)
+          Argument 2: Scheme         (string)
+          Argument 3: Rest           (string)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_STRING(argv[1], (char *) scheme, 1);
+       ZVAL_STRING(argv[2], (char *) rest, 1);
+
+       call_xslt_function("scheme get all", XSLT_SCHEME(handle).get_all, 
+                          3, argv, &retval);
+
+       /* Save the return value in the buffer (copying it) */
+       *buffer     = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval));
+       *byte_count = Z_STRLEN_P(retval);
+
+       /* Free return value */
+       zval_ptr_dtor(&retval);
+
+       return 0;
+}
+/* }}} */
+
+/* {{{ scheme_handler_is_registered()
+   Check to see if the scheme handler is registered with the user */
+static int scheme_handler_is_registered(php_xslt *handle)
+{
+       /* If one of the functions is exists, then scheme
+          handlers are registered */
+       if (XSLT_SCHEME(handle).get_all  ||
+           XSLT_SCHEME(handle).open     ||
+           XSLT_SCHEME(handle).get      ||
+           XSLT_SCHEME(handle).put      ||
+           XSLT_SCHEME(handle).close)
+               return 1;
+       /* otherwise, no cigar */
+       else
+               return 0;
+}
+/* }}} */
+
+/* {{{ scheme_freememory()
+   Called when sablotron needs to free memory related to scheme handling */
+static int scheme_freememory(void *user_data, SablotHandle proc, char *buffer)
+{
+       /* If we don't have any scheme handler's registered, then emalloc() wasn't
+          used, and if emalloc() wasn't then efree shouldn't be used */
+       if (!scheme_handler_is_registered((php_xslt *) user_data)) {
+               return 0;
+       }
+
+       /* Free the memory using efree() and remove it from the register */
+       efree(buffer);
+       
+       return 0;
+}
+/* }}} */
+
+/* {{{ scheme_open()
+   Called when the URI needs to be opened */
+static int  scheme_open(void *user_data, SablotHandle proc, const char *scheme, const char *rest, int *fd)
+{
+       zval      *argv[3];                            /* Arguments to the scheme open function */
+       zval      *retval;                             /* The return value from the scheme open function */
+       php_xslt  *handle = (php_xslt *) user_data;    /* A PHP-XSLT processor */
+
+       /* If no open handler exists, let's exit */
+       if (!XSLT_SCHEME(handle).open) {
+               return 0;
+       }
+
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+       MAKE_STD_ZVAL(argv[2]);
+
+       /* Argument 1: XSLT Processor (resource)
+          Argument 2: Scheme         (string)
+          Argument 3: Rest           (string)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_STRING(argv[1], (char *) scheme, 1);
+       ZVAL_STRING(argv[2], (char *) rest, 1);
+       
+       /* Call the function */
+       call_xslt_function("scheme open", XSLT_SCHEME(handle).open,
+                          3, argv, &retval);
+
+       /* Return value is a resource pointer to an open file */
+       *fd = Z_LVAL_P(retval);
+
+       /* Free it all up */
+       zval_ptr_dtor(&retval);
+
+       /* return success */
+       return 0;
+}
+/* }}} */
+
+/* {{{ scheme_get()
+   Called when data needs to be fetched from the URI */
+static int  scheme_get(void *user_data, SablotHandle proc, int fd, char *buffer, int *byte_count)
+{
+       zval       *argv[3];                           /* Arguments to the scheme get function  */
+       zval       *retval;                            /* Return value from the scheme get function */
+       php_xslt   *handle = (php_xslt *) user_data;   /* A PHP-XSLT processor */
+
+       /* If no get handler exists, let's exit */
+       if (!XSLT_SCHEME(handle).get) {
+               return 0;
+       }
+
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+       MAKE_STD_ZVAL(argv[2]);
+
+       /* Argument 1: XSLT Processor (resource)
+          Argument 2: File Pointer   (resource)
+          Argument 3: Data           (string)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_RESOURCE(argv[1], fd);
+       zend_list_addref(fd);
+       ZVAL_STRINGL(argv[2], buffer, *byte_count, 0);
+       
+       /* Call the function */
+       call_xslt_function("scheme get", XSLT_SCHEME(handle).get,
+                          3, argv, &retval);
+       
+       /* Returns the number of bytes read */
+       *byte_count = Z_LVAL_P(retval);
+
+       /* Free things up */
+       zval_ptr_dtor(&retval);
+
+       /* return success */
+       return 0;
+}
+/* }}} */
+
+/* {{{ scheme_put()
+   Called when data needs to be written */
+static int  scheme_put(void *user_data, SablotHandle proc, int fd, const char *buffer, int *byte_count)
+{
+       zval       *argv[3];                            /* Arguments to the scheme put function */
+       zval       *retval;                             /* Return value from the scheme put function */
+       php_xslt   *handle = (php_xslt *) user_data;    /* A PHP-XSLT processor */
+
+       /* If no put handler exists, let's exit */
+       if (!XSLT_SCHEME(handle).put) {
+               return 0;
+       }
+       
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+       MAKE_STD_ZVAL(argv[2]);
+
+       /* Argument 1: XSLT processor (resource)
+          Argument 2: File pointer   (resource)
+          Argument 3: Data           (string)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_RESOURCE(argv[1], fd);
+       zend_list_addref(fd);
+       ZVAL_STRINGL(argv[2], (char *) buffer, *byte_count, 1);
+       
+       /* Call the scheme put function already */
+       call_xslt_function("scheme put", XSLT_SCHEME(handle).put,
+                          3, argv, &retval);
+
+       /* The return value is the number of bytes written */
+       *byte_count = Z_LVAL_P(retval);
+
+       /* Free everything up */
+       zval_ptr_dtor(&retval);
+
+       /* Return success */
+       return 0;
+}
+/* }}} */
+
+/* {{{ scheme_close()
+   Called when its time to close the fd */
+static int  scheme_close(void *user_data, SablotHandle proc, int fd)
+{
+       zval       *argv[2];                           /* Arguments to the scheme close function*/
+       zval       *retval;                            /* Return value from the scheme close function */
+       php_xslt   *handle = (php_xslt *) user_data;   /* A PHP-XSLT processor */
+
+       /* if no close handler exists, exit */
+       if (!XSLT_SCHEME(handle).close) {
+               return 0;
+       }
+
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+
+       /* Argument 1: XSLT processor (resource)
+          Argument 2: File pointer   (resource)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_RESOURCE(argv[1], fd);
+       zend_list_addref(fd);
+       
+       /* Call the scheme handler close function */
+       call_xslt_function("scheme close", XSLT_SCHEME(handle).close,
+                          2, argv, &retval);
+
+       /* Free everything up */
+       zval_ptr_dtor(&retval);
+
+       /* Return success */
+       return 0;
+}
+/* }}} */
+
+/* {{{ sax_startdoc()
+   Called when the document starts to be processed */
+static SAX_RETURN sax_startdoc(void *ctx)
+{
+       zval       *argv[1];                    /* Arguments to the sax start doc function */
+       zval       *retval;                     /* Return value from sax start doc function */
+       php_xslt   *handle = (php_xslt *) ctx;  /* A PHP-XSLT processor */
+
+       /* if no document start function exists, exit */
+       if (!XSLT_SAX(handle).doc_start) {
+               return;
+       }
+
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+
+       /* Argument 1:  XSLT processor (resource) */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       
+       /* Call the Sax start doc function */
+       call_xslt_function("sax start doc", XSLT_SAX(handle).doc_start,
+                          1, argv, &retval);
+
+       /* Cleanup */
+       zval_ptr_dtor(&retval);
+}
+/* }}} */
+
+/* {{{ sax_startelement()
+   Called when an element is begun to be processed */
+static SAX_RETURN sax_startelement(void *ctx, 
+                                   const char  *name, 
+                                   const char **attr)
+{
+       zval       *argv[3];                     /* Arguments to the sax start element function */
+       zval       *retval;                      /* Return value from the sax start element function */
+       php_xslt   *handle = (php_xslt *) ctx;   /* A PHP-XSLT processor */
+       char      **p;                           /* Pointer to attributes */
+
+       /* If no element start function is found, exit */
+       if (!XSLT_SAX(handle).element_start) {
+               return;
+       }
+
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+       MAKE_STD_ZVAL(argv[2]);
+       array_init(argv[2]);
+
+       /* Argument 1: XSLT processor (resource)
+          Argument 2: Element name   (string)
+          Argument 3: Element attributes (array)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_STRING(argv[1], (char *) name, 1);
+
+       /* loop through the attributes array, copying it onto our
+          php array */
+       p = (char **) attr;
+       while (p && *p) {
+               add_assoc_string(argv[2], *p, *(p + 1), 1);
+               p += 2;
+       }
+
+       /* Call the sax element start function */
+       call_xslt_function("sax start element", XSLT_SAX(handle).element_start, 
+                          3, argv, &retval);
+       
+       /* Cleanup */
+       zval_ptr_dtor(&retval);
+}
+/* }}} */
+
+/* {{{ xslt_sax_endelement()
+   Called when an ending XML element is encountered */
+static SAX_RETURN sax_endelement(void *ctx, const char *name)
+{
+       zval        *argv[2];                   /* Arguments to the sax end element function */
+       zval        *retval;                    /* Return value from the sax end element function */
+       php_xslt    *handle = (php_xslt *) ctx; /* A PHP-XSLT processor */
+
+       /* If no element end function exists, exit */
+       if (!XSLT_SAX(handle).element_end) {
+               return;
+       }
+       
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+
+       /* Argument 1: XSLT processor (resource)
+          Argument 2: Element name   (string)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_STRING(argv[1], (char *) name, 1);
+
+       /* Call the sax end element function */
+       call_xslt_function("sax end element", XSLT_SAX(handle).element_end,
+                          2, argv, &retval);
+       
+       /* Cleanup */
+       zval_ptr_dtor(&retval);
+}
+
+/* {{{ sax_startnamespace()
+   Called at the beginning of the parsing of a new namespace */
+static SAX_RETURN sax_startnamespace(void *ctx, 
+                                     const char *prefix, 
+                                     const char *uri)
+{
+       zval       *argv[3];                    /* Arguments to the sax start namespace function */
+       zval       *retval;                     /* Return value from the sax start namespace function */
+       php_xslt   *handle = (php_xslt *) ctx;  /* A PHP-XSLT processor */
+
+       /* if no namespace start function exists, exit */
+       if (!XSLT_SAX(handle).namespace_start) {
+               return;
+       }
+       
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+       MAKE_STD_ZVAL(argv[2]);
+
+       /* Argument 1: XSLT processor (resource)
+          Argument 2: Prefix         (string)
+          Argument 3: URI            (string)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_STRING(argv[1], (char *) prefix, 1);
+       ZVAL_STRING(argv[2], (char *) uri, 1);
+
+       /* Call the sax start namespace function */
+       call_xslt_function("sax start namespace", XSLT_SAX(handle).namespace_start,
+                          3, argv, &retval);
+
+       /* Cleanup */
+       zval_ptr_dtor(&retval);
+}
+/* }}} */
+
+/* {{{ sax_endnamespace()
+   Called when a new namespace is finished being parsed */
+static SAX_RETURN sax_endnamespace(void *ctx, const char *prefix)
+{
+       zval        *argv[2];                    /* Arguments to the sax end namespace function */
+       zval        *retval;                     /* Return value from the sax end namespace function */
+       php_xslt    *handle = (php_xslt *) ctx;  /* A PHP-XSLT processor */
+
+       /* If no namespace end function exists, exit */
+       if (!XSLT_SAX(handle).namespace_end) {
+               return;
+       }
+       
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+       
+       /* Argument 1: XSLT processor (resource)
+          Argument 2: Prefix         (string)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_STRING(argv[1], (char *) prefix, 1);
+       
+       /* Call the sax end namespace function */
+       call_xslt_function("sax end namespace", XSLT_SAX(handle).namespace_end,
+                          2, argv, &retval);
+       
+       /* Cleanup */
+       zval_ptr_dtor(&retval);
+}
+/* }}} */
+
+/* {{{ sax_comment()
+   Called when a comment is found */
+static SAX_RETURN sax_comment(void *ctx, const char *contents)
+{
+       zval        *argv[2];                    /* Arguments to the sax comment function */
+       zval        *retval;                     /* Return value from the sax comment function */
+       php_xslt    *handle = (php_xslt *) ctx;  /* A PHP-XSLT processor */
+
+       /* if no comment function exists, exit */
+       if (!XSLT_SAX(handle).comment) {
+               return;
+       }
+       
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+       
+       /* Argument 1: XSLT processor   (resource)
+          Argument 2: Comment contents (string)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_STRING(argv[1], (char *) contents, 1);
+       
+       /* Call the sax comment function */
+       call_xslt_function("sax comment", XSLT_SAX(handle).comment,
+                          2, argv, &retval);
+       
+       /* Cleanup */
+       zval_ptr_dtor(&retval);
+}
+/* }}} */
+
+/* {{{ sax_pi()
+   Called when processing instructions are found */
+static SAX_RETURN sax_pi(void *ctx, 
+                         const char *target, 
+                         const char *contents)
+{
+       zval        *argv[3];                    /* Arguments to the sax processing instruction function */
+       zval        *retval;                     /* Return value from the sax processing instruction function */
+       php_xslt    *handle = (php_xslt *) ctx;  /* A PHP-XSLT processor */
+
+       /* If no processing instructions function exists, exit */
+       if (!XSLT_SAX(handle).pi) {
+               return;
+       }
+
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+       MAKE_STD_ZVAL(argv[2]);
+       
+       /* Argument 1: XSLT processor     (resource)
+          Argument 2: Target of the pi   (string)
+          Argument 3: Contents of the pi (string)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_STRING(argv[1], (char *) target, 1);
+       ZVAL_STRING(argv[2], (char *) contents, 1);
+
+       /* Call processing instructions function */
+       call_xslt_function("sax processing instructions", XSLT_SAX(handle).pi,
+                          3, argv, &retval);
+
+       /* Cleanup */
+       zval_ptr_dtor(&retval);
+}
+/* }}} */
+
+/* {{{ sax_characters()
+   Called when characters are come upon */
+static SAX_RETURN sax_characters(void *ctx,
+                                 const char *contents, 
+                                 int length)
+{
+       zval         *argv[2];                    /* Arguments to the sax characters function */
+       zval         *retval;                     /* Return value to the sax characters function */
+       php_xslt     *handle = (php_xslt *) ctx;  /* A PHP-XSLT processor */
+
+       /* If no characters function exists, exit */
+       if (!XSLT_SAX(handle).characters) {
+               return;
+       }
+       
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+       MAKE_STD_ZVAL(argv[1]);
+
+       /* Argument 1: XSLT processor (resource)
+          Argument 2: Contents       (string)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       ZVAL_STRINGL(argv[1], (char *) contents, length, 1);
+
+       /* Call characters function */
+       call_xslt_function("sax characters", XSLT_SAX(handle).characters,
+                          2, argv, &retval);
+       
+       /* Cleanup */
+       zval_ptr_dtor(&retval);
+}
+/* }}} */
+
+/* {{{ sax_enddoc()
+   Called when the document is finished being parsed */
+static SAX_RETURN sax_enddoc(void *ctx)
+{
+       zval        *argv[1];                    /* Arguments to the end document function */
+       zval        *retval;                     /* Return value from the end document function */
+       php_xslt    *handle = (php_xslt *) ctx;  /* A PHP-XSLT processor */
+
+       /* If no end document function exists, exit */
+       if (!XSLT_SAX(handle).doc_end) {
+               return;
+       }
+       
+       /* Allocate and initialize arguments */
+       MAKE_STD_ZVAL(argv[0]);
+
+       /* Argument 1: XSLT Processor (resource)
+        */
+       ZVAL_RESOURCE(argv[0], handle->processor.idx);
+       zend_list_addref(handle->processor.idx);
+       
+       /* Call the function */
+       call_xslt_function("sax end doc", XSLT_SAX(handle).doc_end,
+                          1, argv, &retval);
+       
+       /* Cleanup */
+       zval_ptr_dtor(&retval);
+}
+/* }}} */
+
+/* {{{ error_makecode()
+   Make the error code */
+static MH_ERROR error_makecode(void *user_data, SablotHandle proc, int severity, unsigned short facility, unsigned short code)
+{
+       return(0);
+}
+/* }}} */
+
+/* {{{ error_log()
+   Called when its time to log data */
+static MH_ERROR error_log(void *user_data, SablotHandle proc, MH_ERROR code, MH_LEVEL level, char **fields)
+{
+       php_xslt *handle = (php_xslt *) user_data;                              /* A PHP-XSLT processor */
+       char     *errmsg  = NULL;                                               /* Error message*/
+       char     *errtype = NULL;                                               /* Error type */
+       char     *errline = NULL;                                               /* Error line */
+       char     *msgbuf  = NULL;                                               /* Message buffer */
+       char      msgformat[] = "Sablotron Message on line %s, level %s: %s\n"; /* Message format */
+       int       error = 0;                                                    /* Error container */
+
+       /* Parse the error array */
+       /* Loop through the error array */
+       if (fields) {
+               while (fields && *fields) {
+                       char *key;  /* Key to for the message */
+                       char *val;  /* The message itself */
+                       char *ptr;  /* Pointer to the location of the ':' (separator) */
+                       int   pos;  /* Position of the ':' (separator) */
+                       int   len;  /* Length of the string */
+
+                       len = strlen(*fields);
+
+                       /* Grab the separator's position */
+                       ptr = strchr(*fields, ':');
+                       if (!ptr) {
+                               continue;
+                       }
+                       pos = ptr - *fields;
+
+                       /* Allocate the key and value and copy the data onto them */
+                       key = emalloc(pos + 1);
+                       val = emalloc((len - pos) + 1);
+
+                       memcpy(key, *fields, pos);
+                       memcpy(val, *fields + pos + 1, len - pos - 1);
+
+                       key[pos] = '\0';
+                       val[len - pos - 1] = '\0';
+
+                       /* Check to see whether or not we want to save the data */
+                       if (!strcmp(key, "msg")) {
+                               errmsg = estrndup(val, len - pos -1);
+                       }
+                       else if (!strcmp(key, "type")) {
+                               errtype = estrndup(val, len - pos - 1);
+                       }
+                       else if (!strcmp(key, "line")) {
+                               errline = estrndup(val, len - pos - 1);
+                       }
+                       
+                       /* Cleanup */
+                       if (key) efree(key);
+                       if (val) efree(val);
+
+                       /* Next key:value pair please :) */
+                       fields++;
+               }
+       }
+
+       
+       /* If no error line is given, then place none in the 
+          file */
+       if (!errline) {
+               errline = estrndup("none", sizeof("none") - 1);
+       }
+       
+       /* Default type is a log handle */
+       if (!errtype) {
+               errtype = estrndup("log", sizeof("log") - 1);
+       }
+       
+       /* No error message, no cry */
+       if (!errmsg) {
+               errmsg = estrndup("unknown error", sizeof("unknown error") - 1);
+       }
+       
+       /* Allocate the message buf and copy the data into it */
+       msgbuf = emalloc((sizeof(msgformat) - 6) +
+                        strlen(errmsg) +
+                        strlen(errline) +
+                        strlen(errtype) + 1);
+       sprintf(msgbuf, msgformat, errline, errtype, errmsg);
+
+       /* If the error is serious enough, copy it to our error buffer 
+          which will show up when someone calls the xslt_error() function */
+       if (level == MH_LEVEL_WARN  ||
+           level == MH_LEVEL_ERROR ||
+           level == MH_LEVEL_CRITICAL) {
+               if (XSLT_ERRSTR(handle))
+                       efree(XSLT_ERRSTR(handle));
+               
+               XSLT_ERRSTR(handle) = estrdup(errmsg);
+       }
+
+       /* If we haven't allocated and opened the file yet */
+       if (!XSLT_LOG(handle).fd) {
+               /* Lets open up a file */
+               if (XSLT_LOG(handle).path && strcmp(XSLT_LOG(handle).path, "php://stderr")) {
+                       /* open for append */
+                       XSLT_LOG(handle).fd = open(XSLT_LOG(handle).path, 
+                                                  O_WRONLY|O_CREAT|O_APPEND,
+                                                  S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR);
+                       if (XSLT_LOG(handle).fd < 0) {
+                               php_error(E_WARNING, "Cannot open log file, %s [%d]: %s",
+                                         XSLT_LOG(handle).path, errno, strerror(errno));
+                               XSLT_LOG(handle).fd = 0;
+                       }
+               }
+               /* Default is stderr, or if the user provided "php://stderr" that's the
+                  stream */
+               else {
+                       XSLT_LOG(handle).fd = 2;
+               }
+       }
+       
+       /* Write the error to the file */
+       error = write(XSLT_LOG(handle).fd, msgbuf, strlen(msgbuf));
+       if (error < 1) {
+               php_error(E_WARNING, "Cannot write data to log file, %s, with fd, %d [%d]: %s",
+                         (XSLT_LOG(handle).path ? XSLT_LOG(handle).path : "stderr"),
+                         XSLT_LOG(handle).fd,
+                         error,
+                         strerror(error));
+               return 0;
+       }
+
+       /* Cleanup */
+       if (msgbuf)  efree(msgbuf);
+       if (errtype) efree(errtype);
+       if (errline) efree(errline);
+       if (errmsg)  efree(errmsg);
+       
+       return 0;
+}
+/* }}} */
+
+/* {{{ error_print()
+   Print out an error message or call the error handler */
+static MH_ERROR error_print(void *user_data, SablotHandle proc, MH_ERROR code, MH_LEVEL level, char **fields)
+{
+       php_xslt *handle = (php_xslt *) user_data;   /* A PHP-XSLT processor */
+       
+       if (XSLT_ERROR(handle)) {
+               zval   *argv[4];   /* Arguments to the error function */
+               zval   *retval;    /* Return value from the error function */
+
+               /* Allocate and initialize */
+               MAKE_STD_ZVAL(argv[0]);
+               MAKE_STD_ZVAL(argv[1]);
+               MAKE_STD_ZVAL(argv[2]);
+               MAKE_STD_ZVAL(argv[3]);
+               array_init(argv[3]);
+
+               /* Argument 1: XSLT Processor (resource)
+                  Argument 2: Error level    (long)
+                  Argument 3: Error code     (long)
+                  Argument 4: Error messages (array)
+                */
+               ZVAL_RESOURCE(argv[0], handle->processor.idx);
+               zend_list_addref(handle->processor.idx);
+               ZVAL_LONG(argv[1], level);
+               ZVAL_LONG(argv[2], code);
+
+               if (fields) {
+                       while (fields && *fields) {
+                               char *key;  /* Key to for the message */
+                               char *val;  /* The message itself */
+                               char *ptr;  /* Pointer to the location of the ':' (separator) */
+                               int   pos;  /* Position of the ':' (separator) */
+                               int   len;  /* Length of the string */
+                       
+                               len = strlen(*fields);
+                       
+                               /* Grab the separator's position */
+                               ptr = strchr(*fields, ':');
+                               if (!ptr) {
+                                       continue;
+                               }
+                               pos = ptr - *fields;
+
+                               /* Allocate the key and value and copy the data onto them */
+                               key = emalloc(pos + 1);
+                               val = emalloc((len - pos) + 1);
+
+                               memcpy(key, *fields, pos);
+                               memcpy(val, *fields + pos + 1, len - pos - 1);
+                               key[pos] = '\0';
+                               val[len - pos - 1] = '\0';
+
+                               /* Add it */                            
+                               add_assoc_stringl_ex(argv[3], key, pos, val, len - pos - 1, 1);
+
+                               /* Cleanup */
+                               efree(key);
+                               efree(val);
+
+                               /* Next field please */
+                               fields++;
+                       }
+               }
+
+               /* Call the function */
+               call_xslt_function("error handler", XSLT_ERROR(handle),
+                                  4, argv, &retval);
+
+               /* Free up */
+               zval_ptr_dtor(&retval);
+       }
+       else {
+               char *errmsg  = NULL;                                  /* Error message */
+               char *errline = NULL;                                  /* Error line */
+               char *msgbuf  = NULL;                                  /* Message buffer */
+               char  msgformat[] = "Sablotron error on line %s: %s";  /* Message format */
+
+               /* If the error is not serious, exit out */
+               if (code == MH_LEVEL_WARN  || 
+                   code == MH_LEVEL_ERROR || 
+                   code == MH_LEVEL_CRITICAL) {
+                       return 0;
+               }
+
+               /* Loop through and extract the error message and the 
+                  error line */
+               if (fields) {
+                       while (fields && *fields) {
+                               char *key;  /* Key to for the message */
+                               char *val;  /* The message itself */
+                               char *ptr;  /* Pointer to the location of the ':' (separator) */
+                               int   pos;  /* Position of the ':' (separator) */
+                               int   len;  /* Length of the string */
+                       
+                               len = strlen(*fields);
+                       
+                               /* Grab the separator's position */
+                               ptr = strchr(*fields, ':');
+                               if (!ptr) {
+                                       continue;
+                               }
+                               pos = ptr - *fields;
+                       
+                               /* Allocate the key and value and copy the data onto them */
+                               key = emalloc(pos + 1);
+                               val = emalloc((len - pos) + 1);
+                       
+                               memcpy(key, *fields, pos);
+                               memcpy(val, *fields + pos + 1, len - pos - 1);
+                       
+                               key[pos] = '\0';
+                               val[len - pos - 1] = '\0';
+                       
+                               /* Check to see whether or not we want to save the data */
+                               if (!strcmp(key, "msg")) {
+                                       errmsg = estrdup(val);
+                               }
+                               else if (!strcmp(key, "line")) {
+                                       errline = estrdup(val);
+                               }
+                       
+                               /* Cleanup */
+                               if (key) efree(key);
+                               if (val) efree(val);
+                       
+                               /* Next key:value pair please :) */
+                               fields++;
+                       }
+               }
+               
+               if (!errline) {
+                       errline = estrndup("none", sizeof("none") - 1);
+               }
+
+               /* Allocate the message buffer and copy the data onto it */
+               msgbuf = emalloc((sizeof(msgformat) - 4) + strlen(errmsg) + strlen(errline) + 1);
+               sprintf(msgbuf, msgformat, errline, errmsg);
+
+               /* Copy the error message onto the handle for use when 
+                  the xslt_error function is called */
+               XSLT_ERRSTR(handle) = estrdup(errmsg);
+
+               /* Output a warning */
+               php_error(E_WARNING, msgbuf);
+
+               /* Cleanup */
+               efree(msgbuf);
+               efree(errmsg);
+               efree(errline);
+       }
+
+       return(0);
+}
+/* }}} */
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/ext/xslt/tests/001.phpt b/ext/xslt/tests/001.phpt
new file mode 100644 (file)
index 0000000..3270c3f
--- /dev/null
@@ -0,0 +1,12 @@
+--TEST--
+Check for xslt presence
+--SKIPIF--
+<?php if (!extension_loaded("xslt")) print "skip"; ?>
+--POST--
+--GET--
+--FILE--
+<?php 
+echo "xslt extension is available";
+?>
+--EXPECT--
+xslt extension is available
\ No newline at end of file
diff --git a/ext/xslt/xslt.c b/ext/xslt/xslt.c
new file mode 100644 (file)
index 0000000..641556a
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP version 4.0                                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.02 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available at through the world-wide-web at                           |
+   | http://www.php.net/license/2_02.txt.                                 |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Sterling Hughes <sterling@php.net>                          |
+   +----------------------------------------------------------------------+
+ */
+
+#include "php.h"
+#include "php_xslt.h"
+
+#if HAVE_XSLT
+
+#include <string.h>
+
+static int debug = 0;
+
+/* {{{ xslt_debug() 
+   Output a debug message if debugging is enabled */
+extern void xslt_debug(char *function_name, char *format, ...)
+{
+       if (debug) {
+               va_list argv;
+               char    buffer[1024];
+
+               va_start(argv, format);
+               vsnprintf(buffer, sizeof(buffer) - 1, format, argv);
+               va_end(argv);
+
+               buffer[sizeof(buffer) - 1] = '\0';
+
+               php_printf("<b>XSLT Debug</b>: %s: %s<br>\n", 
+                          function_name, buffer);
+       }
+}
+/* }}} */
+
+/* {{{ call_xslt_function()
+   Call an XSLT handler */
+extern void call_xslt_function(char *name, 
+                               struct xslt_function *fptr, 
+                               int argc, 
+                               zval **argv, 
+                               zval **retval)
+{
+       int    error;  /* Error container */
+       int    idx;    /* Idx, when looping through and free'ing the arguments */
+       ELS_FETCH();   /* For TS mode, fetch the executor globals */
+
+       /* Allocate and initialize return value from the function */
+       MAKE_STD_ZVAL(*retval);
+
+       /* Call the function */
+       error = call_user_function(EG(function_table),
+                                  XSLT_OBJ(fptr),
+                                                          XSLT_FUNC(fptr),
+                                                          *retval, argc, argv);
+       if (error == FAILURE) {
+               php_error(E_WARNING, "Cannot call the %s handler: %s", 
+                         name, Z_STRVAL_P(XSLT_FUNC(fptr)));
+       }
+
+       /* Cleanup arguments */
+       for (idx = 0; idx < argc; idx++) {
+               /* Decrease refcount and free if refcount is <= 0 */
+               zval_ptr_dtor(&argv[idx]);
+       }
+}
+/* }}} */
+
+
+extern void free_xslt_handler(struct xslt_function *func)
+{
+       if (!func) {
+               return;
+       }
+
+       if (func->obj) {
+               efree(func->obj);
+       }
+
+       if (func->func) {
+               efree(func->func);
+       }
+
+       efree(func);
+}
+
+extern void assign_xslt_handler(struct xslt_function **func, zval **zfunc)
+{
+       char error[] = "Invalid function passed to %s";
+
+       *func = emalloc(sizeof(struct xslt_function));
+
+       if (Z_TYPE_PP(zfunc) == IS_STRING) {
+               (*func)->obj = NULL;
+               
+               zval_add_ref(zfunc);
+               (*func)->func = *zfunc;
+       }
+       else if (Z_TYPE_PP(zfunc) == IS_ARRAY) {
+               zval **obj;
+               zval **function;
+
+               if (zend_hash_index_find(Z_ARRVAL_PP(zfunc), 0, (void **) &obj) == FAILURE) {
+                       efree(*func);
+                       php_error(E_WARNING, error, get_active_function_name());
+                       return;
+               }
+
+               if (zend_hash_index_find(Z_ARRVAL_PP(zfunc), 1, (void **) &function) == FAILURE) {
+                       efree(*func);
+                       php_error(E_WARNING, error, get_active_function_name());
+                       return;
+               }
+
+               zval_add_ref(obj);
+               zval_add_ref(function);
+
+               (*func)->obj  = *obj;
+               (*func)->func = *function;
+       }
+       else {
+               efree(*func);
+               php_error(E_WARNING, error, get_active_function_name());
+       }
+}
+
+#endif