diff options
author | Kasimier T. Buchcik <kbuchcik@src.gnome.org> | 2006-07-14 16:10:25 +0000 |
---|---|---|
committer | Kasimier T. Buchcik <kbuchcik@src.gnome.org> | 2006-07-14 16:10:25 +0000 |
commit | 90d2d1c28995e327dacccf820c5fb8ca90b6dc0b (patch) | |
tree | 3e8e712f30d87621379e3152d9839772ae51abfd /libexslt | |
parent | 36615d1c6d582ef9bd2f2a451fae6c12b97d3ede (diff) | |
download | libxslt-90d2d1c28995e327dacccf820c5fb8ca90b6dc0b.tar.gz libxslt-90d2d1c28995e327dacccf820c5fb8ca90b6dc0b.tar.bz2 libxslt-90d2d1c28995e327dacccf820c5fb8ca90b6dc0b.zip |
Refactored xsltValueOf(). Changed to use xmlXPathCastToString() directly,
* 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:
Refactored xsltValueOf(). Changed to use xmlXPathCastToString()
directly, rather than creating an intermediate object with
xmlXPathConvertString(). This now does not add a text-node to
the result if the string is empty (this has impact on
serialization, since an empty text-node is serialized as
<foo></foo>, and now it will be serialized as <foo/>).
Refactored other functions in transform.c:
Mostly code cleanup/restructuring. Minimized number of
function variables for instruction which eat up function stack
memory when recursing templates (xsltIf(), xsltChoose(),
xsltApplyTemplates(), xsltCallTemplate()).
Changed XSLT tests to use xmlXPathCompiledEvalToBoolean().
Implemented redefinition checks at compilation-time and
eliminating them at transformation time in the refactored code
paths.
Introduced the field @currentTemplateRule on xsltTransformContext to
reflect the "Current Template Rule" as defined by the spec.
NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
same; the former is the "Current Template Rule" as defined by the
XSLT spec, the latter is simply the template struct being
currently processed by Libxslt.
Added XML_COMMENT_NODE and XML_CDATA_SECTION_NODE to the macro
IS_XSLT_REAL_NODE.
Misc code cleanup/restructuring and everything else I already forgot.
Refactored lifetime of temporary result tree fragments.
Substituted all calls to the now deprecated xsltRegisterTmpRVT()
for the new xsltRegisterLocalRVT().
Fragments of xsl:variable and xsl:param are freed when the
variable/pram is freed.
Fragments created when evaluating a "select" of xsl:varible and
xsl:param are also bound to the lifetime of the var/param.
EXSLT's func:function now uses the following functions to let take
care the transformation's garbage collector of returned tree
fragments:
xsltExtensionInstructionResultRegister(),
xsltExtensionInstructionResultFinalize()
Fixes:
#339222 - xsl:param at invalid position inside an xsl:template is
not catched
#346015 - Non-declared caller-parameters are accepted
#160400 - Compiles invalid XSLT; unbound variable accepted
#308441 - namespaced parameters become unregistered
#307103 - problem with proximity position in predicates of match
patterns
#328218 - problem with exsl:node-set() when converting strings
to node sets
#318088 - infinite recursion detection
#321505 - Multiple contiguous CDATA in output
#334493 - "--param" option does not have root context
#114377 - weird func:result/xsl:variable/exsl:node-set interaction
#150309 - Regression caused by fix for 142768
Diffstat (limited to 'libexslt')
-rw-r--r-- | libexslt/common.c | 247 | ||||
-rw-r--r-- | libexslt/dynamic.c | 548 | ||||
-rw-r--r-- | libexslt/functions.c | 1409 | ||||
-rw-r--r-- | libexslt/strings.c | 1051 |
4 files changed, 1660 insertions, 1595 deletions
diff --git a/libexslt/common.c b/libexslt/common.c index ffed71b6..7b07ea28 100644 --- a/libexslt/common.c +++ b/libexslt/common.c @@ -1,116 +1,131 @@ -#define IN_LIBEXSLT -#include "libexslt/libexslt.h" - -#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) -#include <win32config.h> -#else -#include "config.h" -#endif - -#include <libxml/tree.h> -#include <libxml/xpath.h> -#include <libxml/xpathInternals.h> - -#include <libxslt/xsltconfig.h> -#include <libxslt/xsltutils.h> -#include <libxslt/xsltInternals.h> -#include <libxslt/extensions.h> -#include <libxslt/transform.h> -#include <libxslt/extra.h> -#include <libxslt/preproc.h> - -#include "exslt.h" - -static void -exsltNodeSetFunction (xmlXPathParserContextPtr ctxt, int nargs) { - xmlChar *strval; - xmlNodePtr retNode; - xmlXPathObjectPtr ret; - - if (nargs != 1) { - xmlXPathSetArityError(ctxt); - return; - } - - if (xmlXPathStackIsNodeSet (ctxt)) { - xsltFunctionNodeSet (ctxt, nargs); - return; - } - - strval = xmlXPathPopString (ctxt); - retNode = xmlNewDocText (NULL, strval); - ret = xmlXPathNewValueTree (retNode); - if (ret == NULL) { - xsltGenericError(xsltGenericErrorContext, - "exsltNodeSetFunction: ret == NULL\n"); - } else { - ret->type = XPATH_NODESET; - } - - if (strval != NULL) - xmlFree (strval); - - valuePush (ctxt, ret); -} - -static void -exsltObjectTypeFunction (xmlXPathParserContextPtr ctxt, int nargs) { - xmlXPathObjectPtr obj, ret; - - if (nargs != 1) { - xmlXPathSetArityError(ctxt); - return; - } - - obj = valuePop(ctxt); - - switch (obj->type) { - case XPATH_STRING: - ret = xmlXPathNewCString("string"); - break; - case XPATH_NUMBER: - ret = xmlXPathNewCString("number"); - break; - case XPATH_BOOLEAN: - ret = xmlXPathNewCString("boolean"); - break; - case XPATH_NODESET: - ret = xmlXPathNewCString("node-set"); - break; - case XPATH_XSLT_TREE: - ret = xmlXPathNewCString("RTF"); - break; - case XPATH_USERS: - ret = xmlXPathNewCString("external"); - break; - default: - xsltGenericError(xsltGenericErrorContext, - "object-type() invalid arg\n"); - ctxt->error = XPATH_INVALID_TYPE; - xmlXPathFreeObject(obj); - return; - } - xmlXPathFreeObject(obj); - valuePush(ctxt, ret); -} - - -/** - * exsltCommonRegister: - * - * Registers the EXSLT - Common module - */ - -void -exsltCommonRegister (void) { - xsltRegisterExtModuleFunction((const xmlChar *) "node-set", - EXSLT_COMMON_NAMESPACE, - exsltNodeSetFunction); - xsltRegisterExtModuleFunction((const xmlChar *) "object-type", - EXSLT_COMMON_NAMESPACE, - exsltObjectTypeFunction); - xsltRegisterExtModuleElement((const xmlChar *) "document", - EXSLT_COMMON_NAMESPACE, - (xsltPreComputeFunction) xsltDocumentComp, - (xsltTransformFunction) xsltDocumentElem); -} +#define IN_LIBEXSLT
+#include "libexslt/libexslt.h"
+
+#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
+#include <win32config.h>
+#else
+#include "config.h"
+#endif
+
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xsltconfig.h>
+#include <libxslt/xsltutils.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/extensions.h>
+#include <libxslt/transform.h>
+#include <libxslt/extra.h>
+#include <libxslt/preproc.h>
+
+#include "exslt.h"
+
+static void
+exsltNodeSetFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+ if (nargs != 1) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+ if (xmlXPathStackIsNodeSet (ctxt)) {
+ xsltFunctionNodeSet (ctxt, nargs);
+ return;
+ } else {
+ xmlDocPtr fragment;
+ xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
+ xmlNodePtr txt;
+ xmlChar *strval;
+ xmlXPathObjectPtr obj;
+ /*
+ * SPEC EXSLT:
+ * "You can also use this function to turn a string into a text
+ * node, which is helpful if you want to pass a string to a
+ * function that only accepts a node-set."
+ */
+ fragment = xsltCreateRVT(tctxt);
+ if (fragment == NULL) {
+ xsltTransformError(tctxt, NULL, tctxt->inst,
+ "exsltNodeSetFunction: Failed to create a tree fragment.\n");
+ tctxt->state = XSLT_STATE_STOPPED;
+ return;
+ }
+ xsltRegisterLocalRVT(tctxt, fragment);
+
+ strval = xmlXPathPopString (ctxt);
+
+ txt = xmlNewDocText (fragment, strval);
+ xmlAddChild((xmlNodePtr) fragment, txt);
+ obj = xmlXPathNewNodeSet(txt);
+ if (obj == NULL) {
+ xsltTransformError(tctxt, NULL, tctxt->inst,
+ "exsltNodeSetFunction: Failed to create a node set object.\n");
+ tctxt->state = XSLT_STATE_STOPPED;
+ }
+ if (strval != NULL)
+ xmlFree (strval);
+
+ valuePush (ctxt, obj);
+ }
+}
+
+static void
+exsltObjectTypeFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+ xmlXPathObjectPtr obj, ret;
+
+ if (nargs != 1) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ obj = valuePop(ctxt);
+
+ switch (obj->type) {
+ case XPATH_STRING:
+ ret = xmlXPathNewCString("string");
+ break;
+ case XPATH_NUMBER:
+ ret = xmlXPathNewCString("number");
+ break;
+ case XPATH_BOOLEAN:
+ ret = xmlXPathNewCString("boolean");
+ break;
+ case XPATH_NODESET:
+ ret = xmlXPathNewCString("node-set");
+ break;
+ case XPATH_XSLT_TREE:
+ ret = xmlXPathNewCString("RTF");
+ break;
+ case XPATH_USERS:
+ ret = xmlXPathNewCString("external");
+ break;
+ default:
+ xsltGenericError(xsltGenericErrorContext,
+ "object-type() invalid arg\n");
+ ctxt->error = XPATH_INVALID_TYPE;
+ xmlXPathFreeObject(obj);
+ return;
+ }
+ xmlXPathFreeObject(obj);
+ valuePush(ctxt, ret);
+}
+
+
+/**
+ * exsltCommonRegister:
+ *
+ * Registers the EXSLT - Common module
+ */
+
+void
+exsltCommonRegister (void) {
+ xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
+ EXSLT_COMMON_NAMESPACE,
+ exsltNodeSetFunction);
+ xsltRegisterExtModuleFunction((const xmlChar *) "object-type",
+ EXSLT_COMMON_NAMESPACE,
+ exsltObjectTypeFunction);
+ xsltRegisterExtModuleElement((const xmlChar *) "document",
+ EXSLT_COMMON_NAMESPACE,
+ (xsltPreComputeFunction) xsltDocumentComp,
+ (xsltTransformFunction) xsltDocumentElem);
+}
diff --git a/libexslt/dynamic.c b/libexslt/dynamic.c index 86db6634..87ef8da3 100644 --- a/libexslt/dynamic.c +++ b/libexslt/dynamic.c @@ -1,274 +1,274 @@ -/* - * dynamic.c: Implementation of the EXSLT -- Dynamic module - * - * References: - * http://www.exslt.org/dyn/dyn.html - * - * See Copyright for the status of this software. - * - * Authors: - * Mark Vakoc <mark_vakoc@jdedwards.com> - * Thomas Broyer <tbroyer@ltgt.net> - * - * TODO: - * elements: - * functions: - * min - * max - * sum - * map - * closure - */ - -#define IN_LIBEXSLT -#include "libexslt/libexslt.h" - -#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) -#include <win32config.h> -#else -#include "config.h" -#endif - -#include <libxml/tree.h> -#include <libxml/xpath.h> -#include <libxml/xpathInternals.h> - -#include <libxslt/xsltconfig.h> -#include <libxslt/xsltutils.h> -#include <libxslt/xsltInternals.h> -#include <libxslt/extensions.h> - -#include "exslt.h" - -/** - * exsltDynEvaluateFunction: - * @ctxt: an XPath parser context - * @nargs: the number of arguments - * - * Evaluates the string as an XPath expression and returns the result - * value, which may be a boolean, number, string, node set, result tree - * fragment or external object. - */ - -static void -exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) { - xmlChar *str = NULL; - xmlXPathObjectPtr ret = NULL; - - if (ctxt == NULL) - return; - if (nargs != 1) { - xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); - xsltGenericError(xsltGenericErrorContext, - "dyn:evalute() : invalid number of args %d\n", nargs); - ctxt->error = XPATH_INVALID_ARITY; - return; - } - str = xmlXPathPopString(ctxt); - /* return an empty node-set if an empty string is passed in */ - if (!str||!xmlStrlen(str)) { - if (str) xmlFree(str); - valuePush(ctxt,xmlXPathNewNodeSet(NULL)); - return; - } - ret = xmlXPathEval(str,ctxt->context); - if (ret) - valuePush(ctxt,ret); - else { - xsltGenericError(xsltGenericErrorContext, - "dyn:evaluate() : unable to evaluate expression '%s'\n",str); - valuePush(ctxt,xmlXPathNewNodeSet(NULL)); - } - xmlFree(str); - return; -} - -/** - * exsltDynMapFunction: - * @ctxt: an XPath parser context - * @nargs: the number of arguments - * - * Evaluates the string as an XPath expression and returns the result - * value, which may be a boolean, number, string, node set, result tree - * fragment or external object. - */ - -static void -exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs) -{ - xmlChar *str = NULL; - xmlNodeSetPtr nodeset = NULL; - xmlXPathCompExprPtr comp = NULL; - xmlXPathObjectPtr ret = NULL; - xmlDocPtr oldDoc, container; - xmlNodePtr oldNode; - int oldContextSize; - int oldProximityPosition; - int i, j; - - - if (nargs != 2) { - xmlXPathSetArityError(ctxt); - return; - } - str = xmlXPathPopString(ctxt); - if (xmlXPathCheckError(ctxt)) { - xmlXPathSetTypeError(ctxt); - return; - } - - nodeset = xmlXPathPopNodeSet(ctxt); - if (xmlXPathCheckError(ctxt)) { - xmlXPathSetTypeError(ctxt); - return; - } - if (str == NULL || !xmlStrlen(str) || !(comp = xmlXPathCompile(str))) { - if (nodeset != NULL) - xmlXPathFreeNodeSet(nodeset); - if (str != NULL) - xmlFree(str); - valuePush(ctxt, xmlXPathNewNodeSet(NULL)); - return; - } - - ret = xmlXPathNewNodeSet(NULL); - if (ret == NULL) { - xsltGenericError(xsltGenericErrorContext, - "exsltDynMapFunctoin: ret == NULL\n"); - goto cleanup; - } - - oldDoc = ctxt->context->doc; - oldNode = ctxt->context->node; - oldContextSize = ctxt->context->contextSize; - oldProximityPosition = ctxt->context->proximityPosition; - - /** - * since we really don't know we're going to be adding node(s) - * down the road we create the RVT regardless - */ - container = xsltCreateRVT(xsltXPathGetTransformContext(ctxt)); - if (container != NULL) - xsltRegisterTmpRVT(xsltXPathGetTransformContext(ctxt), container); - - if (nodeset && nodeset->nodeNr > 0) { - xmlXPathNodeSetSort(nodeset); - ctxt->context->contextSize = nodeset->nodeNr; - ctxt->context->proximityPosition = 0; - for (i = 0; i < nodeset->nodeNr; i++) { - xmlXPathObjectPtr subResult = NULL; - - ctxt->context->proximityPosition++; - ctxt->context->node = nodeset->nodeTab[i]; - ctxt->context->doc = nodeset->nodeTab[i]->doc; - - subResult = xmlXPathCompiledEval(comp, ctxt->context); - if (subResult != NULL) { - switch (subResult->type) { - case XPATH_NODESET: - if (subResult->nodesetval != NULL) - for (j = 0; j < subResult->nodesetval->nodeNr; - j++) - xmlXPathNodeSetAdd(ret->nodesetval, - subResult->nodesetval-> - nodeTab[j]); - break; - case XPATH_BOOLEAN: - if (container != NULL) { - xmlNodePtr cur = - xmlNewChild((xmlNodePtr) container, NULL, - BAD_CAST "boolean", - BAD_CAST (subResult-> - boolval ? "true" : "")); - if (cur != NULL) { - cur->ns = - xmlNewNs(cur, - BAD_CAST - "http://exslt.org/common", - BAD_CAST "exsl"); - xmlXPathNodeSetAddUnique(ret->nodesetval, - cur); - } - } - break; - case XPATH_NUMBER: - if (container != NULL) { - xmlChar *val = - xmlXPathCastNumberToString(subResult-> - floatval); - xmlNodePtr cur = - xmlNewChild((xmlNodePtr) container, NULL, - BAD_CAST "number", val); - if (val != NULL) - xmlFree(val); - - if (cur != NULL) { - cur->ns = - xmlNewNs(cur, - BAD_CAST - "http://exslt.org/common", - BAD_CAST "exsl"); - xmlXPathNodeSetAddUnique(ret->nodesetval, - cur); - } - } - break; - case XPATH_STRING: - if (container != NULL) { - xmlNodePtr cur = - xmlNewChild((xmlNodePtr) container, NULL, - BAD_CAST "string", - subResult->stringval); - if (cur != NULL) { - cur->ns = - xmlNewNs(cur, - BAD_CAST - "http://exslt.org/common", - BAD_CAST "exsl"); - xmlXPathNodeSetAddUnique(ret->nodesetval, - cur); - } - } - break; - default: - break; - } - xmlXPathFreeObject(subResult); - } - } - } - ctxt->context->doc = oldDoc; - ctxt->context->node = oldNode; - ctxt->context->contextSize = oldContextSize; - ctxt->context->proximityPosition = oldProximityPosition; - - - cleanup: - /* restore the xpath context */ - if (comp != NULL) - xmlXPathFreeCompExpr(comp); - if (nodeset != NULL) - xmlXPathFreeNodeSet(nodeset); - if (str != NULL) - xmlFree(str); - valuePush(ctxt, ret); - return; -} - - -/** - * exsltDynRegister: - * - * Registers the EXSLT - Dynamic module - */ - -void -exsltDynRegister (void) { - xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate", - EXSLT_DYNAMIC_NAMESPACE, - exsltDynEvaluateFunction); - xsltRegisterExtModuleFunction ((const xmlChar *) "map", - EXSLT_DYNAMIC_NAMESPACE, - exsltDynMapFunction); - -} +/*
+ * dynamic.c: Implementation of the EXSLT -- Dynamic module
+ *
+ * References:
+ * http://www.exslt.org/dyn/dyn.html
+ *
+ * See Copyright for the status of this software.
+ *
+ * Authors:
+ * Mark Vakoc <mark_vakoc@jdedwards.com>
+ * Thomas Broyer <tbroyer@ltgt.net>
+ *
+ * TODO:
+ * elements:
+ * functions:
+ * min
+ * max
+ * sum
+ * map
+ * closure
+ */
+
+#define IN_LIBEXSLT
+#include "libexslt/libexslt.h"
+
+#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
+#include <win32config.h>
+#else
+#include "config.h"
+#endif
+
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libxslt/xsltconfig.h>
+#include <libxslt/xsltutils.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/extensions.h>
+
+#include "exslt.h"
+
+/**
+ * exsltDynEvaluateFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments
+ *
+ * Evaluates the string as an XPath expression and returns the result
+ * value, which may be a boolean, number, string, node set, result tree
+ * fragment or external object.
+ */
+
+static void
+exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+ xmlChar *str = NULL;
+ xmlXPathObjectPtr ret = NULL;
+
+ if (ctxt == NULL)
+ return;
+ if (nargs != 1) {
+ xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
+ xsltGenericError(xsltGenericErrorContext,
+ "dyn:evalute() : invalid number of args %d\n", nargs);
+ ctxt->error = XPATH_INVALID_ARITY;
+ return;
+ }
+ str = xmlXPathPopString(ctxt);
+ /* return an empty node-set if an empty string is passed in */
+ if (!str||!xmlStrlen(str)) {
+ if (str) xmlFree(str);
+ valuePush(ctxt,xmlXPathNewNodeSet(NULL));
+ return;
+ }
+ ret = xmlXPathEval(str,ctxt->context);
+ if (ret)
+ valuePush(ctxt,ret);
+ else {
+ xsltGenericError(xsltGenericErrorContext,
+ "dyn:evaluate() : unable to evaluate expression '%s'\n",str);
+ valuePush(ctxt,xmlXPathNewNodeSet(NULL));
+ }
+ xmlFree(str);
+ return;
+}
+
+/**
+ * exsltDynMapFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments
+ *
+ * Evaluates the string as an XPath expression and returns the result
+ * value, which may be a boolean, number, string, node set, result tree
+ * fragment or external object.
+ */
+
+static void
+exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs)
+{
+ xmlChar *str = NULL;
+ xmlNodeSetPtr nodeset = NULL;
+ xmlXPathCompExprPtr comp = NULL;
+ xmlXPathObjectPtr ret = NULL;
+ xmlDocPtr oldDoc, container;
+ xmlNodePtr oldNode;
+ int oldContextSize;
+ int oldProximityPosition;
+ int i, j;
+
+
+ if (nargs != 2) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+ str = xmlXPathPopString(ctxt);
+ if (xmlXPathCheckError(ctxt)) {
+ xmlXPathSetTypeError(ctxt);
+ return;
+ }
+
+ nodeset = xmlXPathPopNodeSet(ctxt);
+ if (xmlXPathCheckError(ctxt)) {
+ xmlXPathSetTypeError(ctxt);
+ return;
+ }
+ if (str == NULL || !xmlStrlen(str) || !(comp = xmlXPathCompile(str))) {
+ if (nodeset != NULL)
+ xmlXPathFreeNodeSet(nodeset);
+ if (str != NULL)
+ xmlFree(str);
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+ return;
+ }
+
+ ret = xmlXPathNewNodeSet(NULL);
+ if (ret == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "exsltDynMapFunctoin: ret == NULL\n");
+ goto cleanup;
+ }
+
+ oldDoc = ctxt->context->doc;
+ oldNode = ctxt->context->node;
+ oldContextSize = ctxt->context->contextSize;
+ oldProximityPosition = ctxt->context->proximityPosition;
+
+ /**
+ * since we really don't know we're going to be adding node(s)
+ * down the road we create the RVT regardless
+ */
+ container = xsltCreateRVT(xsltXPathGetTransformContext(ctxt));
+ if (container != NULL)
+ xsltRegisterLocalRVT(xsltXPathGetTransformContext(ctxt), container);
+
+ if (nodeset && nodeset->nodeNr > 0) {
+ xmlXPathNodeSetSort(nodeset);
+ ctxt->context->contextSize = nodeset->nodeNr;
+ ctxt->context->proximityPosition = 0;
+ for (i = 0; i < nodeset->nodeNr; i++) {
+ xmlXPathObjectPtr subResult = NULL;
+
+ ctxt->context->proximityPosition++;
+ ctxt->context->node = nodeset->nodeTab[i];
+ ctxt->context->doc = nodeset->nodeTab[i]->doc;
+
+ subResult = xmlXPathCompiledEval(comp, ctxt->context);
+ if (subResult != NULL) {
+ switch (subResult->type) {
+ case XPATH_NODESET:
+ if (subResult->nodesetval != NULL)
+ for (j = 0; j < subResult->nodesetval->nodeNr;
+ j++)
+ xmlXPathNodeSetAdd(ret->nodesetval,
+ subResult->nodesetval->
+ nodeTab[j]);
+ break;
+ case XPATH_BOOLEAN:
+ if (container != NULL) {
+ xmlNodePtr cur =
+ xmlNewChild((xmlNodePtr) container, NULL,
+ BAD_CAST "boolean",
+ BAD_CAST (subResult->
+ boolval ? "true" : ""));
+ if (cur != NULL) {
+ cur->ns =
+ xmlNewNs(cur,
+ BAD_CAST
+ "http://exslt.org/common",
+ BAD_CAST "exsl");
+ xmlXPathNodeSetAddUnique(ret->nodesetval,
+ cur);
+ }
+ }
+ break;
+ case XPATH_NUMBER:
+ if (container != NULL) {
+ xmlChar *val =
+ xmlXPathCastNumberToString(subResult->
+ floatval);
+ xmlNodePtr cur =
+ xmlNewChild((xmlNodePtr) container, NULL,
+ BAD_CAST "number", val);
+ if (val != NULL)
+ xmlFree(val);
+
+ if (cur != NULL) {
+ cur->ns =
+ xmlNewNs(cur,
+ BAD_CAST
+ "http://exslt.org/common",
+ BAD_CAST "exsl");
+ xmlXPathNodeSetAddUnique(ret->nodesetval,
+ cur);
+ }
+ }
+ break;
+ case XPATH_STRING:
+ if (container != NULL) {
+ xmlNodePtr cur =
+ xmlNewChild((xmlNodePtr) container, NULL,
+ BAD_CAST "string",
+ subResult->stringval);
+ if (cur != NULL) {
+ cur->ns =
+ xmlNewNs(cur,
+ BAD_CAST
+ "http://exslt.org/common",
+ BAD_CAST "exsl");
+ xmlXPathNodeSetAddUnique(ret->nodesetval,
+ cur);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ xmlXPathFreeObject(subResult);
+ }
+ }
+ }
+ ctxt->context->doc = oldDoc;
+ ctxt->context->node = oldNode;
+ ctxt->context->contextSize = oldContextSize;
+ ctxt->context->proximityPosition = oldProximityPosition;
+
+
+ cleanup:
+ /* restore the xpath context */
+ if (comp != NULL)
+ xmlXPathFreeCompExpr(comp);
+ if (nodeset != NULL)
+ xmlXPathFreeNodeSet(nodeset);
+ if (str != NULL)
+ xmlFree(str);
+ valuePush(ctxt, ret);
+ return;
+}
+
+
+/**
+ * exsltDynRegister:
+ *
+ * Registers the EXSLT - Dynamic module
+ */
+
+void
+exsltDynRegister (void) {
+ xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate",
+ EXSLT_DYNAMIC_NAMESPACE,
+ exsltDynEvaluateFunction);
+ xsltRegisterExtModuleFunction ((const xmlChar *) "map",
+ EXSLT_DYNAMIC_NAMESPACE,
+ exsltDynMapFunction);
+
+}
diff --git a/libexslt/functions.c b/libexslt/functions.c index 51f7d448..4d904c9e 100644 --- a/libexslt/functions.c +++ b/libexslt/functions.c @@ -1,680 +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? */ -}; - -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); - -/** - * 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, content = NULL; - 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; - content = func->content; - } - else - paramNode = NULL; - if ((paramNode == NULL) && (func->nargs != 0)) { - xsltGenericError(xsltGenericErrorContext, - "exsltFuncFunctionFunction: nargs != 0 and " - "param == NULL\n"); - return; - } - - /* set params */ - for (i = func->nargs; (i > nargs) && (paramNode != NULL); i--) { - paramNode = paramNode->prev; - if (content != NULL) - content = content->prev; - } - while ((i-- > 0) && (paramNode != NULL)) { - obj = valuePop(ctxt); - /* FIXME: this is a bit hackish */ - 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), - content, NULL, params); - tctxt->insert = oldInsert; - tctxt->varsBase = oldBase; /* restore original scope */ - if (params != NULL) - xsltFreeStackElemList(params); - - if (data->error != 0) - return; - - 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); - return; - } - xmlFreeNode(fake); - valuePush(ctxt, ret); -} - - -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; - xmlNsPtr *oldNsList; - int oldNsNr; - - /* 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) { - /* 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; - } - oldNsList = ctxt->xpathCtxt->namespaces; - oldNsNr = ctxt->xpathCtxt->nsNr; - ctxt->xpathCtxt->namespaces = comp->nsList; - ctxt->xpathCtxt->nsNr = comp->nsNr; - ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt); - ctxt->xpathCtxt->nsNr = oldNsNr; - ctxt->xpathCtxt->namespaces = oldNsList; - if (ret == NULL) { - xsltGenericError(xsltGenericErrorContext, - "exsltFuncResultElem: ret == NULL\n"); - return; - } - } 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; - } - xsltRegisterTmpRVT(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 */ - } - } 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);
+}
diff --git a/libexslt/strings.c b/libexslt/strings.c index 6ad6d6ce..484310a8 100644 --- a/libexslt/strings.c +++ b/libexslt/strings.c @@ -1,525 +1,526 @@ -#define IN_LIBEXSLT -#include "libexslt/libexslt.h" - -#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) -#include <win32config.h> -#else -#include "config.h" -#endif - -#include <libxml/tree.h> -#include <libxml/xpath.h> -#include <libxml/xpathInternals.h> -#include <libxml/parser.h> -#include <libxml/encoding.h> -#include <libxml/uri.h> - -#include <libxslt/xsltconfig.h> -#include <libxslt/xsltutils.h> -#include <libxslt/xsltInternals.h> -#include <libxslt/extensions.h> - -#include "exslt.h" - -/** - * exsltStrTokenizeFunction: - * @ctxt: an XPath parser context - * @nargs: the number of arguments - * - * Splits up a string on the characters of the delimiter string and returns a - * node set of token elements, each containing one token from the string. - */ -static void -exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) -{ - xsltTransformContextPtr tctxt; - xmlChar *str, *delimiters, *cur; - const xmlChar *token, *delimiter; - xmlNodePtr node; - xmlDocPtr container; - xmlXPathObjectPtr ret = NULL; - int clen; - - if ((nargs < 1) || (nargs > 2)) { - xmlXPathSetArityError(ctxt); - return; - } - - if (nargs == 2) { - delimiters = xmlXPathPopString(ctxt); - if (xmlXPathCheckError(ctxt)) - return; - } else { - delimiters = xmlStrdup((const xmlChar *) "\t\r\n "); - } - if (delimiters == NULL) - return; - - str = xmlXPathPopString(ctxt); - if (xmlXPathCheckError(ctxt) || (str == NULL)) { - xmlFree(delimiters); - return; - } - - /* Return a result tree fragment */ - tctxt = xsltXPathGetTransformContext(ctxt); - if (tctxt == NULL) { - xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, - "exslt:tokenize : internal error tctxt == NULL\n"); - goto fail; - } - - container = xsltCreateRVT(tctxt); - if (container != NULL) { - xsltRegisterTmpRVT(tctxt, container); - ret = xmlXPathNewNodeSet(NULL); - if (ret != NULL) { - ret->boolval = 0; /* Freeing is not handled there anymore */ - for (cur = str, token = str; *cur != 0; cur += clen) { - clen = xmlUTF8Size(cur); - if (*delimiters == 0) { /* empty string case */ - xmlChar ctmp; - ctmp = *(cur+clen); - *(cur+clen) = 0; - node = xmlNewDocRawNode(container, NULL, - (const xmlChar *) "token", cur); - xmlAddChild((xmlNodePtr) container, node); - xmlXPathNodeSetAddUnique(ret->nodesetval, node); - *(cur+clen) = ctmp; /* restore the changed byte */ - token = cur + clen; - } else for (delimiter = delimiters; *delimiter != 0; - delimiter += xmlUTF8Size(delimiter)) { - if (!xmlUTF8Charcmp(cur, delimiter)) { - if (cur == token) { - /* discard empty tokens */ - token = cur + clen; - break; - } - *cur = 0; /* terminate the token */ - node = xmlNewDocRawNode(container, NULL, - (const xmlChar *) "token", token); - xmlAddChild((xmlNodePtr) container, node); - xmlXPathNodeSetAddUnique(ret->nodesetval, node); - *cur = *delimiter; /* restore the changed byte */ - token = cur + clen; - break; - } - } - } - if (token != cur) { - node = xmlNewDocRawNode(container, NULL, - (const xmlChar *) "token", token); - xmlAddChild((xmlNodePtr) container, node); - xmlXPathNodeSetAddUnique(ret->nodesetval, node); - } - } - } - -fail: - if (str != NULL) - xmlFree(str); - if (delimiters != NULL) - xmlFree(delimiters); - if (ret != NULL) - valuePush(ctxt, ret); - else - valuePush(ctxt, xmlXPathNewNodeSet(NULL)); -} - -/** - * exsltStrSplitFunction: - * @ctxt: an XPath parser context - * @nargs: the number of arguments - * - * Splits up a string on a delimiting string and returns a node set of token - * elements, each containing one token from the string. - */ -static void -exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) { - xsltTransformContextPtr tctxt; - xmlChar *str, *delimiter, *cur; - const xmlChar *token; - xmlNodePtr node; - xmlDocPtr container; - xmlXPathObjectPtr ret = NULL; - int delimiterLength; - - if ((nargs < 1) || (nargs > 2)) { - xmlXPathSetArityError(ctxt); - return; - } - - if (nargs == 2) { - delimiter = xmlXPathPopString(ctxt); - if (xmlXPathCheckError(ctxt)) - return; - } else { - delimiter = xmlStrdup((const xmlChar *) " "); - } - if (delimiter == NULL) - return; - delimiterLength = xmlStrlen (delimiter); - - str = xmlXPathPopString(ctxt); - if (xmlXPathCheckError(ctxt) || (str == NULL)) { - xmlFree(delimiter); - return; - } - - /* Return a result tree fragment */ - tctxt = xsltXPathGetTransformContext(ctxt); - if (tctxt == NULL) { - xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, - "exslt:tokenize : internal error tctxt == NULL\n"); - goto fail; - } - - container = xsltCreateRVT(tctxt); - if (container != NULL) { - xsltRegisterTmpRVT(tctxt, container); - ret = xmlXPathNewNodeSet(NULL); - if (ret != NULL) { - ret->boolval = 0; /* Freeing is not handled there anymore */ - for (cur = str, token = str; *cur != 0; cur++) { - if (delimiterLength == 0) { - if (cur != token) { - xmlChar tmp = *cur; - *cur = 0; - node = xmlNewDocRawNode(container, NULL, - (const xmlChar *) "token", token); - xmlAddChild((xmlNodePtr) container, node); - xmlXPathNodeSetAddUnique(ret->nodesetval, node); - *cur = tmp; - token++; - } - } - else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) { - if (cur == token) { - /* discard empty tokens */ - cur = cur + delimiterLength - 1; - token = cur + 1; - continue; - } - *cur = 0; - node = xmlNewDocRawNode(container, NULL, - (const xmlChar *) "token", token); - xmlAddChild((xmlNodePtr) container, node); - xmlXPathNodeSetAddUnique(ret->nodesetval, node); - *cur = *delimiter; - cur = cur + delimiterLength - 1; - token = cur + 1; - } - } - if (token != cur) { - node = xmlNewDocRawNode(container, NULL, - (const xmlChar *) "token", token); - xmlAddChild((xmlNodePtr) container, node); - xmlXPathNodeSetAddUnique(ret->nodesetval, node); - } - } - } - -fail: - if (str != NULL) - xmlFree(str); - if (delimiter != NULL) - xmlFree(delimiter); - if (ret != NULL) - valuePush(ctxt, ret); - else - valuePush(ctxt, xmlXPathNewNodeSet(NULL)); -} - -/** - * exsltStrEncodeUriFunction: - * @ctxt: an XPath parser context - * @nargs: the number of arguments - * - * URI-Escapes a string - */ -static void -exsltStrEncodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) { - int escape_all = 1, str_len = 0; - xmlChar *str = NULL, *ret = NULL, *tmp; - - if ((nargs < 2) || (nargs > 3)) { - xmlXPathSetArityError(ctxt); - return; - } - - if (nargs >= 3) { - /* check for UTF-8 if encoding was explicitly given; - we don't support anything else yet */ - tmp = xmlXPathPopString(ctxt); - if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) { - xmlXPathReturnEmptyString(ctxt); - xmlFree(tmp); - return; - } - xmlFree(tmp); - } - - escape_all = xmlXPathPopBoolean(ctxt); - - str = xmlXPathPopString(ctxt); - str_len = xmlUTF8Strlen(str); - - if (str_len == 0) { - xmlXPathReturnEmptyString(ctxt); - xmlFree(str); - return; - } - - ret = xmlURIEscapeStr(str,(const xmlChar *)(escape_all?"-_.!~*'()":"-_.!~*'();/?:@&=+$,[]")); - xmlXPathReturnString(ctxt, ret); - - if (str != NULL) - xmlFree(str); -} - -/** - * exsltStrDecodeUriFunction: - * @ctxt: an XPath parser context - * @nargs: the number of arguments - * - * reverses URI-Escaping of a string - */ -static void -exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) { - int str_len = 0; - xmlChar *str = NULL, *ret = NULL, *tmp; - - if ((nargs < 1) || (nargs > 2)) { - xmlXPathSetArityError(ctxt); - return; - } - - if (nargs >= 2) { - /* check for UTF-8 if encoding was explicitly given; - we don't support anything else yet */ - tmp = xmlXPathPopString(ctxt); - if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) { - xmlXPathReturnEmptyString(ctxt); - xmlFree(tmp); - return; - } - xmlFree(tmp); - } - - str = xmlXPathPopString(ctxt); - str_len = xmlUTF8Strlen(str); - - if (str_len == 0) { - xmlXPathReturnEmptyString(ctxt); - xmlFree(str); - return; - } - - ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL); - if (!xmlCheckUTF8(ret)) { - /* FIXME: instead of throwing away the whole URI, we should - only discard the invalid sequence(s). How to do that? */ - xmlXPathReturnEmptyString(ctxt); - xmlFree(str); - xmlFree(ret); - return; - } - - xmlXPathReturnString(ctxt, ret); - - if (str != NULL) - xmlFree(str); -} - -/** - * exsltStrPaddingFunction: - * @ctxt: an XPath parser context - * @nargs: the number of arguments - * - * Creates a padding string of a certain length. - */ -static void -exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) { - int number, str_len = 0; - xmlChar *str = NULL, *ret = NULL, *tmp; - - if ((nargs < 1) || (nargs > 2)) { - xmlXPathSetArityError(ctxt); - return; - } - - if (nargs == 2) { - str = xmlXPathPopString(ctxt); - str_len = xmlUTF8Strlen(str); - } - if (str_len == 0) { - if (str != NULL) xmlFree(str); - str = xmlStrdup((const xmlChar *) " "); - str_len = 1; - } - - number = (int) xmlXPathPopNumber(ctxt); - - if (number <= 0) { - xmlXPathReturnEmptyString(ctxt); - xmlFree(str); - return; - } - - while (number >= str_len) { - ret = xmlStrncat(ret, str, str_len); - number -= str_len; - } - tmp = xmlUTF8Strndup (str, number); - ret = xmlStrcat(ret, tmp); - if (tmp != NULL) - xmlFree (tmp); - - xmlXPathReturnString(ctxt, ret); - - if (str != NULL) - xmlFree(str); -} - -/** - * exsltStrAlignFunction: - * @ctxt: an XPath parser context - * @nargs: the number of arguments - * - * Aligns a string within another string. - */ -static void -exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) { - xmlChar *str, *padding, *alignment, *ret; - int str_l, padding_l; - - if ((nargs < 2) || (nargs > 3)) { - xmlXPathSetArityError(ctxt); - return; - } - - if (nargs == 3) - alignment = xmlXPathPopString(ctxt); - else - alignment = NULL; - - padding = xmlXPathPopString(ctxt); - str = xmlXPathPopString(ctxt); - - str_l = xmlUTF8Strlen (str); - padding_l = xmlUTF8Strlen (padding); - - if (str_l == padding_l) { - xmlXPathReturnString (ctxt, str); - xmlFree(padding); - xmlFree(alignment); - return; - } - - if (str_l > padding_l) { - ret = xmlUTF8Strndup (str, padding_l); - } else { - if (xmlStrEqual(alignment, (const xmlChar *) "right")) { - ret = xmlUTF8Strndup (padding, padding_l - str_l); - ret = xmlStrcat (ret, str); - } else if (xmlStrEqual(alignment, (const xmlChar *) "center")) { - int left = (padding_l - str_l) / 2; - int right_start; - - ret = xmlUTF8Strndup (padding, left); - ret = xmlStrcat (ret, str); - - right_start = xmlUTF8Strsize (padding, left + str_l); - ret = xmlStrcat (ret, padding + right_start); - } else { - int str_s; - - str_s = xmlStrlen (str); - ret = xmlStrdup (str); - ret = xmlStrcat (ret, padding + str_s); - } - } - - xmlXPathReturnString (ctxt, ret); - - xmlFree(str); - xmlFree(padding); - xmlFree(alignment); -} - -/** - * exsltStrConcatFunction: - * @ctxt: an XPath parser context - * @nargs: the number of arguments - * - * Takes a node set and returns the concatenation of the string values - * of the nodes in that node set. If the node set is empty, it - * returns an empty string. - */ -static void -exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) { - xmlXPathObjectPtr obj; - xmlChar *ret = NULL; - int i; - - if (nargs != 1) { - xmlXPathSetArityError(ctxt); - return; - } - - if (!xmlXPathStackIsNodeSet(ctxt)) { - xmlXPathSetTypeError(ctxt); - return; - } - - obj = valuePop (ctxt); - - if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) { - xmlXPathReturnEmptyString(ctxt); - return; - } - - for (i = 0; i < obj->nodesetval->nodeNr; i++) { - xmlChar *tmp; - tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); - - ret = xmlStrcat (ret, tmp); - - xmlFree(tmp); - } - - xmlXPathFreeObject (obj); - - xmlXPathReturnString(ctxt, ret); -} - -/** - * exsltStrRegister: - * - * Registers the EXSLT - Strings module - */ - -void -exsltStrRegister (void) { - xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize", - EXSLT_STRINGS_NAMESPACE, - exsltStrTokenizeFunction); - xsltRegisterExtModuleFunction ((const xmlChar *) "split", - EXSLT_STRINGS_NAMESPACE, - exsltStrSplitFunction); - xsltRegisterExtModuleFunction ((const xmlChar *) "encode-uri", - EXSLT_STRINGS_NAMESPACE, - exsltStrEncodeUriFunction); - xsltRegisterExtModuleFunction ((const xmlChar *) "decode-uri", - EXSLT_STRINGS_NAMESPACE, - exsltStrDecodeUriFunction); - xsltRegisterExtModuleFunction ((const xmlChar *) "padding", - EXSLT_STRINGS_NAMESPACE, - exsltStrPaddingFunction); - xsltRegisterExtModuleFunction ((const xmlChar *) "align", - EXSLT_STRINGS_NAMESPACE, - exsltStrAlignFunction); - xsltRegisterExtModuleFunction ((const xmlChar *) "concat", - EXSLT_STRINGS_NAMESPACE, - exsltStrConcatFunction); -} +#define IN_LIBEXSLT
+#include "libexslt/libexslt.h"
+
+#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
+#include <win32config.h>
+#else
+#include "config.h"
+#endif
+
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/parser.h>
+#include <libxml/encoding.h>
+#include <libxml/uri.h>
+
+#include <libxslt/xsltconfig.h>
+#include <libxslt/xsltutils.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/extensions.h>
+
+#include "exslt.h"
+
+/**
+ * exsltStrTokenizeFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments
+ *
+ * Splits up a string on the characters of the delimiter string and returns a
+ * node set of token elements, each containing one token from the string.
+ */
+static void
+exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)
+{
+ xsltTransformContextPtr tctxt;
+ xmlChar *str, *delimiters, *cur;
+ const xmlChar *token, *delimiter;
+ xmlNodePtr node;
+ xmlDocPtr container;
+ xmlXPathObjectPtr ret = NULL;
+ int clen;
+
+ if ((nargs < 1) || (nargs > 2)) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ if (nargs == 2) {
+ delimiters = xmlXPathPopString(ctxt);
+ if (xmlXPathCheckError(ctxt))
+ return;
+ } else {
+ delimiters = xmlStrdup((const xmlChar *) "\t\r\n ");
+ }
+ if (delimiters == NULL)
+ return;
+
+ str = xmlXPathPopString(ctxt);
+ if (xmlXPathCheckError(ctxt) || (str == NULL)) {
+ xmlFree(delimiters);
+ return;
+ }
+
+ /* Return a result tree fragment */
+ tctxt = xsltXPathGetTransformContext(ctxt);
+ if (tctxt == NULL) {
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+ "exslt:tokenize : internal error tctxt == NULL\n");
+ goto fail;
+ }
+
+ container = xsltCreateRVT(tctxt);
+ if (container != NULL) {
+ xsltRegisterLocalRVT(tctxt, container);
+ ret = xmlXPathNewNodeSet(NULL);
+ if (ret != NULL) {
+ for (cur = str, token = str; *cur != 0; cur += clen) {
+ clen = xmlUTF8Size(cur);
+ if (*delimiters == 0) { /* empty string case */
+ xmlChar ctmp;
+ ctmp = *(cur+clen);
+ *(cur+clen) = 0;
+ node = xmlNewDocRawNode(container, NULL,
+ (const xmlChar *) "token", cur);
+ xmlAddChild((xmlNodePtr) container, node);
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);
+ *(cur+clen) = ctmp; /* restore the changed byte */
+ token = cur + clen;
+ } else for (delimiter = delimiters; *delimiter != 0;
+ delimiter += xmlUTF8Size(delimiter)) {
+ if (!xmlUTF8Charcmp(cur, delimiter)) {
+ if (cur == token) {
+ /* discard empty tokens */
+ token = cur + clen;
+ break;
+ }
+ *cur = 0; /* terminate the token */
+ node = xmlNewDocRawNode(container, NULL,
+ (const xmlChar *) "token", token);
+ xmlAddChild((xmlNodePtr) container, node);
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);
+ *cur = *delimiter; /* restore the changed byte */
+ token = cur + clen;
+ break;
+ }
+ }
+ }
+ if (token != cur) {
+ node = xmlNewDocRawNode(container, NULL,
+ (const xmlChar *) "token", token);
+ xmlAddChild((xmlNodePtr) container, node);
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);
+ }
+ }
+ }
+
+fail:
+ if (str != NULL)
+ xmlFree(str);
+ if (delimiters != NULL)
+ xmlFree(delimiters);
+ if (ret != NULL)
+ valuePush(ctxt, ret);
+ else
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+}
+
+/**
+ * exsltStrSplitFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments
+ *
+ * Splits up a string on a delimiting string and returns a node set of token
+ * elements, each containing one token from the string.
+ */
+static void
+exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+ xsltTransformContextPtr tctxt;
+ xmlChar *str, *delimiter, *cur;
+ const xmlChar *token;
+ xmlNodePtr node;
+ xmlDocPtr container;
+ xmlXPathObjectPtr ret = NULL;
+ int delimiterLength;
+
+ if ((nargs < 1) || (nargs > 2)) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ if (nargs == 2) {
+ delimiter = xmlXPathPopString(ctxt);
+ if (xmlXPathCheckError(ctxt))
+ return;
+ } else {
+ delimiter = xmlStrdup((const xmlChar *) " ");
+ }
+ if (delimiter == NULL)
+ return;
+ delimiterLength = xmlStrlen (delimiter);
+
+ str = xmlXPathPopString(ctxt);
+ if (xmlXPathCheckError(ctxt) || (str == NULL)) {
+ xmlFree(delimiter);
+ return;
+ }
+
+ /* Return a result tree fragment */
+ tctxt = xsltXPathGetTransformContext(ctxt);
+ if (tctxt == NULL) {
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+ "exslt:tokenize : internal error tctxt == NULL\n");
+ goto fail;
+ }
+
+ /*
+ * OPTIMIZE TODO: We are creating an xmlDoc for every split!
+ */
+ container = xsltCreateRVT(tctxt);
+ if (container != NULL) {
+ xsltRegisterLocalRVT(tctxt, container);
+ ret = xmlXPathNewNodeSet(NULL);
+ if (ret != NULL) {
+ for (cur = str, token = str; *cur != 0; cur++) {
+ if (delimiterLength == 0) {
+ if (cur != token) {
+ xmlChar tmp = *cur;
+ *cur = 0;
+ node = xmlNewDocRawNode(container, NULL,
+ (const xmlChar *) "token", token);
+ xmlAddChild((xmlNodePtr) container, node);
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);
+ *cur = tmp;
+ token++;
+ }
+ }
+ else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) {
+ if (cur == token) {
+ /* discard empty tokens */
+ cur = cur + delimiterLength - 1;
+ token = cur + 1;
+ continue;
+ }
+ *cur = 0;
+ node = xmlNewDocRawNode(container, NULL,
+ (const xmlChar *) "token", token);
+ xmlAddChild((xmlNodePtr) container, node);
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);
+ *cur = *delimiter;
+ cur = cur + delimiterLength - 1;
+ token = cur + 1;
+ }
+ }
+ if (token != cur) {
+ node = xmlNewDocRawNode(container, NULL,
+ (const xmlChar *) "token", token);
+ xmlAddChild((xmlNodePtr) container, node);
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);
+ }
+ }
+ }
+
+fail:
+ if (str != NULL)
+ xmlFree(str);
+ if (delimiter != NULL)
+ xmlFree(delimiter);
+ if (ret != NULL)
+ valuePush(ctxt, ret);
+ else
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+}
+
+/**
+ * exsltStrEncodeUriFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments
+ *
+ * URI-Escapes a string
+ */
+static void
+exsltStrEncodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+ int escape_all = 1, str_len = 0;
+ xmlChar *str = NULL, *ret = NULL, *tmp;
+
+ if ((nargs < 2) || (nargs > 3)) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ if (nargs >= 3) {
+ /* check for UTF-8 if encoding was explicitly given;
+ we don't support anything else yet */
+ tmp = xmlXPathPopString(ctxt);
+ if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {
+ xmlXPathReturnEmptyString(ctxt);
+ xmlFree(tmp);
+ return;
+ }
+ xmlFree(tmp);
+ }
+
+ escape_all = xmlXPathPopBoolean(ctxt);
+
+ str = xmlXPathPopString(ctxt);
+ str_len = xmlUTF8Strlen(str);
+
+ if (str_len == 0) {
+ xmlXPathReturnEmptyString(ctxt);
+ xmlFree(str);
+ return;
+ }
+
+ ret = xmlURIEscapeStr(str,(const xmlChar *)(escape_all?"-_.!~*'()":"-_.!~*'();/?:@&=+$,[]"));
+ xmlXPathReturnString(ctxt, ret);
+
+ if (str != NULL)
+ xmlFree(str);
+}
+
+/**
+ * exsltStrDecodeUriFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments
+ *
+ * reverses URI-Escaping of a string
+ */
+static void
+exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+ int str_len = 0;
+ xmlChar *str = NULL, *ret = NULL, *tmp;
+
+ if ((nargs < 1) || (nargs > 2)) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ if (nargs >= 2) {
+ /* check for UTF-8 if encoding was explicitly given;
+ we don't support anything else yet */
+ tmp = xmlXPathPopString(ctxt);
+ if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {
+ xmlXPathReturnEmptyString(ctxt);
+ xmlFree(tmp);
+ return;
+ }
+ xmlFree(tmp);
+ }
+
+ str = xmlXPathPopString(ctxt);
+ str_len = xmlUTF8Strlen(str);
+
+ if (str_len == 0) {
+ xmlXPathReturnEmptyString(ctxt);
+ xmlFree(str);
+ return;
+ }
+
+ ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL);
+ if (!xmlCheckUTF8(ret)) {
+ /* FIXME: instead of throwing away the whole URI, we should
+ only discard the invalid sequence(s). How to do that? */
+ xmlXPathReturnEmptyString(ctxt);
+ xmlFree(str);
+ xmlFree(ret);
+ return;
+ }
+
+ xmlXPathReturnString(ctxt, ret);
+
+ if (str != NULL)
+ xmlFree(str);
+}
+
+/**
+ * exsltStrPaddingFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments
+ *
+ * Creates a padding string of a certain length.
+ */
+static void
+exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+ int number, str_len = 0;
+ xmlChar *str = NULL, *ret = NULL, *tmp;
+
+ if ((nargs < 1) || (nargs > 2)) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ if (nargs == 2) {
+ str = xmlXPathPopString(ctxt);
+ str_len = xmlUTF8Strlen(str);
+ }
+ if (str_len == 0) {
+ if (str != NULL) xmlFree(str);
+ str = xmlStrdup((const xmlChar *) " ");
+ str_len = 1;
+ }
+
+ number = (int) xmlXPathPopNumber(ctxt);
+
+ if (number <= 0) {
+ xmlXPathReturnEmptyString(ctxt);
+ xmlFree(str);
+ return;
+ }
+
+ while (number >= str_len) {
+ ret = xmlStrncat(ret, str, str_len);
+ number -= str_len;
+ }
+ tmp = xmlUTF8Strndup (str, number);
+ ret = xmlStrcat(ret, tmp);
+ if (tmp != NULL)
+ xmlFree (tmp);
+
+ xmlXPathReturnString(ctxt, ret);
+
+ if (str != NULL)
+ xmlFree(str);
+}
+
+/**
+ * exsltStrAlignFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments
+ *
+ * Aligns a string within another string.
+ */
+static void
+exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+ xmlChar *str, *padding, *alignment, *ret;
+ int str_l, padding_l;
+
+ if ((nargs < 2) || (nargs > 3)) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ if (nargs == 3)
+ alignment = xmlXPathPopString(ctxt);
+ else
+ alignment = NULL;
+
+ padding = xmlXPathPopString(ctxt);
+ str = xmlXPathPopString(ctxt);
+
+ str_l = xmlUTF8Strlen (str);
+ padding_l = xmlUTF8Strlen (padding);
+
+ if (str_l == padding_l) {
+ xmlXPathReturnString (ctxt, str);
+ xmlFree(padding);
+ xmlFree(alignment);
+ return;
+ }
+
+ if (str_l > padding_l) {
+ ret = xmlUTF8Strndup (str, padding_l);
+ } else {
+ if (xmlStrEqual(alignment, (const xmlChar *) "right")) {
+ ret = xmlUTF8Strndup (padding, padding_l - str_l);
+ ret = xmlStrcat (ret, str);
+ } else if (xmlStrEqual(alignment, (const xmlChar *) "center")) {
+ int left = (padding_l - str_l) / 2;
+ int right_start;
+
+ ret = xmlUTF8Strndup (padding, left);
+ ret = xmlStrcat (ret, str);
+
+ right_start = xmlUTF8Strsize (padding, left + str_l);
+ ret = xmlStrcat (ret, padding + right_start);
+ } else {
+ int str_s;
+
+ str_s = xmlStrlen (str);
+ ret = xmlStrdup (str);
+ ret = xmlStrcat (ret, padding + str_s);
+ }
+ }
+
+ xmlXPathReturnString (ctxt, ret);
+
+ xmlFree(str);
+ xmlFree(padding);
+ xmlFree(alignment);
+}
+
+/**
+ * exsltStrConcatFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments
+ *
+ * Takes a node set and returns the concatenation of the string values
+ * of the nodes in that node set. If the node set is empty, it
+ * returns an empty string.
+ */
+static void
+exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+ xmlXPathObjectPtr obj;
+ xmlChar *ret = NULL;
+ int i;
+
+ if (nargs != 1) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ if (!xmlXPathStackIsNodeSet(ctxt)) {
+ xmlXPathSetTypeError(ctxt);
+ return;
+ }
+
+ obj = valuePop (ctxt);
+
+ if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {
+ xmlXPathReturnEmptyString(ctxt);
+ return;
+ }
+
+ for (i = 0; i < obj->nodesetval->nodeNr; i++) {
+ xmlChar *tmp;
+ tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
+
+ ret = xmlStrcat (ret, tmp);
+
+ xmlFree(tmp);
+ }
+
+ xmlXPathFreeObject (obj);
+
+ xmlXPathReturnString(ctxt, ret);
+}
+
+/**
+ * exsltStrRegister:
+ *
+ * Registers the EXSLT - Strings module
+ */
+
+void
+exsltStrRegister (void) {
+ xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize",
+ EXSLT_STRINGS_NAMESPACE,
+ exsltStrTokenizeFunction);
+ xsltRegisterExtModuleFunction ((const xmlChar *) "split",
+ EXSLT_STRINGS_NAMESPACE,
+ exsltStrSplitFunction);
+ xsltRegisterExtModuleFunction ((const xmlChar *) "encode-uri",
+ EXSLT_STRINGS_NAMESPACE,
+ exsltStrEncodeUriFunction);
+ xsltRegisterExtModuleFunction ((const xmlChar *) "decode-uri",
+ EXSLT_STRINGS_NAMESPACE,
+ exsltStrDecodeUriFunction);
+ xsltRegisterExtModuleFunction ((const xmlChar *) "padding",
+ EXSLT_STRINGS_NAMESPACE,
+ exsltStrPaddingFunction);
+ xsltRegisterExtModuleFunction ((const xmlChar *) "align",
+ EXSLT_STRINGS_NAMESPACE,
+ exsltStrAlignFunction);
+ xsltRegisterExtModuleFunction ((const xmlChar *) "concat",
+ EXSLT_STRINGS_NAMESPACE,
+ exsltStrConcatFunction);
+}
|