diff options
author | Kasimier T. Buchcik <kbuchcik@src.gnome.org> | 2006-07-14 16:18:32 +0000 |
---|---|---|
committer | Kasimier T. Buchcik <kbuchcik@src.gnome.org> | 2006-07-14 16:18:32 +0000 |
commit | 7662584ea19f746955775ad77f4fc959568495cb (patch) | |
tree | 8978a6c6e206b7e56dba85cc17296db0a2f3cb41 /libexslt/functions.c | |
parent | 90d2d1c28995e327dacccf820c5fb8ca90b6dc0b (diff) | |
download | libxslt-7662584ea19f746955775ad77f4fc959568495cb.tar.gz libxslt-7662584ea19f746955775ad77f4fc959568495cb.tar.bz2 libxslt-7662584ea19f746955775ad77f4fc959568495cb.zip |
Committing again, since I forgot to switch from win to linux linebreaks in
* libxslt/attributes.c libxslt/documents.c
libxslt/functions.c libxslt/keys.c libxslt/namespaces.c
libxslt/pattern.c libxslt/preproc.c libxslt/templates.c
libxslt/templates.h libxslt/transform.c
libxslt/variables.c libxslt/xslt.c
libxslt/xsltInternals.h libxslt/xsltutils.c
libxslt/xsltutils.h libexslt/common.c libexslt/dynamic.c
libexslt/functions.c libexslt/strings.c:
Committing again, since I forgot to switch from win to linux
linebreaks in the files.
Diffstat (limited to 'libexslt/functions.c')
-rw-r--r-- | libexslt/functions.c | 1458 |
1 files changed, 729 insertions, 729 deletions
diff --git a/libexslt/functions.c b/libexslt/functions.c index 4d904c9e..2cf7249d 100644 --- a/libexslt/functions.c +++ b/libexslt/functions.c @@ -1,729 +1,729 @@ -#define IN_LIBEXSLT
-#include "libexslt/libexslt.h"
-
-#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
-#include <win32config.h>
-#else
-#include "config.h"
-#endif
-
-#include <string.h>
-
-#include <libxml/tree.h>
-#include <libxml/xpath.h>
-#include <libxml/xpathInternals.h>
-#include <libxml/hash.h>
-#include <libxml/debugXML.h>
-
-#include <libxslt/xsltutils.h>
-#include <libxslt/variables.h>
-#include <libxslt/xsltInternals.h>
-#include <libxslt/extensions.h>
-#include <libxslt/transform.h>
-#include <libxslt/imports.h>
-
-#include "exslt.h"
-
-typedef struct _exsltFuncFunctionData exsltFuncFunctionData;
-struct _exsltFuncFunctionData {
- int nargs; /* number of arguments to the function */
- xmlNodePtr content; /* the func:fuction template content */
-};
-
-typedef struct _exsltFuncData exsltFuncData;
-struct _exsltFuncData {
- xmlHashTablePtr funcs; /* pointer to the stylesheet module data */
- xmlXPathObjectPtr result; /* returned by func:result */
- int error; /* did an error occur? */
- xmlDocPtr RVT; /* result tree fragment */
-};
-
-typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp;
-struct _exsltFuncResultPreComp {
- xsltElemPreComp comp;
- xmlXPathCompExprPtr select;
- xmlNsPtr *nsList;
- int nsNr;
-};
-
-/* Used for callback function in exsltInitFunc */
-typedef struct _exsltFuncImportRegData exsltFuncImportRegData;
-struct _exsltFuncImportRegData {
- xsltTransformContextPtr ctxt;
- xmlHashTablePtr hash;
-};
-
-static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,
- int nargs);
-static exsltFuncFunctionData *exsltFuncNewFunctionData(void);
-
-static const xmlChar *exsltResultDataID = (const xmlChar *) "EXSLT Result";
-
-/**
- * exsltFuncRegisterFunc:
- * @func: the #exsltFuncFunctionData for the function
- * @ctxt: an XSLT transformation context
- * @URI: the function namespace URI
- * @name: the function name
- *
- * Registers a function declared by a func:function element
- */
-static void
-exsltFuncRegisterFunc (exsltFuncFunctionData *data,
- xsltTransformContextPtr ctxt,
- const xmlChar *URI, const xmlChar *name,
- ATTRIBUTE_UNUSED const xmlChar *ignored) {
- if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL))
- return;
-
- xsltGenericDebug(xsltGenericDebugContext,
- "exsltFuncRegisterFunc: register {%s}%s\n",
- URI, name);
- xsltRegisterExtFunction(ctxt, name, URI,
- exsltFuncFunctionFunction);
-}
-
-/*
- * exsltFuncRegisterImportFunc
- * @data: the exsltFuncFunctionData for the function
- * @ch: structure containing context and hash table
- * @URI: the function namespace URI
- * @name: the function name
- *
- * Checks if imported function is already registered in top-level
- * stylesheet. If not, copies function data and registers function
- */
-static void
-exsltFuncRegisterImportFunc (exsltFuncFunctionData *data,
- exsltFuncImportRegData *ch,
- const xmlChar *URI, const xmlChar *name,
- ATTRIBUTE_UNUSED const xmlChar *ignored) {
- exsltFuncFunctionData *func=NULL;
-
- if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL))
- return;
-
- if (ch->ctxt == NULL || ch->hash == NULL)
- return;
-
- /* Check if already present */
- func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash, URI, name);
- if (func == NULL) { /* Not yet present - copy it in */
- func = exsltFuncNewFunctionData();
- memcpy(func, data, sizeof(exsltFuncFunctionData));
- if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) {
- xsltGenericError(xsltGenericErrorContext,
- "Failed to register function {%s}%s\n",
- URI, name);
- } else { /* Do the registration */
- xsltGenericDebug(xsltGenericDebugContext,
- "exsltFuncRegisterImportFunc: register {%s}%s\n",
- URI, name);
- xsltRegisterExtFunction(ch->ctxt, name, URI,
- exsltFuncFunctionFunction);
- }
- }
-}
-
-/**
- * exsltFuncInit:
- * @ctxt: an XSLT transformation context
- * @URI: the namespace URI for the extension
- *
- * Initializes the EXSLT - Functions module.
- * Called at transformation-time; merges all
- * functions declared in the import tree taking
- * import precedence into account, i.e. overriding
- * functions with lower import precedence.
- *
- * Returns the data for this transformation
- */
-static exsltFuncData *
-exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
- exsltFuncData *ret;
- xsltStylesheetPtr tmp;
- exsltFuncImportRegData ch;
- xmlHashTablePtr hash;
-
- ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData));
- if (ret == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncInit: not enough memory\n");
- return(NULL);
- }
- memset(ret, 0, sizeof(exsltFuncData));
-
- ret->result = NULL;
- ret->error = 0;
-
- ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI);
- ret->funcs = ch.hash;
- xmlHashScanFull(ch.hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt);
- tmp = ctxt->style;
- ch.ctxt = ctxt;
- while ((tmp=xsltNextImport(tmp))!=NULL) {
- hash = xsltGetExtInfo(tmp, URI);
- if (hash != NULL) {
- xmlHashScanFull(hash,
- (xmlHashScannerFull) exsltFuncRegisterImportFunc, &ch);
- }
- }
-
- return(ret);
-}
-
-/**
- * exsltFuncShutdown:
- * @ctxt: an XSLT transformation context
- * @URI: the namespace URI for the extension
- * @data: the module data to free up
- *
- * Shutdown the EXSLT - Functions module
- * Called at transformation-time.
- */
-static void
-exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
- const xmlChar *URI ATTRIBUTE_UNUSED,
- exsltFuncData *data) {
- if (data->result != NULL)
- xmlXPathFreeObject(data->result);
- xmlFree(data);
-}
-
-/**
- * exsltFuncStyleInit:
- * @style: an XSLT stylesheet
- * @URI: the namespace URI for the extension
- *
- * Allocates the stylesheet data for EXSLT - Function
- * Called at compile-time.
- *
- * Returns the allocated data
- */
-static xmlHashTablePtr
-exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
- const xmlChar *URI ATTRIBUTE_UNUSED) {
- return xmlHashCreate(1);
-}
-
-/**
- * exsltFuncStyleShutdown:
- * @style: an XSLT stylesheet
- * @URI: the namespace URI for the extension
- * @data: the stylesheet data to free up
- *
- * Shutdown the EXSLT - Function module
- * Called at compile-time.
- */
-static void
-exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
- const xmlChar *URI ATTRIBUTE_UNUSED,
- xmlHashTablePtr data) {
- xmlHashFree(data, (xmlHashDeallocator) xmlFree);
-}
-
-/**
- * exsltFuncNewFunctionData:
- *
- * Allocates an #exslFuncFunctionData object
- *
- * Returns the new structure
- */
-static exsltFuncFunctionData *
-exsltFuncNewFunctionData (void) {
- exsltFuncFunctionData *ret;
-
- ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData));
- if (ret == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncNewFunctionData: not enough memory\n");
- return (NULL);
- }
- memset(ret, 0, sizeof(exsltFuncFunctionData));
-
- ret->nargs = 0;
- ret->content = NULL;
-
- return(ret);
-}
-
-/**
- * exsltFreeFuncResultPreComp:
- * @comp: the #exsltFuncResultPreComp to free up
- *
- * Deallocates an #exsltFuncResultPreComp
- */
-static void
-exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) {
- if (comp == NULL)
- return;
-
- if (comp->select != NULL)
- xmlXPathFreeCompExpr (comp->select);
- if (comp->nsList != NULL)
- xmlFree(comp->nsList);
- xmlFree(comp);
-}
-
-/**
- * exsltFuncFunctionFunction:
- * @ctxt: an XPath parser context
- * @nargs: the number of arguments
- *
- * Evaluates the func:function element that defines the called function.
- */
-static void
-exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
- xmlXPathObjectPtr obj, oldResult, ret;
- exsltFuncData *data;
- exsltFuncFunctionData *func;
- xmlNodePtr paramNode, oldInsert, fake;
- int oldBase;
- xsltStackElemPtr params = NULL, param;
- xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
- int i;
-
- /*
- * retrieve func:function template
- */
- data = (exsltFuncData *) xsltGetExtData (tctxt,
- EXSLT_FUNCTIONS_NAMESPACE);
- oldResult = data->result;
- data->result = NULL;
-
- func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs,
- ctxt->context->functionURI,
- ctxt->context->function);
-
- /*
- * params handling
- */
- if (nargs > func->nargs) {
- xsltGenericError(xsltGenericErrorContext,
- "{%s}%s: called with too many arguments\n",
- ctxt->context->functionURI, ctxt->context->function);
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- if (func->content != NULL) {
- paramNode = func->content->prev;
- }
- else
- paramNode = NULL;
- if ((paramNode == NULL) && (func->nargs != 0)) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncFunctionFunction: nargs != 0 and "
- "param == NULL\n");
- return;
- }
- /*
- * Process xsl:param instructions which were not set by the
- * invoking function call.
- */
- for (i = func->nargs; (i > nargs) && (paramNode != NULL); i--) {
- /*
- * Those are the xsl:param instructions, which were not
- * set by the calling function.
- */
- param = xsltParseStylesheetCallerParam (tctxt, paramNode);
- param->next = params;
- params = param;
- paramNode = paramNode->prev;
- }
- /*
- * Process xsl:param instructions which are set by the
- * invoking function call.
- */
- while ((i-- > 0) && (paramNode != NULL)) {
- obj = valuePop(ctxt);
- /*
- * TODO: Using xsltParseStylesheetCallerParam() is actually
- * not correct, since we are processing an xsl:param; but
- * using xsltParseStylesheetParam() won't work, as it puts
- * the param on the varible stack and does not give access to
- * the created xsltStackElemPtr.
- * It's also not correct, as xsltParseStylesheetCallerParam()
- * will report error messages indicating an "xsl:with-param" and
- * not the actual "xsl:param".
- */
- param = xsltParseStylesheetCallerParam (tctxt, paramNode);
- param->computed = 1;
- if (param->value != NULL)
- xmlXPathFreeObject(param->value);
- param->value = obj;
- param->next = params;
- params = param;
- paramNode = paramNode->prev;
- }
-
- /*
- * actual processing
- */
- fake = xmlNewDocNode(tctxt->output, NULL,
- (const xmlChar *)"fake", NULL);
- oldInsert = tctxt->insert;
- tctxt->insert = fake;
- /*
- * In order to give the function variables a new 'scope' we
- * change varsBase in the context.
- */
- oldBase = tctxt->varsBase;
- tctxt->varsBase = tctxt->varsNr;
- xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
- func->content, NULL, params);
- tctxt->insert = oldInsert;
- tctxt->varsBase = oldBase; /* restore original scope */
- if (params != NULL)
- xsltFreeStackElemList(params);
-
- if (data->error != 0)
- goto error;
-
- if (data->result != NULL) {
- ret = data->result;
- } else
- ret = xmlXPathNewCString("");
-
- data->result = oldResult;
-
- /*
- * It is an error if the instantiation of the template results in
- * the generation of result nodes.
- */
- if (fake->children != NULL) {
-#ifdef LIBXML_DEBUG_ENABLED
- xmlDebugDumpNode (stderr, fake, 1);
-#endif
- xsltGenericError(xsltGenericErrorContext,
- "{%s}%s: cannot write to result tree while "
- "executing a function\n",
- ctxt->context->functionURI, ctxt->context->function);
- xmlFreeNode(fake);
- goto error;
- }
- xmlFreeNode(fake);
- valuePush(ctxt, ret);
-
-error:
- /*
- * IMPORTANT: This enables previously tree fragments marked as
- * being results of a function, to be garbage-collected after
- * the calling process exits.
- */
- xsltExtensionInstructionResultFinalize(tctxt);
-}
-
-
-static void
-exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) {
- xmlChar *name, *prefix;
- xmlNsPtr ns;
- xmlHashTablePtr data;
- exsltFuncFunctionData *func;
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-
- {
- xmlChar *qname;
-
- qname = xmlGetProp(inst, (const xmlChar *) "name");
- name = xmlSplitQName2 (qname, &prefix);
- xmlFree(qname);
- }
- if ((name == NULL) || (prefix == NULL)) {
- xsltGenericError(xsltGenericErrorContext,
- "func:function: not a QName\n");
- if (name != NULL)
- xmlFree(name);
- return;
- }
- /* namespace lookup */
- ns = xmlSearchNs (inst->doc, inst, prefix);
- if (ns == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "func:function: undeclared prefix %s\n",
- prefix);
- xmlFree(name);
- xmlFree(prefix);
- return;
- }
- xmlFree(prefix);
-
- /*
- * Create function data
- */
- func = exsltFuncNewFunctionData();
- func->content = inst->children;
- while (IS_XSLT_ELEM(func->content) &&
- IS_XSLT_NAME(func->content, "param")) {
- func->content = func->content->next;
- func->nargs++;
- }
-
- xsltParseTemplateContent(style, inst);
-
- /*
- * Register the function data such that it can be retrieved
- * by exslFuncFunctionFunction
- */
-#ifdef XSLT_REFACTORED
- /*
- * Ensure that the hash table will be stored in the *current*
- * stylesheet level in order to correctly evaluate the
- * import precedence.
- */
- data = (xmlHashTablePtr)
- xsltStyleStylesheetLevelGetExtData(style,
- EXSLT_FUNCTIONS_NAMESPACE);
-#else
- data = (xmlHashTablePtr)
- xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE);
-#endif
- if (data == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncFunctionComp: no stylesheet data\n");
- xmlFree(name);
- return;
- }
-
- if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) {
- xsltTransformError(NULL, style, inst,
- "Failed to register function {%s}%s\n",
- ns->href, name);
- style->errors++;
- } else {
- xsltGenericDebug(xsltGenericDebugContext,
- "exsltFuncFunctionComp: register {%s}%s\n",
- ns->href, name);
- }
- xmlFree(name);
-}
-
-static xsltElemPreCompPtr
-exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst,
- xsltTransformFunction function) {
- xmlNodePtr test;
- xmlChar *sel;
- exsltFuncResultPreComp *ret;
-
- /*
- * "Validity" checking
- */
- /* it is an error to have any following sibling elements aside
- * from the xsl:fallback element.
- */
- for (test = inst->next; test != NULL; test = test->next) {
- if (test->type != XML_ELEMENT_NODE)
- continue;
- if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback"))
- continue;
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncResultElem: only xsl:fallback is "
- "allowed to follow func:result\n");
- return (NULL);
- }
- /* it is an error for a func:result element to not be a descendant
- * of func:function.
- * it is an error if a func:result occurs within a func:result
- * element.
- * it is an error if instanciating the content of a variable
- * binding element (i.e. xsl:variable, xsl:param) results in the
- * instanciation of a func:result element.
- */
- for (test = inst->parent; test != NULL; test = test->parent) {
- if ((test->ns != NULL) &&
- (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) {
- if (xmlStrEqual(test->name, (const xmlChar *) "function")) {
- break;
- }
- if (xmlStrEqual(test->name, (const xmlChar *) "result")) {
- xsltGenericError(xsltGenericErrorContext,
- "func:result element not allowed within"
- " another func:result element\n");
- return (NULL);
- }
- }
- if (IS_XSLT_ELEM(test) &&
- (IS_XSLT_NAME(test, "variable") ||
- IS_XSLT_NAME(test, "param"))) {
- xsltGenericError(xsltGenericErrorContext,
- "func:result element not allowed within"
- " a variable binding element\n");
- return (NULL);
- }
- }
-
- /*
- * Precomputation
- */
- ret = (exsltFuncResultPreComp *)
- xmlMalloc (sizeof(exsltFuncResultPreComp));
- if (ret == NULL) {
- xsltPrintErrorContext(NULL, NULL, NULL);
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncResultComp : malloc failed\n");
- return (NULL);
- }
- memset(ret, 0, sizeof(exsltFuncResultPreComp));
-
- xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function,
- (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp);
- ret->select = NULL;
-
- /*
- * Precompute the select attribute
- */
- sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL);
- if (sel != NULL) {
- ret->select = xmlXPathCompile (sel);
- xmlFree(sel);
- }
- /*
- * Precompute the namespace list
- */
- ret->nsList = xmlGetNsList(inst->doc, inst);
- if (ret->nsList != NULL) {
- int i = 0;
- while (ret->nsList[i] != NULL)
- i++;
- ret->nsNr = i;
- }
- return ((xsltElemPreCompPtr) ret);
-}
-
-static void
-exsltFuncResultElem (xsltTransformContextPtr ctxt,
- xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
- exsltFuncResultPreComp *comp) {
- exsltFuncData *data;
- xmlXPathObjectPtr ret;
-
-
- /* It is an error if instantiating the content of the
- * func:function element results in the instantiation of more than
- * one func:result elements.
- */
- data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE);
- if (data == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncReturnElem: data == NULL\n");
- return;
- }
- if (data->result != NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "func:result already instanciated\n");
- data->error = 1;
- return;
- }
- /*
- * Processing
- */
- if (comp->select != NULL) {
- xmlNsPtr *oldXPNsList;
- int oldXPNsNr;
- xmlNodePtr oldXPContextNode;
- /* If the func:result element has a select attribute, then the
- * value of the attribute must be an expression and the
- * returned value is the object that results from evaluating
- * the expression. In this case, the content must be empty.
- */
- if (inst->children != NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "func:result content must be empty if it"
- " has a select attribute\n");
- data->error = 1;
- return;
- }
- oldXPNsList = ctxt->xpathCtxt->namespaces;
- oldXPNsNr = ctxt->xpathCtxt->nsNr;
- oldXPContextNode = ctxt->xpathCtxt->node;
-
- ctxt->xpathCtxt->namespaces = comp->nsList;
- ctxt->xpathCtxt->nsNr = comp->nsNr;
-
- ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt);
-
- ctxt->xpathCtxt->node = oldXPContextNode;
- ctxt->xpathCtxt->nsNr = oldXPNsNr;
- ctxt->xpathCtxt->namespaces = oldXPNsList;
-
- if (ret == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncResultElem: ret == NULL\n");
- return;
- }
- /*
- * Mark it as a function result in order to avoid garbage
- * collecting of tree fragments before the function exits.
- */
- xsltExtensionInstructionResultRegister(ctxt, ret);
- } else if (inst->children != NULL) {
- /* If the func:result element does not have a select attribute
- * and has non-empty content (i.e. the func:result element has
- * one or more child nodes), then the content of the
- * func:result element specifies the value.
- */
- xmlNodePtr oldInsert;
- xmlDocPtr container;
-
- container = xsltCreateRVT(ctxt);
- if (container == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncResultElem: out of memory\n");
- data->error = 1;
- return;
- }
- xsltRegisterLocalRVT(ctxt, container);
-
- oldInsert = ctxt->insert;
- ctxt->insert = (xmlNodePtr) container;
- xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
- inst->children, NULL, NULL);
- ctxt->insert = oldInsert;
-
- ret = xmlXPathNewValueTree((xmlNodePtr) container);
- if (ret == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncResultElem: ret == NULL\n");
- data->error = 1;
- } else {
- ret->boolval = 0; /* Freeing is not handled there anymore */
- /*
- * Mark it as a function result in order to avoid garbage
- * collecting of tree fragments before the function exits.
- */
- xsltExtensionInstructionResultRegister(ctxt, ret);
- }
- } else {
- /* If the func:result element has empty content and does not
- * have a select attribute, then the returned value is an
- * empty string.
- */
- ret = xmlXPathNewCString("");
- }
- data->result = ret;
-}
-
-/**
- * exsltFuncRegister:
- *
- * Registers the EXSLT - Functions module
- */
-void
-exsltFuncRegister (void) {
- xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,
- (xsltExtInitFunction) exsltFuncInit,
- (xsltExtShutdownFunction) exsltFuncShutdown,
- (xsltStyleExtInitFunction) exsltFuncStyleInit,
- (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown);
-
- xsltRegisterExtModuleTopLevel ((const xmlChar *) "function",
- EXSLT_FUNCTIONS_NAMESPACE,
- exsltFuncFunctionComp);
- xsltRegisterExtModuleElement ((const xmlChar *) "result",
- EXSLT_FUNCTIONS_NAMESPACE,
- (xsltPreComputeFunction)exsltFuncResultComp,
- (xsltTransformFunction) exsltFuncResultElem);
-}
+#define IN_LIBEXSLT +#include "libexslt/libexslt.h" + +#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) +#include <win32config.h> +#else +#include "config.h" +#endif + +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include <libxml/hash.h> +#include <libxml/debugXML.h> + +#include <libxslt/xsltutils.h> +#include <libxslt/variables.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/extensions.h> +#include <libxslt/transform.h> +#include <libxslt/imports.h> + +#include "exslt.h" + +typedef struct _exsltFuncFunctionData exsltFuncFunctionData; +struct _exsltFuncFunctionData { + int nargs; /* number of arguments to the function */ + xmlNodePtr content; /* the func:fuction template content */ +}; + +typedef struct _exsltFuncData exsltFuncData; +struct _exsltFuncData { + xmlHashTablePtr funcs; /* pointer to the stylesheet module data */ + xmlXPathObjectPtr result; /* returned by func:result */ + int error; /* did an error occur? */ + xmlDocPtr RVT; /* result tree fragment */ +}; + +typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp; +struct _exsltFuncResultPreComp { + xsltElemPreComp comp; + xmlXPathCompExprPtr select; + xmlNsPtr *nsList; + int nsNr; +}; + +/* Used for callback function in exsltInitFunc */ +typedef struct _exsltFuncImportRegData exsltFuncImportRegData; +struct _exsltFuncImportRegData { + xsltTransformContextPtr ctxt; + xmlHashTablePtr hash; +}; + +static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, + int nargs); +static exsltFuncFunctionData *exsltFuncNewFunctionData(void); + +static const xmlChar *exsltResultDataID = (const xmlChar *) "EXSLT Result"; + +/** + * exsltFuncRegisterFunc: + * @func: the #exsltFuncFunctionData for the function + * @ctxt: an XSLT transformation context + * @URI: the function namespace URI + * @name: the function name + * + * Registers a function declared by a func:function element + */ +static void +exsltFuncRegisterFunc (exsltFuncFunctionData *data, + xsltTransformContextPtr ctxt, + const xmlChar *URI, const xmlChar *name, + ATTRIBUTE_UNUSED const xmlChar *ignored) { + if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL)) + return; + + xsltGenericDebug(xsltGenericDebugContext, + "exsltFuncRegisterFunc: register {%s}%s\n", + URI, name); + xsltRegisterExtFunction(ctxt, name, URI, + exsltFuncFunctionFunction); +} + +/* + * exsltFuncRegisterImportFunc + * @data: the exsltFuncFunctionData for the function + * @ch: structure containing context and hash table + * @URI: the function namespace URI + * @name: the function name + * + * Checks if imported function is already registered in top-level + * stylesheet. If not, copies function data and registers function + */ +static void +exsltFuncRegisterImportFunc (exsltFuncFunctionData *data, + exsltFuncImportRegData *ch, + const xmlChar *URI, const xmlChar *name, + ATTRIBUTE_UNUSED const xmlChar *ignored) { + exsltFuncFunctionData *func=NULL; + + if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL)) + return; + + if (ch->ctxt == NULL || ch->hash == NULL) + return; + + /* Check if already present */ + func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash, URI, name); + if (func == NULL) { /* Not yet present - copy it in */ + func = exsltFuncNewFunctionData(); + memcpy(func, data, sizeof(exsltFuncFunctionData)); + if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) { + xsltGenericError(xsltGenericErrorContext, + "Failed to register function {%s}%s\n", + URI, name); + } else { /* Do the registration */ + xsltGenericDebug(xsltGenericDebugContext, + "exsltFuncRegisterImportFunc: register {%s}%s\n", + URI, name); + xsltRegisterExtFunction(ch->ctxt, name, URI, + exsltFuncFunctionFunction); + } + } +} + +/** + * exsltFuncInit: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * + * Initializes the EXSLT - Functions module. + * Called at transformation-time; merges all + * functions declared in the import tree taking + * import precedence into account, i.e. overriding + * functions with lower import precedence. + * + * Returns the data for this transformation + */ +static exsltFuncData * +exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { + exsltFuncData *ret; + xsltStylesheetPtr tmp; + exsltFuncImportRegData ch; + xmlHashTablePtr hash; + + ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData)); + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncInit: not enough memory\n"); + return(NULL); + } + memset(ret, 0, sizeof(exsltFuncData)); + + ret->result = NULL; + ret->error = 0; + + ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI); + ret->funcs = ch.hash; + xmlHashScanFull(ch.hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt); + tmp = ctxt->style; + ch.ctxt = ctxt; + while ((tmp=xsltNextImport(tmp))!=NULL) { + hash = xsltGetExtInfo(tmp, URI); + if (hash != NULL) { + xmlHashScanFull(hash, + (xmlHashScannerFull) exsltFuncRegisterImportFunc, &ch); + } + } + + return(ret); +} + +/** + * exsltFuncShutdown: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * @data: the module data to free up + * + * Shutdown the EXSLT - Functions module + * Called at transformation-time. + */ +static void +exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, + const xmlChar *URI ATTRIBUTE_UNUSED, + exsltFuncData *data) { + if (data->result != NULL) + xmlXPathFreeObject(data->result); + xmlFree(data); +} + +/** + * exsltFuncStyleInit: + * @style: an XSLT stylesheet + * @URI: the namespace URI for the extension + * + * Allocates the stylesheet data for EXSLT - Function + * Called at compile-time. + * + * Returns the allocated data + */ +static xmlHashTablePtr +exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED, + const xmlChar *URI ATTRIBUTE_UNUSED) { + return xmlHashCreate(1); +} + +/** + * exsltFuncStyleShutdown: + * @style: an XSLT stylesheet + * @URI: the namespace URI for the extension + * @data: the stylesheet data to free up + * + * Shutdown the EXSLT - Function module + * Called at compile-time. + */ +static void +exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED, + const xmlChar *URI ATTRIBUTE_UNUSED, + xmlHashTablePtr data) { + xmlHashFree(data, (xmlHashDeallocator) xmlFree); +} + +/** + * exsltFuncNewFunctionData: + * + * Allocates an #exslFuncFunctionData object + * + * Returns the new structure + */ +static exsltFuncFunctionData * +exsltFuncNewFunctionData (void) { + exsltFuncFunctionData *ret; + + ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData)); + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncNewFunctionData: not enough memory\n"); + return (NULL); + } + memset(ret, 0, sizeof(exsltFuncFunctionData)); + + ret->nargs = 0; + ret->content = NULL; + + return(ret); +} + +/** + * exsltFreeFuncResultPreComp: + * @comp: the #exsltFuncResultPreComp to free up + * + * Deallocates an #exsltFuncResultPreComp + */ +static void +exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) { + if (comp == NULL) + return; + + if (comp->select != NULL) + xmlXPathFreeCompExpr (comp->select); + if (comp->nsList != NULL) + xmlFree(comp->nsList); + xmlFree(comp); +} + +/** + * exsltFuncFunctionFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Evaluates the func:function element that defines the called function. + */ +static void +exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr obj, oldResult, ret; + exsltFuncData *data; + exsltFuncFunctionData *func; + xmlNodePtr paramNode, oldInsert, fake; + int oldBase; + xsltStackElemPtr params = NULL, param; + xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); + int i; + + /* + * retrieve func:function template + */ + data = (exsltFuncData *) xsltGetExtData (tctxt, + EXSLT_FUNCTIONS_NAMESPACE); + oldResult = data->result; + data->result = NULL; + + func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs, + ctxt->context->functionURI, + ctxt->context->function); + + /* + * params handling + */ + if (nargs > func->nargs) { + xsltGenericError(xsltGenericErrorContext, + "{%s}%s: called with too many arguments\n", + ctxt->context->functionURI, ctxt->context->function); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if (func->content != NULL) { + paramNode = func->content->prev; + } + else + paramNode = NULL; + if ((paramNode == NULL) && (func->nargs != 0)) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncFunctionFunction: nargs != 0 and " + "param == NULL\n"); + return; + } + /* + * Process xsl:param instructions which were not set by the + * invoking function call. + */ + for (i = func->nargs; (i > nargs) && (paramNode != NULL); i--) { + /* + * Those are the xsl:param instructions, which were not + * set by the calling function. + */ + param = xsltParseStylesheetCallerParam (tctxt, paramNode); + param->next = params; + params = param; + paramNode = paramNode->prev; + } + /* + * Process xsl:param instructions which are set by the + * invoking function call. + */ + while ((i-- > 0) && (paramNode != NULL)) { + obj = valuePop(ctxt); + /* + * TODO: Using xsltParseStylesheetCallerParam() is actually + * not correct, since we are processing an xsl:param; but + * using xsltParseStylesheetParam() won't work, as it puts + * the param on the varible stack and does not give access to + * the created xsltStackElemPtr. + * It's also not correct, as xsltParseStylesheetCallerParam() + * will report error messages indicating an "xsl:with-param" and + * not the actual "xsl:param". + */ + param = xsltParseStylesheetCallerParam (tctxt, paramNode); + param->computed = 1; + if (param->value != NULL) + xmlXPathFreeObject(param->value); + param->value = obj; + param->next = params; + params = param; + paramNode = paramNode->prev; + } + + /* + * actual processing + */ + fake = xmlNewDocNode(tctxt->output, NULL, + (const xmlChar *)"fake", NULL); + oldInsert = tctxt->insert; + tctxt->insert = fake; + /* + * In order to give the function variables a new 'scope' we + * change varsBase in the context. + */ + oldBase = tctxt->varsBase; + tctxt->varsBase = tctxt->varsNr; + xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt), + func->content, NULL, params); + tctxt->insert = oldInsert; + tctxt->varsBase = oldBase; /* restore original scope */ + if (params != NULL) + xsltFreeStackElemList(params); + + if (data->error != 0) + goto error; + + if (data->result != NULL) { + ret = data->result; + } else + ret = xmlXPathNewCString(""); + + data->result = oldResult; + + /* + * It is an error if the instantiation of the template results in + * the generation of result nodes. + */ + if (fake->children != NULL) { +#ifdef LIBXML_DEBUG_ENABLED + xmlDebugDumpNode (stderr, fake, 1); +#endif + xsltGenericError(xsltGenericErrorContext, + "{%s}%s: cannot write to result tree while " + "executing a function\n", + ctxt->context->functionURI, ctxt->context->function); + xmlFreeNode(fake); + goto error; + } + xmlFreeNode(fake); + valuePush(ctxt, ret); + +error: + /* + * IMPORTANT: This enables previously tree fragments marked as + * being results of a function, to be garbage-collected after + * the calling process exits. + */ + xsltExtensionInstructionResultFinalize(tctxt); +} + + +static void +exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) { + xmlChar *name, *prefix; + xmlNsPtr ns; + xmlHashTablePtr data; + exsltFuncFunctionData *func; + + if ((style == NULL) || (inst == NULL)) + return; + + + { + xmlChar *qname; + + qname = xmlGetProp(inst, (const xmlChar *) "name"); + name = xmlSplitQName2 (qname, &prefix); + xmlFree(qname); + } + if ((name == NULL) || (prefix == NULL)) { + xsltGenericError(xsltGenericErrorContext, + "func:function: not a QName\n"); + if (name != NULL) + xmlFree(name); + return; + } + /* namespace lookup */ + ns = xmlSearchNs (inst->doc, inst, prefix); + if (ns == NULL) { + xsltGenericError(xsltGenericErrorContext, + "func:function: undeclared prefix %s\n", + prefix); + xmlFree(name); + xmlFree(prefix); + return; + } + xmlFree(prefix); + + /* + * Create function data + */ + func = exsltFuncNewFunctionData(); + func->content = inst->children; + while (IS_XSLT_ELEM(func->content) && + IS_XSLT_NAME(func->content, "param")) { + func->content = func->content->next; + func->nargs++; + } + + xsltParseTemplateContent(style, inst); + + /* + * Register the function data such that it can be retrieved + * by exslFuncFunctionFunction + */ +#ifdef XSLT_REFACTORED + /* + * Ensure that the hash table will be stored in the *current* + * stylesheet level in order to correctly evaluate the + * import precedence. + */ + data = (xmlHashTablePtr) + xsltStyleStylesheetLevelGetExtData(style, + EXSLT_FUNCTIONS_NAMESPACE); +#else + data = (xmlHashTablePtr) + xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE); +#endif + if (data == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncFunctionComp: no stylesheet data\n"); + xmlFree(name); + return; + } + + if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) { + xsltTransformError(NULL, style, inst, + "Failed to register function {%s}%s\n", + ns->href, name); + style->errors++; + } else { + xsltGenericDebug(xsltGenericDebugContext, + "exsltFuncFunctionComp: register {%s}%s\n", + ns->href, name); + } + xmlFree(name); +} + +static xsltElemPreCompPtr +exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst, + xsltTransformFunction function) { + xmlNodePtr test; + xmlChar *sel; + exsltFuncResultPreComp *ret; + + /* + * "Validity" checking + */ + /* it is an error to have any following sibling elements aside + * from the xsl:fallback element. + */ + for (test = inst->next; test != NULL; test = test->next) { + if (test->type != XML_ELEMENT_NODE) + continue; + if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback")) + continue; + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultElem: only xsl:fallback is " + "allowed to follow func:result\n"); + return (NULL); + } + /* it is an error for a func:result element to not be a descendant + * of func:function. + * it is an error if a func:result occurs within a func:result + * element. + * it is an error if instanciating the content of a variable + * binding element (i.e. xsl:variable, xsl:param) results in the + * instanciation of a func:result element. + */ + for (test = inst->parent; test != NULL; test = test->parent) { + if ((test->ns != NULL) && + (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) { + if (xmlStrEqual(test->name, (const xmlChar *) "function")) { + break; + } + if (xmlStrEqual(test->name, (const xmlChar *) "result")) { + xsltGenericError(xsltGenericErrorContext, + "func:result element not allowed within" + " another func:result element\n"); + return (NULL); + } + } + if (IS_XSLT_ELEM(test) && + (IS_XSLT_NAME(test, "variable") || + IS_XSLT_NAME(test, "param"))) { + xsltGenericError(xsltGenericErrorContext, + "func:result element not allowed within" + " a variable binding element\n"); + return (NULL); + } + } + + /* + * Precomputation + */ + ret = (exsltFuncResultPreComp *) + xmlMalloc (sizeof(exsltFuncResultPreComp)); + if (ret == NULL) { + xsltPrintErrorContext(NULL, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultComp : malloc failed\n"); + return (NULL); + } + memset(ret, 0, sizeof(exsltFuncResultPreComp)); + + xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function, + (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp); + ret->select = NULL; + + /* + * Precompute the select attribute + */ + sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL); + if (sel != NULL) { + ret->select = xmlXPathCompile (sel); + xmlFree(sel); + } + /* + * Precompute the namespace list + */ + ret->nsList = xmlGetNsList(inst->doc, inst); + if (ret->nsList != NULL) { + int i = 0; + while (ret->nsList[i] != NULL) + i++; + ret->nsNr = i; + } + return ((xsltElemPreCompPtr) ret); +} + +static void +exsltFuncResultElem (xsltTransformContextPtr ctxt, + xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, + exsltFuncResultPreComp *comp) { + exsltFuncData *data; + xmlXPathObjectPtr ret; + + + /* It is an error if instantiating the content of the + * func:function element results in the instantiation of more than + * one func:result elements. + */ + data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE); + if (data == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncReturnElem: data == NULL\n"); + return; + } + if (data->result != NULL) { + xsltGenericError(xsltGenericErrorContext, + "func:result already instanciated\n"); + data->error = 1; + return; + } + /* + * Processing + */ + if (comp->select != NULL) { + xmlNsPtr *oldXPNsList; + int oldXPNsNr; + xmlNodePtr oldXPContextNode; + /* If the func:result element has a select attribute, then the + * value of the attribute must be an expression and the + * returned value is the object that results from evaluating + * the expression. In this case, the content must be empty. + */ + if (inst->children != NULL) { + xsltGenericError(xsltGenericErrorContext, + "func:result content must be empty if it" + " has a select attribute\n"); + data->error = 1; + return; + } + oldXPNsList = ctxt->xpathCtxt->namespaces; + oldXPNsNr = ctxt->xpathCtxt->nsNr; + oldXPContextNode = ctxt->xpathCtxt->node; + + ctxt->xpathCtxt->namespaces = comp->nsList; + ctxt->xpathCtxt->nsNr = comp->nsNr; + + ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt); + + ctxt->xpathCtxt->node = oldXPContextNode; + ctxt->xpathCtxt->nsNr = oldXPNsNr; + ctxt->xpathCtxt->namespaces = oldXPNsList; + + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultElem: ret == NULL\n"); + return; + } + /* + * Mark it as a function result in order to avoid garbage + * collecting of tree fragments before the function exits. + */ + xsltExtensionInstructionResultRegister(ctxt, ret); + } else if (inst->children != NULL) { + /* If the func:result element does not have a select attribute + * and has non-empty content (i.e. the func:result element has + * one or more child nodes), then the content of the + * func:result element specifies the value. + */ + xmlNodePtr oldInsert; + xmlDocPtr container; + + container = xsltCreateRVT(ctxt); + if (container == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultElem: out of memory\n"); + data->error = 1; + return; + } + xsltRegisterLocalRVT(ctxt, container); + + oldInsert = ctxt->insert; + ctxt->insert = (xmlNodePtr) container; + xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node, + inst->children, NULL, NULL); + ctxt->insert = oldInsert; + + ret = xmlXPathNewValueTree((xmlNodePtr) container); + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultElem: ret == NULL\n"); + data->error = 1; + } else { + ret->boolval = 0; /* Freeing is not handled there anymore */ + /* + * Mark it as a function result in order to avoid garbage + * collecting of tree fragments before the function exits. + */ + xsltExtensionInstructionResultRegister(ctxt, ret); + } + } else { + /* If the func:result element has empty content and does not + * have a select attribute, then the returned value is an + * empty string. + */ + ret = xmlXPathNewCString(""); + } + data->result = ret; +} + +/** + * exsltFuncRegister: + * + * Registers the EXSLT - Functions module + */ +void +exsltFuncRegister (void) { + xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE, + (xsltExtInitFunction) exsltFuncInit, + (xsltExtShutdownFunction) exsltFuncShutdown, + (xsltStyleExtInitFunction) exsltFuncStyleInit, + (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown); + + xsltRegisterExtModuleTopLevel ((const xmlChar *) "function", + EXSLT_FUNCTIONS_NAMESPACE, + exsltFuncFunctionComp); + xsltRegisterExtModuleElement ((const xmlChar *) "result", + EXSLT_FUNCTIONS_NAMESPACE, + (xsltPreComputeFunction)exsltFuncResultComp, + (xsltTransformFunction) exsltFuncResultElem); +} |