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 | |
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')
-rw-r--r-- | libexslt/common.c | 262 | ||||
-rw-r--r-- | libexslt/dynamic.c | 548 | ||||
-rw-r--r-- | libexslt/functions.c | 1458 | ||||
-rw-r--r-- | libexslt/strings.c | 1052 |
4 files changed, 1660 insertions, 1660 deletions
diff --git a/libexslt/common.c b/libexslt/common.c index 7b07ea28..ba57fa5b 100644 --- a/libexslt/common.c +++ b/libexslt/common.c @@ -1,131 +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) {
- 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);
-}
+#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 87ef8da3..11c291b0 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)
- 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);
-
-}
+/* + * 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 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); +} diff --git a/libexslt/strings.c b/libexslt/strings.c index 484310a8..c867f9cb 100644 --- a/libexslt/strings.c +++ b/libexslt/strings.c @@ -1,526 +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) {
- 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);
-}
+#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); +} |