1#define IN_LIBEXSLT
2#include "libexslt/libexslt.h"
3
4#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
5#include <win32config.h>
6#else
7#include "config.h"
8#endif
9
10#include <string.h>
11
12#include <libxml/tree.h>
13#include <libxml/xpath.h>
14#include <libxml/xpathInternals.h>
15#include <libxml/hash.h>
16#include <libxml/debugXML.h>
17
18#include <libxslt/xsltutils.h>
19#include <libxslt/variables.h>
20#include <libxslt/xsltInternals.h>
21#include <libxslt/extensions.h>
22#include <libxslt/transform.h>
23#include <libxslt/imports.h>
24
25#include "exslt.h"
26
27typedef struct _exsltFuncFunctionData exsltFuncFunctionData;
28struct _exsltFuncFunctionData {
29    int nargs;			/* number of arguments to the function */
30    xmlNodePtr content;		/* the func:fuction template content */
31};
32
33typedef struct _exsltFuncData exsltFuncData;
34struct _exsltFuncData {
35    xmlHashTablePtr funcs;	/* pointer to the stylesheet module data */
36    xmlXPathObjectPtr result;	/* returned by func:result */
37    int error;			/* did an error occur? */
38    xmlDocPtr RVT;   /* result tree fragment */
39};
40
41typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp;
42struct _exsltFuncResultPreComp {
43    xsltElemPreComp comp;
44    xmlXPathCompExprPtr select;
45    xmlNsPtr *nsList;
46    int nsNr;
47};
48
49/* Used for callback function in exsltInitFunc */
50typedef struct _exsltFuncImportRegData exsltFuncImportRegData;
51struct _exsltFuncImportRegData {
52    xsltTransformContextPtr ctxt;
53    xmlHashTablePtr hash;
54};
55
56static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,
57				       int nargs);
58static exsltFuncFunctionData *exsltFuncNewFunctionData(void);
59
60#define MAX_FUNC_RECURSION 1000
61
62/*static const xmlChar *exsltResultDataID = (const xmlChar *) "EXSLT Result";*/
63
64/**
65 * exsltFuncRegisterFunc:
66 * @func:  the #exsltFuncFunctionData for the function
67 * @ctxt:  an XSLT transformation context
68 * @URI:  the function namespace URI
69 * @name: the function name
70 *
71 * Registers a function declared by a func:function element
72 */
73static void
74exsltFuncRegisterFunc (exsltFuncFunctionData *data,
75		       xsltTransformContextPtr ctxt,
76		       const xmlChar *URI, const xmlChar *name,
77		       ATTRIBUTE_UNUSED const xmlChar *ignored) {
78    if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL))
79	return;
80
81    xsltGenericDebug(xsltGenericDebugContext,
82		     "exsltFuncRegisterFunc: register {%s}%s\n",
83		     URI, name);
84    xsltRegisterExtFunction(ctxt, name, URI,
85			    exsltFuncFunctionFunction);
86}
87
88/*
89 * exsltFuncRegisterImportFunc
90 * @data:    the exsltFuncFunctionData for the function
91 * @ch:	     structure containing context and hash table
92 * @URI:     the function namespace URI
93 * @name:    the function name
94 *
95 * Checks if imported function is already registered in top-level
96 * stylesheet.  If not, copies function data and registers function
97 */
98static void
99exsltFuncRegisterImportFunc (exsltFuncFunctionData *data,
100			     exsltFuncImportRegData *ch,
101			     const xmlChar *URI, const xmlChar *name,
102			     ATTRIBUTE_UNUSED const xmlChar *ignored) {
103    exsltFuncFunctionData *func=NULL;
104
105    if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL))
106            return;
107
108    if (ch->ctxt == NULL || ch->hash == NULL)
109	return;
110
111    /* Check if already present */
112    func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash, URI, name);
113    if (func == NULL) {		/* Not yet present - copy it in */
114	func = exsltFuncNewFunctionData();
115	memcpy(func, data, sizeof(exsltFuncFunctionData));
116	if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) {
117	    xsltGenericError(xsltGenericErrorContext,
118		    "Failed to register function {%s}%s\n",
119		    URI, name);
120	} else {		/* Do the registration */
121	    xsltGenericDebug(xsltGenericDebugContext,
122	            "exsltFuncRegisterImportFunc: register {%s}%s\n",
123		    URI, name);
124	    xsltRegisterExtFunction(ch->ctxt, name, URI,
125		    exsltFuncFunctionFunction);
126	}
127    }
128}
129
130/**
131 * exsltFuncInit:
132 * @ctxt: an XSLT transformation context
133 * @URI: the namespace URI for the extension
134 *
135 * Initializes the EXSLT - Functions module.
136 * Called at transformation-time; merges all
137 * functions declared in the import tree taking
138 * import precedence into account, i.e. overriding
139 * functions with lower import precedence.
140 *
141 * Returns the data for this transformation
142 */
143static exsltFuncData *
144exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
145    exsltFuncData *ret;
146    xsltStylesheetPtr tmp;
147    exsltFuncImportRegData ch;
148    xmlHashTablePtr hash;
149
150    ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData));
151    if (ret == NULL) {
152	xsltGenericError(xsltGenericErrorContext,
153			 "exsltFuncInit: not enough memory\n");
154	return(NULL);
155    }
156    memset(ret, 0, sizeof(exsltFuncData));
157
158    ret->result = NULL;
159    ret->error = 0;
160
161    ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI);
162    ret->funcs = ch.hash;
163    xmlHashScanFull(ch.hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt);
164    tmp = ctxt->style;
165    ch.ctxt = ctxt;
166    while ((tmp=xsltNextImport(tmp))!=NULL) {
167	hash = xsltGetExtInfo(tmp, URI);
168	if (hash != NULL) {
169	    xmlHashScanFull(hash,
170		    (xmlHashScannerFull) exsltFuncRegisterImportFunc, &ch);
171	}
172    }
173
174    return(ret);
175}
176
177/**
178 * exsltFuncShutdown:
179 * @ctxt: an XSLT transformation context
180 * @URI: the namespace URI for the extension
181 * @data: the module data to free up
182 *
183 * Shutdown the EXSLT - Functions module
184 * Called at transformation-time.
185 */
186static void
187exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
188		   const xmlChar *URI ATTRIBUTE_UNUSED,
189		   exsltFuncData *data) {
190    if (data->result != NULL)
191	xmlXPathFreeObject(data->result);
192    xmlFree(data);
193}
194
195/**
196 * exsltFuncStyleInit:
197 * @style: an XSLT stylesheet
198 * @URI: the namespace URI for the extension
199 *
200 * Allocates the stylesheet data for EXSLT - Function
201 * Called at compile-time.
202 *
203 * Returns the allocated data
204 */
205static xmlHashTablePtr
206exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
207		    const xmlChar *URI ATTRIBUTE_UNUSED) {
208    return xmlHashCreate(1);
209}
210
211/**
212 * exsltFuncStyleShutdown:
213 * @style: an XSLT stylesheet
214 * @URI: the namespace URI for the extension
215 * @data: the stylesheet data to free up
216 *
217 * Shutdown the EXSLT - Function module
218 * Called at compile-time.
219 */
220static void
221exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
222			const xmlChar *URI ATTRIBUTE_UNUSED,
223			xmlHashTablePtr data) {
224    xmlHashFree(data, (xmlHashDeallocator) xmlFree);
225}
226
227/**
228 * exsltFuncNewFunctionData:
229 *
230 * Allocates an #exslFuncFunctionData object
231 *
232 * Returns the new structure
233 */
234static exsltFuncFunctionData *
235exsltFuncNewFunctionData (void) {
236    exsltFuncFunctionData *ret;
237
238    ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData));
239    if (ret == NULL) {
240	xsltGenericError(xsltGenericErrorContext,
241			 "exsltFuncNewFunctionData: not enough memory\n");
242	return (NULL);
243    }
244    memset(ret, 0, sizeof(exsltFuncFunctionData));
245
246    ret->nargs = 0;
247    ret->content = NULL;
248
249    return(ret);
250}
251
252/**
253 * exsltFreeFuncResultPreComp:
254 * @comp:  the #exsltFuncResultPreComp to free up
255 *
256 * Deallocates an #exsltFuncResultPreComp
257 */
258static void
259exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) {
260    if (comp == NULL)
261	return;
262
263    if (comp->select != NULL)
264	xmlXPathFreeCompExpr (comp->select);
265    if (comp->nsList != NULL)
266        xmlFree(comp->nsList);
267    xmlFree(comp);
268}
269
270/**
271 * exsltFuncFunctionFunction:
272 * @ctxt:  an XPath parser context
273 * @nargs:  the number of arguments
274 *
275 * Evaluates the func:function element that defines the called function.
276 */
277static void
278exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
279    xmlXPathObjectPtr oldResult, ret;
280    exsltFuncData *data;
281    exsltFuncFunctionData *func;
282    xmlNodePtr paramNode, oldInsert, fake;
283    int oldBase;
284    xsltStackElemPtr params = NULL, param;
285    xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
286    int i, notSet;
287    struct objChain {
288	struct objChain *next;
289	xmlXPathObjectPtr obj;
290    };
291    struct objChain	*savedObjChain = NULL, *savedObj;
292
293    /*
294     * retrieve func:function template
295     */
296    data = (exsltFuncData *) xsltGetExtData (tctxt,
297					     EXSLT_FUNCTIONS_NAMESPACE);
298    oldResult = data->result;
299    data->result = NULL;
300
301    func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs,
302						    ctxt->context->functionURI,
303						    ctxt->context->function);
304
305    /*
306     * params handling
307     */
308    if (nargs > func->nargs) {
309	xsltGenericError(xsltGenericErrorContext,
310			 "{%s}%s: called with too many arguments\n",
311			 ctxt->context->functionURI, ctxt->context->function);
312	ctxt->error = XPATH_INVALID_ARITY;
313	return;
314    }
315    if (func->content != NULL) {
316	paramNode = func->content->prev;
317    }
318    else
319	paramNode = NULL;
320    if ((paramNode == NULL) && (func->nargs != 0)) {
321	xsltGenericError(xsltGenericErrorContext,
322			 "exsltFuncFunctionFunction: nargs != 0 and "
323			 "param == NULL\n");
324	return;
325    }
326    if (tctxt->funcLevel > MAX_FUNC_RECURSION) {
327	xsltGenericError(xsltGenericErrorContext,
328			 "{%s}%s: detected a recursion\n",
329			 ctxt->context->functionURI, ctxt->context->function);
330	ctxt->error = XPATH_MEMORY_ERROR;
331	return;
332    }
333    tctxt->funcLevel++;
334
335    /*
336     * We have a problem with the evaluation of function parameters.
337     * The original library code did not evaluate XPath expressions until
338     * the last moment.  After version 1.1.17 of the libxslt, the logic
339     * of other parts of the library was changed, and the evaluation of
340     * XPath expressions within parameters now takes place as soon as the
341     * parameter is parsed/evaluated (xsltParseStylesheetCallerParam).
342     * This means that the parameters need to be evaluated in lexical
343     * order (since a variable is "in scope" as soon as it is declared).
344     * However, on entry to this routine, the values (from the caller) are
345     * in reverse order (held on the XPath context variable stack).  To
346     * accomplish what is required, I have added code to pop the XPath
347     * objects off of the stack at the beginning and save them, then use
348     * them (in the reverse order) as the params are evaluated.  This
349     * requires an xmlMalloc/xmlFree for each param set by the caller,
350     * which is not very nice.  There is probably a much better solution
351     * (like change other code to delay the evaluation).
352     */
353    /*
354     * In order to give the function params and variables a new 'scope'
355     * we change varsBase in the context.
356     */
357    oldBase = tctxt->varsBase;
358    tctxt->varsBase = tctxt->varsNr;
359    /* If there are any parameters */
360    if (paramNode != NULL) {
361        /* Fetch the stored argument values from the caller */
362	for (i = 0; i < nargs; i++) {
363	    savedObj = xmlMalloc(sizeof(struct objChain));
364	    savedObj->next = savedObjChain;
365	    savedObj->obj = valuePop(ctxt);
366	    savedObjChain = savedObj;
367	}
368
369	/*
370	 * Prepare to process params in reverse order.  First, go to
371	 * the beginning of the param chain.
372	 */
373	for (i = 1; i <= func->nargs; i++) {
374	    if (paramNode->prev == NULL)
375	        break;
376	    paramNode = paramNode->prev;
377	}
378	/*
379	 * i has total # params found, nargs is number which are present
380	 * as arguments from the caller
381	 * Calculate the number of un-set parameters
382	 */
383	notSet = func->nargs - nargs;
384	for (; i > 0; i--) {
385	    param = xsltParseStylesheetCallerParam (tctxt, paramNode);
386	    if (i > notSet) {	/* if parameter value set */
387		param->computed = 1;
388		if (param->value != NULL)
389		    xmlXPathFreeObject(param->value);
390		savedObj = savedObjChain;	/* get next val from chain */
391		param->value = savedObj->obj;
392		savedObjChain = savedObjChain->next;
393		xmlFree(savedObj);
394	    }
395	    xsltLocalVariablePush(tctxt, param, -1);
396	    param->next = params;
397	    params = param;
398	    paramNode = paramNode->next;
399	}
400    }
401    /*
402     * actual processing
403     */
404    fake = xmlNewDocNode(tctxt->output, NULL,
405			 (const xmlChar *)"fake", NULL);
406    oldInsert = tctxt->insert;
407    tctxt->insert = fake;
408    xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
409			  func->content, NULL, NULL);
410    xsltLocalVariablePop(tctxt, tctxt->varsBase, -2);
411    tctxt->insert = oldInsert;
412    tctxt->varsBase = oldBase;	/* restore original scope */
413    if (params != NULL)
414	xsltFreeStackElemList(params);
415
416    if (data->error != 0)
417	goto error;
418
419    if (data->result != NULL) {
420	ret = data->result;
421    } else
422	ret = xmlXPathNewCString("");
423
424    data->result = oldResult;
425
426    /*
427     * It is an error if the instantiation of the template results in
428     * the generation of result nodes.
429     */
430    if (fake->children != NULL) {
431#ifdef LIBXML_DEBUG_ENABLED
432	xmlDebugDumpNode (stderr, fake, 1);
433#endif
434	xsltGenericError(xsltGenericErrorContext,
435			 "{%s}%s: cannot write to result tree while "
436			 "executing a function\n",
437			 ctxt->context->functionURI, ctxt->context->function);
438	xmlFreeNode(fake);
439	goto error;
440    }
441    xmlFreeNode(fake);
442    valuePush(ctxt, ret);
443
444error:
445    /*
446    * IMPORTANT: This enables previously tree fragments marked as
447    * being results of a function, to be garbage-collected after
448    * the calling process exits.
449    */
450    xsltExtensionInstructionResultFinalize(tctxt);
451    tctxt->funcLevel--;
452}
453
454
455static void
456exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) {
457    xmlChar *name, *prefix;
458    xmlNsPtr ns;
459    xmlHashTablePtr data;
460    exsltFuncFunctionData *func;
461
462    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
463	return;
464
465    {
466	xmlChar *qname;
467
468	qname = xmlGetProp(inst, (const xmlChar *) "name");
469	name = xmlSplitQName2 (qname, &prefix);
470	xmlFree(qname);
471    }
472    if ((name == NULL) || (prefix == NULL)) {
473	xsltGenericError(xsltGenericErrorContext,
474			 "func:function: not a QName\n");
475	if (name != NULL)
476	    xmlFree(name);
477	return;
478    }
479    /* namespace lookup */
480    ns = xmlSearchNs (inst->doc, inst, prefix);
481    if (ns == NULL) {
482	xsltGenericError(xsltGenericErrorContext,
483			 "func:function: undeclared prefix %s\n",
484			 prefix);
485	xmlFree(name);
486	xmlFree(prefix);
487	return;
488    }
489    xmlFree(prefix);
490
491    xsltParseTemplateContent(style, inst);
492
493    /*
494     * Create function data
495     */
496    func = exsltFuncNewFunctionData();
497    func->content = inst->children;
498    while (IS_XSLT_ELEM(func->content) &&
499	   IS_XSLT_NAME(func->content, "param")) {
500	func->content = func->content->next;
501	func->nargs++;
502    }
503
504    /*
505     * Register the function data such that it can be retrieved
506     * by exslFuncFunctionFunction
507     */
508#ifdef XSLT_REFACTORED
509    /*
510    * Ensure that the hash table will be stored in the *current*
511    * stylesheet level in order to correctly evaluate the
512    * import precedence.
513    */
514    data = (xmlHashTablePtr)
515	xsltStyleStylesheetLevelGetExtData(style,
516	    EXSLT_FUNCTIONS_NAMESPACE);
517#else
518    data = (xmlHashTablePtr)
519	xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE);
520#endif
521    if (data == NULL) {
522	xsltGenericError(xsltGenericErrorContext,
523			 "exsltFuncFunctionComp: no stylesheet data\n");
524	xmlFree(name);
525	return;
526    }
527
528    if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) {
529	xsltTransformError(NULL, style, inst,
530	    "Failed to register function {%s}%s\n",
531			 ns->href, name);
532	style->errors++;
533    } else {
534	xsltGenericDebug(xsltGenericDebugContext,
535			 "exsltFuncFunctionComp: register {%s}%s\n",
536			 ns->href, name);
537    }
538    xmlFree(name);
539}
540
541static xsltElemPreCompPtr
542exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst,
543		     xsltTransformFunction function) {
544    xmlNodePtr test;
545    xmlChar *sel;
546    exsltFuncResultPreComp *ret;
547
548    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
549        return (NULL);
550
551    /*
552     * "Validity" checking
553     */
554    /* it is an error to have any following sibling elements aside
555     * from the xsl:fallback element.
556     */
557    for (test = inst->next; test != NULL; test = test->next) {
558	if (test->type != XML_ELEMENT_NODE)
559	    continue;
560	if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback"))
561	    continue;
562	xsltGenericError(xsltGenericErrorContext,
563			 "exsltFuncResultElem: only xsl:fallback is "
564			 "allowed to follow func:result\n");
565	style->errors++;
566	return (NULL);
567    }
568    /* it is an error for a func:result element to not be a descendant
569     * of func:function.
570     * it is an error if a func:result occurs within a func:result
571     * element.
572     * it is an error if instanciating the content of a variable
573     * binding element (i.e. xsl:variable, xsl:param) results in the
574     * instanciation of a func:result element.
575     */
576    for (test = inst->parent; test != NULL; test = test->parent) {
577	if (IS_XSLT_ELEM(test) &&
578	    IS_XSLT_NAME(test, "stylesheet")) {
579	    xsltGenericError(xsltGenericErrorContext,
580			     "func:result element not a descendant "
581			     "of a func:function\n");
582	    style->errors++;
583	    return (NULL);
584	}
585	if ((test->ns != NULL) &&
586	    (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) {
587	    if (xmlStrEqual(test->name, (const xmlChar *) "function")) {
588		break;
589	    }
590	    if (xmlStrEqual(test->name, (const xmlChar *) "result")) {
591		xsltGenericError(xsltGenericErrorContext,
592				 "func:result element not allowed within"
593				 " another func:result element\n");
594	        style->errors++;
595		return (NULL);
596	    }
597	}
598	if (IS_XSLT_ELEM(test) &&
599	    (IS_XSLT_NAME(test, "variable") ||
600	     IS_XSLT_NAME(test, "param"))) {
601	    xsltGenericError(xsltGenericErrorContext,
602			     "func:result element not allowed within"
603			     " a variable binding element\n");
604            style->errors++;
605	    return (NULL);
606	}
607    }
608
609    /*
610     * Precomputation
611     */
612    ret = (exsltFuncResultPreComp *)
613	xmlMalloc (sizeof(exsltFuncResultPreComp));
614    if (ret == NULL) {
615	xsltPrintErrorContext(NULL, NULL, NULL);
616        xsltGenericError(xsltGenericErrorContext,
617                         "exsltFuncResultComp : malloc failed\n");
618        style->errors++;
619        return (NULL);
620    }
621    memset(ret, 0, sizeof(exsltFuncResultPreComp));
622
623    xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function,
624		 (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp);
625    ret->select = NULL;
626
627    /*
628     * Precompute the select attribute
629     */
630    sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL);
631    if (sel != NULL) {
632	ret->select = xmlXPathCompile (sel);
633	xmlFree(sel);
634    }
635    /*
636     * Precompute the namespace list
637     */
638    ret->nsList = xmlGetNsList(inst->doc, inst);
639    if (ret->nsList != NULL) {
640        int i = 0;
641        while (ret->nsList[i] != NULL)
642	    i++;
643	ret->nsNr = i;
644    }
645    return ((xsltElemPreCompPtr) ret);
646}
647
648static void
649exsltFuncResultElem (xsltTransformContextPtr ctxt,
650	             xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
651		     exsltFuncResultPreComp *comp) {
652    exsltFuncData *data;
653    xmlXPathObjectPtr ret;
654
655
656    /* It is an error if instantiating the content of the
657     * func:function element results in the instantiation of more than
658     * one func:result elements.
659     */
660    data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE);
661    if (data == NULL) {
662	xsltGenericError(xsltGenericErrorContext,
663			 "exsltFuncReturnElem: data == NULL\n");
664	return;
665    }
666    if (data->result != NULL) {
667	xsltGenericError(xsltGenericErrorContext,
668			 "func:result already instanciated\n");
669	data->error = 1;
670	return;
671    }
672    /*
673     * Processing
674     */
675    if (comp->select != NULL) {
676	xmlNsPtr *oldXPNsList;
677	int oldXPNsNr;
678	xmlNodePtr oldXPContextNode;
679	/* If the func:result element has a select attribute, then the
680	 * value of the attribute must be an expression and the
681	 * returned value is the object that results from evaluating
682	 * the expression. In this case, the content must be empty.
683	 */
684	if (inst->children != NULL) {
685	    xsltGenericError(xsltGenericErrorContext,
686			     "func:result content must be empty if"
687			     " the function has a select attribute\n");
688	    data->error = 1;
689	    return;
690	}
691	oldXPNsList = ctxt->xpathCtxt->namespaces;
692	oldXPNsNr = ctxt->xpathCtxt->nsNr;
693	oldXPContextNode = ctxt->xpathCtxt->node;
694
695	ctxt->xpathCtxt->namespaces = comp->nsList;
696	ctxt->xpathCtxt->nsNr = comp->nsNr;
697
698	ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt);
699
700	ctxt->xpathCtxt->node = oldXPContextNode;
701	ctxt->xpathCtxt->nsNr = oldXPNsNr;
702	ctxt->xpathCtxt->namespaces = oldXPNsList;
703
704	if (ret == NULL) {
705	    xsltGenericError(xsltGenericErrorContext,
706			     "exsltFuncResultElem: ret == NULL\n");
707	    return;
708	}
709	/*
710	* Mark it as a function result in order to avoid garbage
711	* collecting of tree fragments before the function exits.
712	*/
713	xsltExtensionInstructionResultRegister(ctxt, ret);
714    } else if (inst->children != NULL) {
715	/* If the func:result element does not have a select attribute
716	 * and has non-empty content (i.e. the func:result element has
717	 * one or more child nodes), then the content of the
718	 * func:result element specifies the value.
719	 */
720	xmlNodePtr oldInsert;
721	xmlDocPtr container;
722
723	container = xsltCreateRVT(ctxt);
724	if (container == NULL) {
725	    xsltGenericError(xsltGenericErrorContext,
726			     "exsltFuncResultElem: out of memory\n");
727	    data->error = 1;
728	    return;
729	}
730	xsltRegisterLocalRVT(ctxt, container);
731
732	oldInsert = ctxt->insert;
733	ctxt->insert = (xmlNodePtr) container;
734	xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
735			      inst->children, NULL, NULL);
736	ctxt->insert = oldInsert;
737
738	ret = xmlXPathNewValueTree((xmlNodePtr) container);
739	if (ret == NULL) {
740	    xsltGenericError(xsltGenericErrorContext,
741			     "exsltFuncResultElem: ret == NULL\n");
742	    data->error = 1;
743	} else {
744	    ret->boolval = 0; /* Freeing is not handled there anymore */
745	    /*
746	    * Mark it as a function result in order to avoid garbage
747	    * collecting of tree fragments before the function exits.
748	    */
749	    xsltExtensionInstructionResultRegister(ctxt, ret);
750	}
751    } else {
752	/* If the func:result element has empty content and does not
753	 * have a select attribute, then the returned value is an
754	 * empty string.
755	 */
756	ret = xmlXPathNewCString("");
757    }
758    data->result = ret;
759}
760
761/**
762 * exsltFuncRegister:
763 *
764 * Registers the EXSLT - Functions module
765 */
766void
767exsltFuncRegister (void) {
768    xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,
769		       (xsltExtInitFunction) exsltFuncInit,
770		       (xsltExtShutdownFunction) exsltFuncShutdown,
771		       (xsltStyleExtInitFunction) exsltFuncStyleInit,
772		       (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown);
773
774    xsltRegisterExtModuleTopLevel ((const xmlChar *) "function",
775				   EXSLT_FUNCTIONS_NAMESPACE,
776				   exsltFuncFunctionComp);
777    xsltRegisterExtModuleElement ((const xmlChar *) "result",
778			  EXSLT_FUNCTIONS_NAMESPACE,
779			  (xsltPreComputeFunction)exsltFuncResultComp,
780			  (xsltTransformFunction) exsltFuncResultElem);
781}
782