From: Sterling Hughes Date: Sun, 3 Sep 2000 13:00:08 +0000 (+0000) Subject: @-Add the Sablotron extension for XSL parsing. (Sterling) X-Git-Tag: php-4.0.3RC1~348 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=89b77bfb4728bfd0298fe81e5751dad372336615;p=php @-Add the Sablotron extension for XSL parsing. (Sterling) 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.) --- diff --git a/ext/sablot/Makefile.in b/ext/sablot/Makefile.in new file mode 100644 index 0000000000..d6cc91eb60 --- /dev/null +++ b/ext/sablot/Makefile.in @@ -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 index 0000000000..e093555838 --- /dev/null +++ b/ext/sablot/config.m4 @@ -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 index 0000000000..1baca7bfa2 --- /dev/null +++ b/ext/sablot/php_sablot.h @@ -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 | + +----------------------------------------------------------------------+ + */ + +#ifndef PHP_SABLOT_H +#define PHP_SABLOT_H + +#if HAVE_SABLOT + +#include + +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 index 0000000000..1499777b2a --- /dev/null +++ b/ext/sablot/sablot.c @@ -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 | + +----------------------------------------------------------------------+ + */ + +#include "php.h" + +#if HAVE_SABLOT + +#include +#include +#include +#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; istartDocHandler) { + 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: + */