root/third_party/libxslt/libexslt/functions.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. exsltFuncRegisterFunc
  2. exsltFuncRegisterImportFunc
  3. exsltFuncInit
  4. exsltFuncShutdown
  5. exsltFuncStyleInit
  6. exsltFuncStyleShutdown
  7. exsltFuncNewFunctionData
  8. exsltFreeFuncResultPreComp
  9. exsltFuncFunctionFunction
  10. exsltFuncFunctionComp
  11. exsltFuncResultComp
  12. exsltFuncResultElem
  13. exsltFuncRegister

#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);

#define MAX_FUNC_RECURSION 1000

/*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 oldResult, ret;
    exsltFuncData *data;
    exsltFuncFunctionData *func;
    xmlNodePtr paramNode, oldInsert, fake;
    int oldBase;
    xsltStackElemPtr params = NULL, param;
    xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
    int i, notSet;
    struct objChain {
        struct objChain *next;
        xmlXPathObjectPtr obj;
    };
    struct objChain     *savedObjChain = NULL, *savedObj;

    /*
     * 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;
    }
    if (tctxt->funcLevel > MAX_FUNC_RECURSION) {
        xsltGenericError(xsltGenericErrorContext,
                         "{%s}%s: detected a recursion\n",
                         ctxt->context->functionURI, ctxt->context->function);
        ctxt->error = XPATH_MEMORY_ERROR;
        return;
    }
    tctxt->funcLevel++;

    /*
     * We have a problem with the evaluation of function parameters.
     * The original library code did not evaluate XPath expressions until
     * the last moment.  After version 1.1.17 of the libxslt, the logic
     * of other parts of the library was changed, and the evaluation of
     * XPath expressions within parameters now takes place as soon as the
     * parameter is parsed/evaluated (xsltParseStylesheetCallerParam).
     * This means that the parameters need to be evaluated in lexical
     * order (since a variable is "in scope" as soon as it is declared).
     * However, on entry to this routine, the values (from the caller) are
     * in reverse order (held on the XPath context variable stack).  To
     * accomplish what is required, I have added code to pop the XPath
     * objects off of the stack at the beginning and save them, then use
     * them (in the reverse order) as the params are evaluated.  This
     * requires an xmlMalloc/xmlFree for each param set by the caller,
     * which is not very nice.  There is probably a much better solution
     * (like change other code to delay the evaluation).
     */
    /* 
     * In order to give the function params and variables a new 'scope'
     * we change varsBase in the context.
     */
    oldBase = tctxt->varsBase;
    tctxt->varsBase = tctxt->varsNr;
    /* If there are any parameters */
    if (paramNode != NULL) {
        /* Fetch the stored argument values from the caller */
        for (i = 0; i < nargs; i++) {
            savedObj = xmlMalloc(sizeof(struct objChain));
            savedObj->next = savedObjChain;
            savedObj->obj = valuePop(ctxt);
            savedObjChain = savedObj;
        }

        /*
         * Prepare to process params in reverse order.  First, go to
         * the beginning of the param chain.
         */
        for (i = 1; i <= func->nargs; i++) {
            if (paramNode->prev == NULL)
                break;
            paramNode = paramNode->prev;
        }
        /*
         * i has total # params found, nargs is number which are present
         * as arguments from the caller
         * Calculate the number of un-set parameters
         */
        notSet = func->nargs - nargs;
        for (; i > 0; i--) {
            param = xsltParseStylesheetCallerParam (tctxt, paramNode);
            if (i > notSet) {   /* if parameter value set */
                param->computed = 1;
                if (param->value != NULL)
                    xmlXPathFreeObject(param->value);
                savedObj = savedObjChain;       /* get next val from chain */
                param->value = savedObj->obj;
                savedObjChain = savedObjChain->next;
                xmlFree(savedObj);
            }
            xsltLocalVariablePush(tctxt, param, -1);
            param->next = params;
            params = param;
            paramNode = paramNode->next;
        }
    }
    /*
     * actual processing
     */
    fake = xmlNewDocNode(tctxt->output, NULL,
                         (const xmlChar *)"fake", NULL);
    oldInsert = tctxt->insert;
    tctxt->insert = fake;
    xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
                          func->content, NULL, NULL);
    xsltLocalVariablePop(tctxt, tctxt->varsBase, -2);
    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);
    tctxt->funcLevel--;
}


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 (IS_XSLT_ELEM(test) &&
            IS_XSLT_NAME(test, "stylesheet")) {
            xsltGenericError(xsltGenericErrorContext,
                             "func:result element not a descendant "
                             "of a func:function\n");
            return (NULL);
        }
        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"
                             " the function 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);
}

/* [<][>][^][v][top][bottom][index][help] */