]> granicus.if.org Git - php/commitdiff
@-Add the Sablotron extension for XSL parsing. (Sterling)
authorSterling Hughes <sterling@php.net>
Sun, 3 Sep 2000 13:00:08 +0000 (13:00 +0000)
committerSterling Hughes <sterling@php.net>
Sun, 3 Sep 2000 13:00:08 +0000 (13:00 +0000)
Folks, features include:

- Output Buffering Tie-ins
- Optional Descriptive error reporting (compile option)
- String Transformations
- File Transformations
- Logging
- SAX XML Processing support (slightly different from expat, even though
Sablotron uses expat to do the parsing.)

ext/sablot/Makefile.in [new file with mode: 0644]
ext/sablot/config.m4 [new file with mode: 0644]
ext/sablot/php_sablot.h [new file with mode: 0644]
ext/sablot/sablot.c [new file with mode: 0644]

diff --git a/ext/sablot/Makefile.in b/ext/sablot/Makefile.in
new file mode 100644 (file)
index 0000000..d6cc91e
--- /dev/null
@@ -0,0 +1,8 @@
+# $Id $
+
+LTLIBRARY_NAME        = libsablot.la
+LTLIBRARY_SOURCES     = sablot.c
+LTLIBRARY_SHARED_NAME = sablot.la
+LTLIBRARY_SHARED_LIBADD  = $(SABLOT_SHARED_LIBADD)
+
+include $(top_srcdir)/build/dynlib.mk
diff --git a/ext/sablot/config.m4 b/ext/sablot/config.m4
new file mode 100644 (file)
index 0000000..e093555
--- /dev/null
@@ -0,0 +1,47 @@
+dnl $Id$
+dnl config.m4 for extension Sablot
+
+PHP_ARG_WITH(sablot, for Sablotron XSL support,
+[  --with-sablot[=DIR]        Include Sablotron support])
+
+if test "$PHP_SABLOT" != "no"; then
+  if test -r $PHP_SABLOT/include/sablot.h; then
+    SABLOT_DIR=$PHP_SABLOT
+  else
+    AC_MSG_CHECKING(for Sablotron in default path)
+    for i in /usr/local /usr; do
+      if test -r $i/include/sablot.h; then
+        SABLOT_DIR=$i
+        AC_MSG_RESULT(found in $i)
+      fi
+    done
+  fi
+
+  if test -z "$SABLOT_DIR"; then
+    AC_MSG_RESULT(not found)
+    AC_MSG_ERROR(Please reinstall the Sablotron distribution)
+  fi
+
+  AC_ADD_INCLUDE($SABLOT_DIR/include)
+
+  PHP_SUBST(SABLOT_SHARED_LIBADD)
+  AC_ADD_LIBRARY_WITH_PATH(sablot, $SABLOT_DIR/lib, SABLOT_SHARED_LIBADD)
+
+  AC_DEFINE(HAVE_SABLOT,1,[ ])
+
+  PHP_EXTENSION(sablot, $ext_shared)
+fi
+
+AC_MSG_CHECKING(whether to enable UCD SNMP hack)
+AC_ARG_ENABLE(sablot-errors-descriptive,
+[  --enable-sablot-errors-descriptive  Enable Descriptive errors],[
+  if test "$enableval" = "yes" ; then
+    AC_DEFINE(SABLOT_ERRORS, 1, [ ])
+    AC_MSG_RESULT(yes)
+  else
+    AC_MSG_RESULT(no)
+  fi
+],[
+  AC_MSG_RESULT(no)
+])
+
diff --git a/ext/sablot/php_sablot.h b/ext/sablot/php_sablot.h
new file mode 100644 (file)
index 0000000..1baca7b
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP version 4.0                                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997, 1998, 1999, 2000 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_SABLOT_H
+#define PHP_SABLOT_H
+
+#if HAVE_SABLOT
+
+#include <sablot.h>
+
+extern zend_module_entry sablot_module_entry;
+#define phpext_sablot_ptr &sablot_module_entry
+
+#ifdef PHP_WIN32
+#define PHP_SABLOT_API __declspec(dllexport)
+#else
+#define PHP_SABLOT_API
+#endif
+
+PHP_MINIT_FUNCTION(sablot);
+PHP_MINFO_FUNCTION(sablot);
+PHP_FUNCTION(xslt_output_begintransform);
+PHP_FUNCTION(xslt_output_endtransform);
+PHP_FUNCTION(xslt_transform);
+PHP_FUNCTION(xslt_process);
+PHP_FUNCTION(xslt_create);
+PHP_FUNCTION(xslt_run);
+PHP_FUNCTION(xslt_fetch_result);
+PHP_FUNCTION(xslt_openlog);
+PHP_FUNCTION(xslt_closelog);
+PHP_FUNCTION(xslt_set_sax_handler);
+PHP_FUNCTION(xslt_free);
+PHP_FUNCTION(xslt_error);
+PHP_FUNCTION(xslt_errno);
+
+#ifdef SABLOT_ERRORS
+struct _php_sablot_error {
+       char *key;
+       char *value;
+       struct _php_sablot_error *next;
+};
+
+typedef struct _php_sablot_error php_sablot_error;
+#endif
+
+typedef struct {
+       long index;
+       int last_errno;
+#ifdef SABLOT_ERRORS
+       php_sablot_error *errors, errors_start;
+#endif
+       zval *startDocHandler;
+       zval *startElementHandler;
+       zval *endElementHandler;
+       zval *startNamespaceHandler;
+       zval *endNamespaceHandler;
+       zval *commentHandler;
+       zval *PIHandler;
+       zval *charactersHandler;
+       zval *endDocHandler;
+       SablotHandle p;
+} php_sablot;
+
+typedef struct {
+       char *output_transform_file;
+       int le_sablot;
+       int last_errno;
+} php_sablot_globals;
+
+
+#ifdef ZTS
+#define SABLOTG(v) (sablot_globals->v)
+#define SABLOTLS_FETCH() php_sablot_globals *sablot_globals = ts_resource(sablot_globals_id)
+#else
+#define SABLOTG(v) (sablot_globals.v)
+#define SABLOTLS_FETCH()
+#endif
+
+#else
+
+#define phpext_sablot_ptr NULL
+
+#endif
+
+#endif
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/ext/sablot/sablot.c b/ext/sablot/sablot.c
new file mode 100644 (file)
index 0000000..1499777
--- /dev/null
@@ -0,0 +1,1171 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP version 4.0                                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997, 1998, 1999, 2000 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"
+
+#if HAVE_SABLOT
+
+#include <sablot.h>
+#include <string.h>
+#include <stdarg.h>
+#include "ext/standard/php_output.h"
+#include "php_sablot.h"
+
+/* Functions related to PHP's list handling */
+static void _php_sablot_free_processor(php_sablot *handle);
+
+/* SAX Handlers */
+static void _php_sablot_handler_pair(php_sablot *handle, zval **first_func, zval **second_func, zval **indiv_handlers);
+static void _php_sablot_call_handler_function(zval *handlerName, int argc, zval **args, char *function_name);
+static SAX_RETURN _php_sablot_sax_startDoc(void *userData);
+static SAX_RETURN _php_sablot_sax_startElement(void *userData, const char *name, const char **attributes);
+static SAX_RETURN _php_sablot_sax_endElement(void *userData, const char *name);
+static SAX_RETURN _php_sablot_sax_startNamespace(void *userData, const char *prefix, const char *uri);
+static SAX_RETURN _php_sablot_sax_endNamespace(void *userData, const char *prefix);
+static SAX_RETURN _php_sablot_sax_comment(void *userData, const char *contents);
+static SAX_RETURN _php_sablot_sax_PI(void *userData, const char *target, const char *contents);
+static SAX_RETURN _php_sablot_sax_characters(void *userData, const char *contents, int length);
+static SAX_RETURN _php_sablot_sax_endDoc(void *userData);
+
+/* Error Handling Functions */
+#ifdef SABLOT_ERRORS
+static MH_ERROR _php_sablot_make_code(void *userData, SablotHandle p, int severity, unsigned short facility, unsigned short code);
+static MH_ERROR _php_sablot_error(void *userData, SablotHandle p, MH_ERROR code, MH_LEVEL level, char **fields);
+#endif
+
+/* PHP Utility Functions */
+static void m_convert_to_string_ex(int argc, ...);
+static zval *_php_xslt_string_zval(const char *str);
+static zval *_php_xslt_resource_zval(long value);
+
+/* Free macros */
+#define S_FREE(var) if (var) efree(var);
+#define FUNCH_FREE(var) if (var) zval_del_ref(&(var));
+
+
+static SAXHandler sax = {
+       _php_sablot_sax_startDoc,
+       _php_sablot_sax_startElement,
+       _php_sablot_sax_endElement,
+       _php_sablot_sax_startNamespace,
+       _php_sablot_sax_endNamespace,
+       _php_sablot_sax_comment,
+       _php_sablot_sax_PI,
+       _php_sablot_sax_characters,
+       _php_sablot_sax_endDoc
+};
+
+#ifdef SABLOT_ERRORS
+static MessageHandler mh = {
+       _php_sablot_make_code,
+       _php_sablot_error,
+       _php_sablot_error
+};
+#endif
+
+/* {{{ Begin PHP Extension code */
+
+#ifdef ZTS
+int sablot_globals_id;
+#else
+php_sablot_globals sablot_globals;
+#endif
+
+
+static unsigned char sixth_arg_force_ref[] = { 6, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
+static unsigned char third_arg_force_ref[] = { 4, BYREF_NONE, BYREF_NONE, BYREF_FORCE, BYREF_NONE };
+
+function_entry sablot_functions[] = {
+       PHP_FE(xslt_output_begintransform,    NULL)
+       PHP_FE(xslt_output_endtransform,      NULL)
+       PHP_FE(xslt_transform,                sixth_arg_force_ref)
+       PHP_FE(xslt_process,                  third_arg_force_ref)
+       PHP_FE(xslt_create,                   NULL)
+       PHP_FE(xslt_run,                      NULL)
+       PHP_FE(xslt_fetch_result,             NULL)
+       PHP_FE(xslt_openlog,                  NULL)
+       PHP_FE(xslt_closelog,                 NULL)
+       PHP_FE(xslt_set_sax_handler,          NULL)
+       PHP_FE(xslt_free,                     NULL)
+       PHP_FE(xslt_error,                    NULL)
+       PHP_FE(xslt_errno,                    NULL)
+       {NULL, NULL, NULL}
+};
+
+zend_module_entry sablot_module_entry = {
+       "sablot",
+       sablot_functions,
+       PHP_MINIT(sablot),
+       NULL,
+       NULL,
+       NULL,
+       PHP_MINFO(sablot),
+       STANDARD_MODULE_PROPERTIES
+};
+
+#ifdef COMPILE_DL_SABLOT
+ZEND_GET_MODULE(sablot)
+#endif
+
+/* }}} */
+
+
+/* {{{ MINIT and MINFO Functions */
+PHP_MINIT_FUNCTION(sablot)
+{
+       SABLOTLS_FETCH();
+       SABLOTG(le_sablot) = register_list_destructors(_php_sablot_free_processor, NULL);
+       return SUCCESS;
+}
+
+PHP_MINFO_FUNCTION(sablot)
+{
+       php_info_print_table_start();
+       php_info_print_table_header(2, "Sablotron support", "enabled");
+       php_info_print_table_end();
+
+}
+/* }}} */
+
+/* }}} */
+
+/* {{{ Begin Extension function */
+
+/* {{{ Begin Output Transformation functions */
+
+/* {{{ void xslt_output_begintransform(string file)
+   Begin filtering of all data that is being printed out through the XSL file given by the file parameter. */
+PHP_FUNCTION(xslt_output_begintransform)
+{
+       zval **file;
+       SABLOTLS_FETCH();
+       
+       if (ZEND_NUM_ARGS() != 1 ||
+           zend_get_parameters_ex(1, &file) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_string_ex(file);
+       
+       S_FREE(SABLOTG(output_transform_file));
+               
+       SABLOTG(output_transform_file) = estrndup(Z_STRVAL_PP(file), Z_STRLEN_PP(file));
+       php_start_ob_buffer();
+}
+/* }}} */
+
+/* {{{ void xslt_output_endtranform(void)
+   End filtering that data through the XSL file set by xslt_output_transform() and output the data */
+PHP_FUNCTION(xslt_output_endtransform)
+{
+       zval **buffer;
+       int ret = 0;
+       char *tRes = NULL;
+       OLS_FETCH();
+
+       if (OG(nesting_level) == 0) {
+               return;
+       }
+       ZVAL_STRINGL(*buffer, OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, 1);
+       
+       if (Z_STRVAL_PP(buffer)) {
+               char *args[] = {"/_xmlinput", Z_STRVAL_PP(buffer),
+                               "/_output",   NULL};
+               
+               ret = SablotProcess(SABLOTG(output_transform_file), "arg:/_xmlinput", "arg:/_output", NULL, args, &tRes);
+               
+               if (ret) {
+                       php_error(E_WARNING, "Error [%d]: %s", ret, SablotGetMsgText(ret));
+                       SABLOTG(last_errno) = ret;
+                       S_FREE(SABLOTG(output_transform_file));
+                       return;
+               }
+               
+               php_end_ob_buffer(0);
+               
+               PUTS(tRes);
+               S_FREE(SABLOTG(output_transform_file));
+               
+               if (tRes)
+                       SablotFree(tRes);
+       } else {
+               php_end_ob_buffer(0);
+       }
+}
+/* }}} */
+
+/* }}} */
+
+/* {{{ Begin Simple API */
+
+/* {{{ bool xslt_transform(string xslt_uri, string transform_uri, string result_uri[, array xslt_params[, array xslt_args[, string &result]]])
+   Transform an XML document, transform_uri, with an XSL stylesheet, xslt_uri with parameters, xslt_params, into the Result buffer, result_uri, xslt_args defines the variables in xslt_uri, transform_uri and result_uri. */
+PHP_FUNCTION(xslt_transform)
+{
+       zval **xslt_uri, **transform_uri, **result_uri,
+            **xslt_params, **xslt_args, **result, **value;
+       
+       char **args   = NULL,
+            **params = NULL,
+            *tResult = NULL,
+            *string_key;
+       
+       int argc = ZEND_NUM_ARGS(), ret = 0;
+       ulong num_key;
+       SABLOTLS_FETCH();
+       
+       if (argc < 3 || argc > 6 ||
+           zend_get_parameters_ex(argc, &xslt_uri, &transform_uri, &result_uri, &xslt_params, &xslt_args, &result) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       m_convert_to_string_ex(3, xslt_uri, transform_uri, result_uri);
+       
+       if (argc > 3) {
+               if (Z_TYPE_PP(xslt_params) != IS_LONG || Z_LVAL_PP(xslt_params) != 0) {
+                       int numelems, size, i=0;
+                       HashTable *ar = HASH_OF(*xslt_params);
+
+                       numelems = zend_hash_num_elements(ar);
+                       size = (numelems * 2 + 1) * sizeof(char *);
+                       
+                       params = (char **)emalloc(size+1);
+                       memset((char *)params, 0, size);
+                       
+                       for (zend_hash_internal_pointer_reset(ar);
+                            zend_hash_get_current_data(ar, (void **)&value) == SUCCESS;
+                            zend_hash_move_forward(ar)) {
+                               SEPARATE_ZVAL(value);
+                               convert_to_string_ex(value);
+                               
+                               if (zend_hash_get_current_key(ar, &string_key, &num_key) == HASH_KEY_IS_LONG) {
+                                       params[i++] = Z_STRVAL_PP(value);
+                                       continue;
+                               }
+                               
+                               params[i++] = string_key;
+                               params[i++] = Z_STRVAL_PP(value);
+                       }
+                       params[i] = NULL;
+               }
+       }
+       
+       if (argc > 4) {
+               if (Z_TYPE_PP(xslt_args) != IS_LONG || Z_LVAL_PP(xslt_args) != 0) {
+                       int numelems, size, i=0;
+                       HashTable *ar = HASH_OF(*xslt_args);
+
+                       numelems = zend_hash_num_elements(ar);
+                       size = (numelems * 2 + 1) * sizeof(char *);
+                       
+                       args = (char **)emalloc(size+1);
+                       memset((char *)args, 0, size);
+                       
+                       for (zend_hash_internal_pointer_reset(ar);
+                            zend_hash_get_current_data(ar, (void **)&value) == SUCCESS;
+                            zend_hash_move_forward(ar)) {
+                               SEPARATE_ZVAL(value);
+                               convert_to_string_ex(value);
+                               
+                               if (zend_hash_get_current_key(ar, &string_key, &num_key) == HASH_KEY_IS_LONG) {
+                                       args[i++] = Z_STRVAL_PP(value);
+                                       continue;
+                               }
+                               
+                               args[i++] = string_key;
+                               args[i++] = Z_STRVAL_PP(value);
+                       }
+                       args[i] = NULL;
+               }
+       }
+       
+       ret = SablotProcess(Z_STRVAL_PP(xslt_uri), Z_STRVAL_PP(transform_uri),
+                           Z_STRVAL_PP(result_uri), params, args, &tResult);
+       
+       if (ret) {
+               SABLOTG(last_errno) = ret;
+               
+               S_FREE(params);
+               S_FREE(args);
+               if (tResult)
+                       SablotFree(tResult);
+               
+               RETURN_FALSE;
+       } else { RETVAL_TRUE; }
+
+
+       if (tResult &&
+           argc == 6) {
+               ZVAL_STRING(*result, tResult, 1);
+       }
+       
+       S_FREE(params);
+       S_FREE(args);
+       
+       if (tResult)
+               SablotFree(tResult);
+}
+/* }}} */
+
+/* {{{ bool xslt_process(string xslt, string input_str, string &result[, string base])
+   Process data given by input_str through xslt and place the results in the string result.  If base is supplied, it will be used as the base URI. */
+PHP_FUNCTION(xslt_process)
+{
+       zval **xslt, **input, **result, **base;
+       char *tRes = NULL;
+       int ret = 0, argc = ZEND_NUM_ARGS();
+       SABLOTLS_FETCH();
+       
+       if (argc < 3 || argc > 4 ||
+           zend_get_parameters_ex(argc, &xslt, &input, &result, &base) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       m_convert_to_string_ex(2, xslt, input);
+       
+       if (argc > 3) {
+               convert_to_string_ex(base);
+               ret = SablotProcessStringsWithBase(Z_STRVAL_PP(xslt), Z_STRVAL_PP(input), &tRes, Z_STRVAL_PP(base));
+       } else {
+               ret = SablotProcessStrings(Z_STRVAL_PP(xslt), Z_STRVAL_PP(input), &tRes);
+       }
+       
+       if (ret) {
+               SABLOTG(last_errno) = ret;
+               if (tRes)
+                       SablotFree(tRes);
+               RETURN_FALSE;
+       }
+
+       if (tRes) {
+               ZVAL_STRING(*result, tRes, 1);
+               SablotFree(tRes);
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* }}} */
+
+/* {{{ Begin Advanced Resource API */
+
+/* {{{ proto resource xslt_create(void)
+   Create a new XSL processor and return a resource identifier. */
+PHP_FUNCTION(xslt_create)
+{
+       php_sablot *handle;
+       SablotHandle p;
+       int ret;
+       SABLOTLS_FETCH();
+
+       ret = SablotCreateProcessor(&p);
+       
+       if (ret) {
+               SABLOTG(last_errno) = ret;
+               RETURN_FALSE;
+       }
+       
+       handle = (php_sablot *)emalloc(sizeof(php_sablot));
+       if (!handle) {
+               php_error(E_WARNING, "Couldn't allocate PHP-Sablotron Handle");
+               RETURN_FALSE;
+       }
+       memset(handle, 0, sizeof(php_sablot));
+       
+       handle->p = p;
+       ret = SablotRegHandler(handle->p, HLR_SAX, (void *)&sax, (void *)handle);
+       
+       if (ret) {
+               SABLOTG(last_errno) = ret;
+               RETURN_FALSE;
+       }
+
+#ifdef SABLOT_ERRORS   
+       ret = SablotRegHandler(handle->p, HLR_MESSAGE, (void *)&mh, (void *)handle);
+       
+       if (ret) {
+               SABLOTG(last_errno) = ret;
+               RETURN_FALSE;
+       }
+#endif
+       
+       ZEND_REGISTER_RESOURCE(return_value, handle, SABLOTG(le_sablot));
+       handle->index = Z_LVAL_P(return_value);
+}
+/* }}} */
+
+/* {{{ proto bool xslt_run(resource xh, string xslt_file, string data_file[, string result[, array xslt_params[, array xslt_args]]])
+   Process the file data_file with the XSL stylesheet xslt_file and parameters xslt_parameters place the results in the buffer pointed to by the result parameter (defaults to "/_result"), args contains the values of the variables in the other parameters.  */
+PHP_FUNCTION(xslt_run)
+{
+       zval **xh, **xslt_file, **data_file, 
+            **xslt_result, **xslt_params, **xslt_args, **value;
+
+       php_sablot *handle;
+       char **args   = NULL,
+            **params = NULL,
+            *result  = NULL,
+            *string_key;
+       
+       int argc = ZEND_NUM_ARGS(),
+           ret  = 0;
+       ulong num_key;
+
+       SABLOTLS_FETCH();
+       
+       if (argc < 3 || argc > 6 ||
+           zend_get_parameters_ex(argc, &xh, &xslt_file, &data_file, &xslt_result, &xslt_params, &xslt_args) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron handle", SABLOTG(le_sablot));
+       m_convert_to_string_ex(2, xslt_file, data_file);
+       
+       if (argc == 3)
+               result = estrdup("arg:/_result");
+       
+       if (argc > 3) {
+               convert_to_string_ex(xslt_result);
+               result = estrndup(Z_STRVAL_PP(xslt_result), Z_STRLEN_PP(xslt_result));
+       }
+       
+       if (argc > 4) {
+               if (Z_TYPE_PP(xslt_params) != IS_LONG || Z_LVAL_PP(xslt_params) != 0) { 
+                       int numelems, size, i=0;
+                       HashTable *ar = HASH_OF(*xslt_params);
+
+                       numelems = zend_hash_num_elements(ar);
+                       size = (numelems * 2 + 1) * sizeof(char *);
+                       
+                       params = (char **)emalloc(size+1);
+                       memset((char *)params, 0, size);
+                       
+                       for (zend_hash_internal_pointer_reset(ar);
+                            zend_hash_get_current_data(ar, (void **)&value) == SUCCESS;
+                            zend_hash_move_forward(ar)) {
+                               SEPARATE_ZVAL(value);
+                               convert_to_string_ex(value);
+                               
+                               if (zend_hash_get_current_key(ar, &string_key, &num_key) == HASH_KEY_IS_LONG) {
+                                       params[i++] = Z_STRVAL_PP(value);
+                                       continue;
+                               }
+                               
+                               params[i++] = string_key;
+                               params[i++] = Z_STRVAL_PP(value);
+                       }
+                       params[i] = NULL;
+               }
+       }
+       
+       if (argc > 5) {
+               if (Z_TYPE_PP(xslt_args) != IS_LONG || Z_LVAL_PP(xslt_args) != 0) {
+                       int numelems, size, i=0;
+                       HashTable *ar = HASH_OF(*xslt_args);
+
+                       numelems = zend_hash_num_elements(ar);
+                       size = (numelems * 2 + 1) * sizeof(char *);
+                       
+                       args = (char **)emalloc(size+1);
+                       memset((char *)args, 0, size);
+                       
+                       for (zend_hash_internal_pointer_reset(ar);
+                            zend_hash_get_current_data(ar, (void **)&value) == SUCCESS;
+                            zend_hash_move_forward(ar)) {
+                               SEPARATE_ZVAL(value);
+                               convert_to_string_ex(value);
+                               
+                               if (zend_hash_get_current_key(ar, &string_key, &num_key) == HASH_KEY_IS_LONG) {
+                                       args[i++] = Z_STRVAL_PP(value);
+                                       continue;
+                               }
+                               
+                               args[i++] = string_key;
+                               args[i++] = Z_STRVAL_PP(value);
+                       }
+                       args[i] = NULL;
+               }
+       }
+       
+       ret = SablotRunProcessor(handle->p, Z_STRVAL_PP(xslt_file), Z_STRVAL_PP(data_file), result, params, args);
+       
+       if (ret) {
+               handle->last_errno = ret;
+               SABLOTG(last_errno) = ret;
+               S_FREE(params);
+               S_FREE(args);
+               S_FREE(result);
+               RETURN_FALSE;
+       }
+       
+       S_FREE(params);
+       S_FREE(args);
+       S_FREE(result);
+       
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool xslt_openlog(resource xh, string logfile[, int loglevel])
+   Sets a logfile for Sablotron to place all of its error messages */
+PHP_FUNCTION(xslt_openlog)
+{
+       zval **xh, **logfile, **opt_loglevel;
+       php_sablot *handle;
+       int ret = 0, loglevel = 0, argc = ZEND_NUM_ARGS();
+       
+       if (argc < 2 || argc > 3 ||
+           zend_get_parameters_ex(argc, &xh, &logfile, &opt_loglevel) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron", SABLOTG(le_sablot));
+       convert_to_string_ex(logfile);
+       
+       if (argc > 2) {
+               convert_to_long_ex(opt_loglevel);
+               loglevel = Z_LVAL_PP(opt_loglevel);
+       }
+       
+       ret = SablotSetLog(handle->p, (const char *)Z_STRVAL_PP(logfile), loglevel);
+       
+       if (ret) {
+               handle->last_errno  = ret;
+               SABLOTG(last_errno) = ret;
+               RETURN_FALSE;
+       } else {
+               RETURN_TRUE;
+       }
+}
+/* }}} */
+
+/* {{{ proto bool xslt_closelog(resource xh)
+   Clear the logfile for a given instance Sablotron */
+PHP_FUNCTION(xslt_closelog)
+{
+       zval **xh;
+       php_sablot *handle;
+       int ret;
+       SABLOTLS_FETCH();
+       
+       if (ZEND_NUM_ARGS() != 1 ||
+           zend_get_parameters_ex(1, &xh) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron", SABLOTG(le_sablot));
+       
+       ret = SablotSetLog(handle->p, (const char *)NULL, 1);
+       
+       if (ret) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE; 
+}
+/* }}} */
+
+/* {{{ proto string xslt_fetch_result(resource xh[, string result_name])
+   Fetch a result buffer on process handle, xh, with name, result_name, if name is not given than the "/_result" buffer is fetched. */
+PHP_FUNCTION(xslt_fetch_result)
+{
+       zval **xh, **result_name;
+       php_sablot *handle;
+       char *rname, *value=NULL;
+       int argc = ZEND_NUM_ARGS(), ret = 0;
+       SABLOTLS_FETCH();
+
+       if (argc < 1 || argc > 2 ||
+           zend_get_parameters_ex(argc, &xh, &result_name) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron Handle", SABLOTG(le_sablot));
+       
+       if (argc > 1) {
+               convert_to_string_ex(result_name);
+               rname = Z_STRVAL_PP(result_name);
+       } else {
+               rname = "/_result";
+       }
+       
+       ret = SablotGetResultArg(handle->p, rname, &value);
+       
+       if (ret) {
+               handle->last_errno  = ret;
+               SABLOTG(last_errno) = ret;
+               PUTS((char *)SablotGetMsgText(ret));
+               if (value)
+                       SablotFree(value);
+               RETURN_FALSE;
+       }
+       
+       if (value) {
+               RETVAL_STRING(value, 1);
+               SablotFree(value);
+       }
+}
+/* }}} */
+
+/* {{{ proto void xslt_free(resource xh)
+   Free resources associated with a xslt handle. */
+PHP_FUNCTION(xslt_free)
+{
+       zval **xh;
+       php_sablot *handle;
+       SABLOTLS_FETCH();
+       
+       if (ZEND_NUM_ARGS() != 1 ||
+           zend_get_parameters_ex(1, &xh) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       
+       ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron Handle", SABLOTG(le_sablot));
+       zend_list_delete(Z_LVAL_PP(xh));
+}
+/* }}} */
+
+/* {{{ proto void xslt_set_sax_handler(resource xh, array handlers)
+   Set SAX Handlers on the resource handle given by xh. */
+PHP_FUNCTION(xslt_set_sax_handler)
+{
+       zval **xh, **handlers, **indiv_handlers, **handler;
+       php_sablot *handle;
+       HashTable *handlers_list;
+       char *string_key = NULL;
+       ulong num_key;
+       SABLOTLS_FETCH();
+       
+       if (ZEND_NUM_ARGS() != 2 ||
+           zend_get_parameters_ex(2, &xh, &handlers) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron Handle", SABLOTG(le_sablot));
+       
+       handlers_list = HASH_OF(*handlers);
+       
+       for (zend_hash_internal_pointer_reset(handlers_list);
+            zend_hash_get_current_data(handlers_list, (void **)&indiv_handlers) == SUCCESS;
+            zend_hash_move_forward(handlers_list)) {
+               
+               SEPARATE_ZVAL(indiv_handlers);
+               
+               if (zend_hash_get_current_key(handlers_list, &string_key, &num_key) == HASH_KEY_IS_LONG) {
+                       php_error(E_WARNING, "The Keys of the first dimension of your array must be strings");
+                       RETURN_FALSE;
+               }
+               
+               
+               if (!strcasecmp("document", string_key)) {
+                       _php_sablot_handler_pair(handle, 
+                                                &handle->startDocHandler, &handle->endDocHandler,
+                                                indiv_handlers);
+               } else if (!strcasecmp("element", string_key)) {
+                       _php_sablot_handler_pair(handle, 
+                                                &handle->startElementHandler, &handle->endElementHandler, 
+                                                indiv_handlers);
+               } else if (!strcasecmp("namespace", string_key)) {
+                       _php_sablot_handler_pair(handle,
+                                                &handle->startNamespaceHandler, &handle->endNamespaceHandler, 
+                                                indiv_handlers);
+               } else if (!strcasecmp("comment", string_key)) {
+                       zval_add_ref(indiv_handlers);
+                       handle->commentHandler = *indiv_handlers;
+               } else if (!strcasecmp("pi", string_key)) {
+                       zval_add_ref(indiv_handlers);
+                       handle->PIHandler = *indiv_handlers;
+               } else if (!strcasecmp("characters", string_key)) {
+                       zval_add_ref(indiv_handlers);
+                       handle->charactersHandler = *indiv_handlers;
+               } else {                
+                       php_error(E_WARNING, "Invalid option: %s", string_key);
+               }
+               
+               S_FREE(string_key);
+       }
+}
+/* }}} */
+
+/* }}} */
+
+/* {{{ Begin Error Handling functions */
+
+/* {{{ proto mixed xslt_error([int xh])
+   Return the error string related to a given error handle.  If no handle is given the last error that occurred anywhere is returned. */
+PHP_FUNCTION(xslt_error)
+{
+       zval **xh;
+       int errno;
+       php_sablot *handle;
+       int argc = ZEND_NUM_ARGS();
+       
+       if (argc < 0 || argc > 1 ||
+           zend_get_parameters_ex(argc, &xh) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       
+       if (argc) {
+               ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron Handle", SABLOTG(le_sablot));
+
+#ifdef SABLOT_ERRORS           
+               if (handle->errors) {
+                       if (array_init(return_value) == FAILURE) {
+                               php_error(E_WARNING, "Cannot initialize return array from xslt_error");
+                               RETURN_FALSE;
+                       }
+               
+                       handle->errors = handle->errors_start.next;
+                       while (handle->errors) {
+                               add_assoc_string(return_value, handle->errors->key, handle->errors->value, 0);
+                               handle->errors = handle->errors->next;
+                       }
+                       add_assoc_string(return_value, "errstr", (char *)SablotGetMsgText(handle->last_errno), 1);
+                       add_assoc_long(return_value, "errno", handle->last_errno);
+                       return;
+               }
+#endif
+               
+               errno = handle->last_errno;
+       } else {
+               errno = SABLOTG(last_errno);
+       }
+
+       RETURN_STRING((char *)SablotGetMsgText(errno), 1);
+}
+/* }}} */
+
+/* {{{ proto int xslt_errno([int xh])
+   Return the error number related to a given error handle.  If no handle is given the last error number that occurred anywhere is returned. */
+PHP_FUNCTION(xslt_errno)
+{
+       zval **xh;
+       int errno;
+       php_sablot *handle;
+       int argc = ZEND_NUM_ARGS();
+       
+       if (argc < 0 || argc > 1 ||
+           zend_get_parameters_ex(argc, &xh) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       
+       if (argc) {
+               ZEND_FETCH_RESOURCE(handle, php_sablot *, xh, -1, "PHP-Sablotron Handle", SABLOTG(le_sablot));
+               RETURN_LONG(handle->last_errno);
+       } else {
+               RETURN_LONG(SABLOTG(last_errno));
+       }
+}
+/* }}} */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ BEGIN HANDLER FUNCTIONS */
+
+/* {{{ Begin SAX Handler functions */
+
+/* {{{ _php_sablot_handler_pair()
+   Set the handler functions from a two item array */
+static void _php_sablot_handler_pair(php_sablot *handle, zval **first_func, zval **second_func, zval **indiv_handlers)
+{
+       HashTable *second_level = HASH_OF(*indiv_handlers);
+       zval **handler;
+       int item = 0;
+               
+       for (zend_hash_internal_pointer_reset(second_level);
+            zend_hash_get_current_data(second_level, (void **)&handler) == SUCCESS;
+            zend_hash_move_forward(second_level)) {
+               
+               SEPARATE_ZVAL(handler);
+               zval_add_ref(handler);
+       
+               switch (item)
+               {
+                       case 0:
+                               *first_func  = *handler;
+                               break;
+                       case 1:
+                               *second_func = *handler;
+                               break;
+                       default:
+                               convert_to_string_ex(handler);
+                               php_error(E_WARNING, "Sorry, too many elements, %s discarded", Z_STRVAL_PP(handler));
+                               zval_del_ref(handler);
+                               break;
+               }
+               item++;
+       }
+}
+/* }}} */
+
+/* {{{ _php_sablot_call_handler_function()
+   Call a sablot call handler function, wrapper for call_user_function() */
+static void _php_sablot_call_handler_function(zval *handlerName, int argc, zval **args, char *function_name)
+{
+       zval *retval;
+       int result, i;
+       ELS_FETCH();
+       
+       MAKE_STD_ZVAL(retval);
+       
+       if (call_user_function(EG(function_table), NULL, handlerName, retval, argc, args) == FAILURE) {
+               php_error(E_WARNING, "Sorry, couldn't call %s handler", function_name);
+       }
+       
+       zval_dtor(retval);
+       efree(retval);
+       
+       for (i=0; i<argc; i++) {
+               zval_del_ref(&(args[i]));
+       }
+}
+/* }}} */
+
+/* {{{ _php_sablot_startDoc() */
+static SAX_RETURN _php_sablot_sax_startDoc(void *userData)
+{
+       php_sablot *handle = (php_sablot *)userData;
+
+       if (handle->startDocHandler) {
+               zval *args[1];
+               args[0] = _php_xslt_resource_zval(handle->index);
+
+               _php_sablot_call_handler_function(handle->startDocHandler, 1, args, "start document");
+       }
+}
+/* }}} */
+
+/* {{{ _php_sablot_sax_startElement() */
+static SAX_RETURN _php_sablot_sax_startElement(void *userData, const char *name, const char **attributes)
+{
+       php_sablot *handle = (php_sablot *)userData;
+       
+       if (handle->startElementHandler) {
+               zval *args[3];
+               
+               args[0] = _php_xslt_resource_zval(handle->index);
+               args[1] = _php_xslt_string_zval(name);
+
+               MAKE_STD_ZVAL(args[2]);
+               if (array_init(args[2]) == FAILURE) {
+                       php_error(E_WARNING, "Couldn't initialize array to be passed to start element handler");
+                       return;
+               }
+
+               while (attributes && *attributes) {
+                       char *key = (char *)attributes[0];
+                       zval *value = _php_xslt_string_zval(attributes[1]);
+                       
+                       add_assoc_string(args[2], key, Z_STRVAL_P(value), 0);
+                       attributes += 2;
+               }
+       
+               _php_sablot_call_handler_function(handle->startElementHandler, 3, args, "start element");
+       }
+}
+/* }}} */
+
+/* {{{ _php_sablot_sax_endElement() */
+static SAX_RETURN _php_sablot_sax_endElement(void *userData, const char *name)
+{
+       php_sablot *handle = (php_sablot *)userData;
+
+       if (handle->endElementHandler) {
+               zval *args[2];
+               
+               args[0] = _php_xslt_resource_zval(handle->index);
+               args[1] = _php_xslt_string_zval(name);
+               
+               _php_sablot_call_handler_function(handle->endElementHandler, 2, args, "end element");
+       }
+}
+/* }}} */
+
+/* {{{ _php_sablot_sax_startNamespace() */
+static SAX_RETURN _php_sablot_sax_startNamespace(void *userData, const char *prefix, const char *uri)
+{
+       php_sablot *handle = (php_sablot *)userData;
+       
+       if (handle->startNamespaceHandler) {
+               zval *args[3];
+               
+               args[0] = _php_xslt_resource_zval(handle->index);
+               args[1] = _php_xslt_string_zval(prefix);
+               args[2] = _php_xslt_string_zval(uri);
+               
+               _php_sablot_call_handler_function(handle->startNamespaceHandler, 3, args, "start namespace");
+       }
+}
+/* }}} */
+
+/* {{{ _php_sablot_sax_endNamespace() */
+static SAX_RETURN _php_sablot_sax_endNamespace(void *userData, const char *prefix)
+{
+       php_sablot *handle = (php_sablot *)userData;
+       
+       if (handle->endNamespaceHandler) {
+               zval *args[2];
+               
+               args[0] = _php_xslt_resource_zval(handle->index);
+               args[1] = _php_xslt_string_zval(prefix);
+               
+               _php_sablot_call_handler_function(handle->endNamespaceHandler, 2, args, "end namespace");
+       }
+}
+/* }}} */
+
+/* {{{ _php_sablot_sax_comment() */
+static SAX_RETURN _php_sablot_sax_comment(void *userData, const char *contents)
+{
+       php_sablot *handle = (php_sablot *)userData;
+       
+       if (handle->commentHandler) {
+               zval *args[2];
+               
+               args[0] = _php_xslt_resource_zval(handle->index);
+               args[1] = _php_xslt_string_zval(contents);
+               
+               _php_sablot_call_handler_function(handle->commentHandler, 2, args, "comment");
+       }
+}
+/* }}} */
+
+/* {{{ _php_sablot_sax_PI() */
+static SAX_RETURN _php_sablot_sax_PI(void *userData, const char *target, const char *contents)
+{
+       php_sablot *handle = (php_sablot *)userData;
+       
+       if (handle->PIHandler) {
+               zval *args[3];
+               
+               args[0] = _php_xslt_resource_zval(handle->index);
+               args[1] = _php_xslt_string_zval(target);
+               args[2] = _php_xslt_string_zval(contents);
+               
+               _php_sablot_call_handler_function(handle->PIHandler, 3, args, "PI Handler");
+       }
+}
+/* }}} */
+
+/* {{{ _php_sablot_sax_characters() */
+static SAX_RETURN _php_sablot_sax_characters(void *userData, const char *contents, int length)
+{
+       php_sablot *handle = (php_sablot *)userData;
+       
+       if (handle->charactersHandler) {
+               zval *args[2];
+               
+               args[0] = _php_xslt_resource_zval(handle->index);
+               args[1] = _php_xslt_string_zval(contents);
+               
+               _php_sablot_call_handler_function(handle->charactersHandler, 2, args, "characters");
+       }
+}
+/* }}} */
+
+/* {{{ _php_sablot_sax_endDoc() */
+static SAX_RETURN _php_sablot_sax_endDoc(void *userData)
+{
+       php_sablot *handle = (php_sablot *)userData;
+       
+       if (handle->endDocHandler) {
+               zval *args[1];
+               
+               args[0] = _php_xslt_resource_zval(handle->index);
+               
+               _php_sablot_call_handler_function(handle->endDocHandler, 1, args, "end document");
+       }
+}
+/* }}} */
+
+
+/* }}} */
+
+/* {{{ Sablotron Error Handling */
+
+#ifdef SABLOT_ERRORS
+/* {{{ _php_sablot_make_code() */
+static MH_ERROR _php_sablot_make_code(void *userData, SablotHandle p, int severity, unsigned short facility, unsigned short code)
+{
+       return(code);
+}
+/* }}} */
+
+/* {{{ _php_sablot_error()
+   Handle Sablotron errors */
+static MH_ERROR _php_sablot_error(void *userData, SablotHandle p, MH_ERROR code, MH_LEVEL level, char **fields)
+{
+       php_sablot *handle = (php_sablot *)userData;
+       int idx, len;
+       char *sep;
+
+       if (!fields) {
+               if (code) {
+                       handle->last_errno = (int)code;
+               }
+               return(0);
+       }
+       
+       switch (code)
+       {
+               case MH_LEVEL_CRITICAL:
+                       php_error(E_CORE, "Critical Error with Sablotron XSL Processor, must abort");
+                       return (0);
+               case MH_LEVEL_ERROR:
+                       php_error(E_ERROR, "Error with Sablotron XSL Processor, must abort");
+                       return (0);
+               case MH_LEVEL_WARN:
+                       php_error(E_WARNING, "Error occured with Sablotron XSL Processor");
+                       break;
+       }       
+       
+       if (handle->errors) {
+               handle->errors = handle->errors_start.next;
+               while (handle->errors) {
+                       S_FREE(handle->errors->key);
+                       S_FREE(handle->errors->value);
+                       handle->errors = handle->errors->next;
+               }
+               S_FREE(handle->errors);
+       }
+
+       handle->errors_start.next = NULL;
+       handle->errors = &(handle->errors_start);
+
+       while (fields && *fields) {
+               handle->errors->next = (php_sablot_error *)emalloc(sizeof(php_sablot_error));
+               handle->errors = handle->errors->next;
+       
+               sep = strchr(fields[0], ':');
+               
+               idx = sep - fields[0];
+               len = strlen(fields[0]);
+               
+               handle->errors->key   = emalloc(idx+1);
+               handle->errors->value = emalloc((len - idx) + 1);
+               memcpy(handle->errors->key, fields[0], idx);
+               memcpy(handle->errors->value, fields[0] + idx + 1, len - idx - 1);
+               
+               handle->errors->next = NULL;
+               fields++;
+       }
+       handle->last_errno = (int)code;
+
+       return(0);
+}
+/* }}} */
+#endif
+
+/* }}} */
+
+/* {{{ List Handling functions */
+
+/* {{{ _php_sablot_free_processor()
+   Free a Sablot handle */
+static void _php_sablot_free_processor(php_sablot *handle)
+{
+       if (handle->p) {
+#ifdef SABLOT_ERRORS
+               SablotUnregHandler(handle->p, HLR_MESSAGE, NULL, NULL);
+#endif
+               SablotUnregHandler(handle->p, HLR_SAX, NULL, NULL);
+               SablotDestroyProcessor(handle->p);
+       }
+       FUNCH_FREE(handle->startDocHandler);
+       FUNCH_FREE(handle->startElementHandler);
+       FUNCH_FREE(handle->endElementHandler);
+       FUNCH_FREE(handle->startNamespaceHandler);
+       FUNCH_FREE(handle->endNamespaceHandler);
+       FUNCH_FREE(handle->commentHandler);
+       FUNCH_FREE(handle->PIHandler);
+       FUNCH_FREE(handle->charactersHandler);
+       FUNCH_FREE(handle->endDocHandler);
+
+#ifdef SABLOT_ERRORS
+       if (handle->errors) {
+               handle->errors = handle->errors_start.next;
+               while (handle->errors) {
+                       S_FREE(handle->errors->key);
+                       S_FREE(handle->errors->value);
+                       handle->errors = handle->errors->next;
+               }
+               S_FREE(handle->errors);
+       }
+       S_FREE(handle);
+#endif
+}
+/* }}} */
+
+/* }}} */
+
+/* {{{ Conversion Helper functions */
+
+/* {{{ m_convert_to_string_ex()
+   A little wrapper function to convert a bunch o' function arguments to strings */
+static void m_convert_to_string_ex(int argc, ...)
+{
+       zval **arg;
+       va_list ap;
+       int i;
+       
+       va_start(ap, argc);
+       
+       for (i = 0; i < argc; i++) {
+               arg = va_arg(ap, zval **);
+               convert_to_string_ex(arg);
+       }
+       
+       va_end(ap);
+}
+/* }}} */
+
+/* {{{ _php_xslt_string_zval()
+   Converts a Sablotron string to a zval */
+static zval *_php_xslt_string_zval(const char *str)
+{
+       zval *ret;
+       int len = strlen(str);
+       MAKE_STD_ZVAL(ret);
+       
+       Z_TYPE_P(ret)   = IS_STRING;
+       Z_STRLEN_P(ret) = len;
+       Z_STRVAL_P(ret) = estrndup(str, len);
+       return(ret);
+}
+/* }}} */
+
+/* {{{ _php_xslt_resource_zval()
+   Converts a long identifier to a resource id */
+static zval *_php_xslt_resource_zval(long value)
+{
+       zval *ret;
+       MAKE_STD_ZVAL(ret);
+       
+       Z_TYPE_P(ret) = IS_RESOURCE;
+       Z_LVAL_P(ret) = value;
+       
+       zend_list_addref(value);
+       return(ret);
+}
+/* }}} */
+
+/* }}} */
+
+/* }}} */
+#endif
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */