diff --git a/libexslt/common.c b/libexslt/common.c index 451a60d8..91be04fd 100644 --- a/libexslt/common.c +++ b/libexslt/common.c @@ -60,12 +60,6 @@ exsltNodeSetFunction (xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformError(tctxt, NULL, tctxt->inst, "exsltNodeSetFunction: Failed to create a node set object.\n"); tctxt->state = XSLT_STATE_STOPPED; - } else { - /* - * Mark it as a function result in order to avoid garbage - * collecting of tree fragments - */ - xsltExtensionInstructionResultRegister(tctxt, obj); } if (strval != NULL) xmlFree (strval); diff --git a/libexslt/dynamic.c b/libexslt/dynamic.c index 7b95fc5e..4a4944e8 100644 --- a/libexslt/dynamic.c +++ b/libexslt/dynamic.c @@ -216,7 +216,6 @@ exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs) xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } - xsltExtensionInstructionResultRegister(tctxt, ret); } break; case XPATH_NUMBER: @@ -239,7 +238,6 @@ exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs) xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } - xsltExtensionInstructionResultRegister(tctxt, ret); } break; case XPATH_STRING: @@ -257,7 +255,6 @@ exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs) xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } - xsltExtensionInstructionResultRegister(tctxt, ret); } break; default: diff --git a/libexslt/functions.c b/libexslt/functions.c index 0795a13d..b2c98d56 100644 --- a/libexslt/functions.c +++ b/libexslt/functions.c @@ -35,7 +35,6 @@ 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; @@ -428,6 +427,12 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) { if (data->result != NULL) { ret = data->result; + /* + * IMPORTANT: This enables previously tree fragments marked as + * being results of a function, to be garbage-collected after + * the calling process exits. + */ + xsltFlagRVTs(tctxt, ret, XSLT_RVT_LOCAL); } else ret = xmlXPathNewCString(""); @@ -452,12 +457,6 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) { 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--; } @@ -724,7 +723,7 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt, * Mark it as a function result in order to avoid garbage * collecting of tree fragments before the function exits. */ - xsltExtensionInstructionResultRegister(ctxt, ret); + xsltFlagRVTs(ctxt, ret, XSLT_RVT_FUNC_RESULT); } 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 @@ -741,7 +740,8 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt, data->error = 1; return; } - xsltRegisterLocalRVT(ctxt, container); + /* Mark as function result. */ + container->psvi = XSLT_RVT_FUNC_RESULT; oldInsert = ctxt->insert; ctxt->insert = (xmlNodePtr) container; @@ -756,11 +756,6 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt, 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 diff --git a/libexslt/strings.c b/libexslt/strings.c index f5f2d3c5..62f76fb3 100644 --- a/libexslt/strings.c +++ b/libexslt/strings.c @@ -111,11 +111,6 @@ exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } - /* - * Mark it as a function result in order to avoid garbage - * collecting of tree fragments - */ - xsltExtensionInstructionResultRegister(tctxt, ret); } } @@ -222,11 +217,6 @@ exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } - /* - * Mark it as a function result in order to avoid garbage - * collecting of tree fragments - */ - xsltExtensionInstructionResultRegister(tctxt, ret); } } @@ -543,7 +533,6 @@ exsltStrReturnString(xmlXPathParserContextPtr ctxt, const xmlChar *str, return(-1); } - xsltExtensionInstructionResultRegister(tctxt, ret); valuePush(ctxt, ret); return(0); diff --git a/libxslt/transform.c b/libxslt/transform.c index 8b86e2eb..9faaede0 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -56,6 +56,7 @@ #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_EXTRA #define WITH_XSLT_DEBUG_PROCESS +#define WITH_XSLT_DEBUG_VARIABLE #endif #define XSLT_GENERATE_HTML_DOCTYPE @@ -2299,30 +2300,28 @@ xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base) { xmlDocPtr cur = ctxt->localRVT, tmp; - while ((cur != NULL) && (cur != base)) { - if (cur->psvi == (void *) ((long) 1)) { - cur = (xmlDocPtr) cur->next; - } else { - tmp = cur; - cur = (xmlDocPtr) cur->next; + if (cur == base) + return; + if (cur->prev != NULL) + xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n"); - if (tmp == ctxt->localRVT) - ctxt->localRVT = cur; + do { + tmp = cur; + cur = (xmlDocPtr) cur->next; + if (tmp->psvi == XSLT_RVT_LOCAL) { + xsltReleaseRVT(ctxt, tmp); + } else if (tmp->psvi == XSLT_RVT_GLOBAL) { + xsltRegisterPersistRVT(ctxt, tmp); + } else if (tmp->psvi != XSLT_RVT_FUNC_RESULT) { + xmlGenericError(xmlGenericErrorContext, + "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n", + tmp->psvi); + } + } while (cur != base); - /* - * We need ctxt->localRVTBase for extension instructions - * which return values (like EXSLT's function). - */ - if (tmp == ctxt->localRVTBase) - ctxt->localRVTBase = cur; - - if (tmp->prev) - tmp->prev->next = (xmlNodePtr) cur; - if (cur) - cur->prev = tmp->prev; - xsltReleaseRVT(ctxt, tmp); - } - } + if (base != NULL) + base->prev = NULL; + ctxt->localRVT = base; } /** @@ -2348,7 +2347,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode; xmlNodePtr cur, insert, copy = NULL; int level = 0, oldVarsNr; - xmlDocPtr oldLocalFragmentTop, oldLocalFragmentBase; + xmlDocPtr oldLocalFragmentTop; #ifdef XSLT_REFACTORED xsltStylePreCompPtr info; @@ -2676,16 +2675,9 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, cur->name)); #endif ctxt->insert = insert; - /* - * We need the fragment base for extension instructions - * which return values (like EXSLT's function). - */ - oldLocalFragmentBase = ctxt->localRVTBase; - ctxt->localRVTBase = NULL; func(ctxt, contextNode, cur, cur->psvi); - ctxt->localRVTBase = oldLocalFragmentBase; /* * Cleanup temporary tree fragments. */ @@ -2749,12 +2741,9 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, oldCurInst = ctxt->inst; ctxt->inst = cur; ctxt->insert = insert; - oldLocalFragmentBase = ctxt->localRVTBase; - ctxt->localRVTBase = NULL; info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info); - ctxt->localRVTBase = oldLocalFragmentBase; /* * Cleanup temporary tree fragments. */ @@ -2869,12 +2858,6 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, #endif ctxt->insert = insert; - /* - * We need the fragment base for extension instructions - * which return values (like EXSLT's function). - */ - oldLocalFragmentBase = ctxt->localRVTBase; - ctxt->localRVTBase = NULL; function(ctxt, contextNode, cur, cur->psvi); /* @@ -2883,7 +2866,6 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, if (oldLocalFragmentTop != ctxt->localRVT) xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); - ctxt->localRVTBase = oldLocalFragmentBase; ctxt->insert = oldInsert; } @@ -3059,7 +3041,7 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, long start = 0; xmlNodePtr cur; xsltStackElemPtr tmpParam = NULL; - xmlDocPtr oldUserFragmentTop, oldLocalFragmentTop; + xmlDocPtr oldUserFragmentTop; #ifdef XSLT_REFACTORED xsltStyleItemParamPtr iparam; @@ -3122,7 +3104,6 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, oldUserFragmentTop = ctxt->tmpRVT; ctxt->tmpRVT = NULL; - oldLocalFragmentTop = ctxt->localRVT; /* * Initiate a distinct scope of local params/variables. @@ -3223,31 +3204,6 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, xsltTemplateParamsCleanup(ctxt); ctxt->varsBase = oldVarsBase; - /* - * Clean up remaining local tree fragments. - * This also frees fragments which are the result of - * extension instructions. Should normally not be hit; but - * just for the case xsltExtensionInstructionResultFinalize() - * was not called by the extension author. - */ - if (oldLocalFragmentTop != ctxt->localRVT) { - xmlDocPtr curdoc = ctxt->localRVT, tmp; - - do { - tmp = curdoc; - curdoc = (xmlDocPtr) curdoc->next; - /* Need to housekeep localRVTBase */ - if (tmp == ctxt->localRVTBase) - ctxt->localRVTBase = curdoc; - if (tmp->prev) - tmp->prev->next = (xmlNodePtr) curdoc; - if (curdoc) - curdoc->prev = tmp->prev; - xsltReleaseRVT(ctxt, tmp); - } while (curdoc != oldLocalFragmentTop); - } - ctxt->localRVT = oldLocalFragmentTop; - /* * Release user-created fragments stored in the scope * of xsl:template. Note that this mechanism is deprecated: @@ -6040,6 +5996,9 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc, xsltEvalGlobalVariables(ctxt); + /* Clean up any unused RVTs. */ + xsltReleaseLocalRVTs(ctxt, NULL); + ctxt->node = (xmlNodePtr) doc; ctxt->output = res; ctxt->insert = (xmlNodePtr) res; diff --git a/libxslt/variables.c b/libxslt/variables.c index 345123d6..52cd68da 100644 --- a/libxslt/variables.c +++ b/libxslt/variables.c @@ -43,8 +43,8 @@ const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt"; const xmlChar *xsltComputingGlobalVarMarker = (const xmlChar *) " var/param being computed"; -#define XSLT_VAR_GLOBAL 1<<0 -#define XSLT_VAR_IN_SELECT 1<<1 +#define XSLT_VAR_GLOBAL (1<<0) +#define XSLT_VAR_IN_SELECT (1<<1) #define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable) /************************************************************************ @@ -122,6 +122,9 @@ xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) if ((ctxt == NULL) || (RVT == NULL)) return(-1); + RVT->prev = NULL; + RVT->psvi = XSLT_RVT_VARIABLE; + /* * We'll restrict the lifetime of user-created fragments * insinde an xsl:variable and xsl:param to the lifetime of the @@ -159,15 +162,18 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, if ((ctxt == NULL) || (RVT == NULL)) return(-1); + RVT->prev = NULL; + /* * When evaluating "select" expressions of xsl:variable * and xsl:param, we need to bind newly created tree fragments - * to the variable itself; otherwise the tragment will be + * to the variable itself; otherwise the fragment will be * freed before we leave the scope of a var. */ if ((ctxt->contextVariable != NULL) && (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT)) { + RVT->psvi = XSLT_RVT_VARIABLE; RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment; XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT; return(0); @@ -177,19 +183,11 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, * If not reference by a returning instruction (like EXSLT's function), * then this fragment will be freed, when the instruction exits. */ + RVT->psvi = XSLT_RVT_LOCAL; RVT->next = (xmlNodePtr) ctxt->localRVT; if (ctxt->localRVT != NULL) ctxt->localRVT->prev = (xmlNodePtr) RVT; ctxt->localRVT = RVT; - /* - * We need to keep track of the first registered fragment - * for extension instructions which return fragments - * (e.g. EXSLT'S function), in order to let - * xsltExtensionInstructionResultFinalize() clear the - * preserving flag on the fragments. - */ - if (ctxt->localRVTBase == NULL) - ctxt->localRVTBase = RVT; return(0); } @@ -204,26 +202,16 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, * collector will free them after the function-calling process exits. * * Returns 0 in case of success and -1 in case of API or internal errors. + * + * This function is unsupported in newer releases of libxslt. */ int xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt) { - xmlDocPtr cur; - - if (ctxt == NULL) - return(-1); - if (ctxt->localRVTBase == NULL) - return(0); - /* - * Enable remaining local tree fragments to be freed - * by the fragment garbage collector. - */ - cur = ctxt->localRVTBase; - do { - cur->psvi = NULL; - cur = (xmlDocPtr) cur->next; - } while (cur != NULL); - return(0); + xmlGenericError(xmlGenericErrorContext, + "xsltExtensionInstructionResultFinalize is unsupported " + "in this release of libxslt.\n"); + return(-1); } /** @@ -238,11 +226,35 @@ xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt) * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT(). * * Returns 0 in case of success and -1 in case of error. + * + * It isn't necessary to call this function in newer releases of + * libxslt. */ int xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj) { + return(0); +} + +/** + * xsltFlagRVTs: + * @ctxt: an XSLT transformation context + * @obj: an XPath object to be inspected for result tree fragments + * @val: the flag value + * + * Updates ownership information of RVTs in @obj according to @val. + * + * @val = XSLT_RVT_FUNC_RESULT for the result of an extension function, so its + * RVTs won't be destroyed after leaving the returning scope. + * @val = XSLT_RVT_LOCAL for the result of an extension function to reset + * the state of its RVTs after it was returned to a new scope. + * @val = XSLT_RVT_GLOBAL for parts of global variables. + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, void *val) { int i; xmlNodePtr cur; xmlDocPtr doc; @@ -275,36 +287,59 @@ xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt, doc = cur->doc; } else { xsltTransformError(ctxt, NULL, ctxt->inst, - "Internal error in " - "xsltExtensionInstructionResultRegister(): " + "Internal error in xsltFlagRVTs(): " "Cannot retrieve the doc of a namespace node.\n"); - goto error; + return(-1); } } else { doc = cur->doc; } if (doc == NULL) { xsltTransformError(ctxt, NULL, ctxt->inst, - "Internal error in " - "xsltExtensionInstructionResultRegister(): " + "Internal error in xsltFlagRVTs(): " "Cannot retrieve the doc of a node.\n"); - goto error; + return(-1); } - if (doc->name && (doc->name[0] == ' ')) { + if (doc->name && (doc->name[0] == ' ') && + doc->psvi != XSLT_RVT_GLOBAL) { /* * This is a result tree fragment. - * We'll use the @psvi field for reference counting. - * TODO: How do we know if this is a value of a - * global variable or a doc acquired via the + * We store ownership information in the @psvi field. + * TODO: How do we know if this is a doc acquired via the * document() function? */ - doc->psvi = (void *) ((long) 1); +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "Flagging RVT %p: %p -> %p\n", doc, doc->psvi, val)); +#endif + + if (val == XSLT_RVT_LOCAL) { + if (doc->psvi != XSLT_RVT_FUNC_RESULT) { + xmlGenericError(xmlGenericErrorContext, + "xsltFlagRVTs: Invalid transition %p => LOCAL\n", + doc->psvi); + return(-1); + } + + xsltRegisterLocalRVT(ctxt, doc); + } else if (val == XSLT_RVT_GLOBAL) { + if (doc->psvi != XSLT_RVT_LOCAL) { + xmlGenericError(xmlGenericErrorContext, + "xsltFlagRVTs: Invalid transition %p => GLOBAL\n", + doc->psvi); + doc->psvi = XSLT_RVT_GLOBAL; + return(-1); + } + + /* Will be registered as persistant in xsltReleaseLocalRVTs. */ + doc->psvi = XSLT_RVT_GLOBAL; + } else if (val == XSLT_RVT_FUNC_RESULT) { + doc->psvi = val; + } } } return(0); -error: - return(-1); } /** @@ -350,9 +385,9 @@ xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) } /* - * Reset the reference counter. + * Reset the ownership information. */ - RVT->psvi = 0; + RVT->psvi = NULL; RVT->next = (xmlNodePtr) ctxt->cache->RVT; ctxt->cache->RVT = RVT; @@ -391,6 +426,8 @@ xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) { if ((ctxt == NULL) || (RVT == NULL)) return(-1); + RVT->psvi = XSLT_RVT_GLOBAL; + RVT->prev = NULL; RVT->next = (xmlNodePtr) ctxt->persistRVT; if (ctxt->persistRVT != NULL) ctxt->persistRVT->prev = (xmlNodePtr) RVT; @@ -541,35 +578,21 @@ xsltFreeStackElem(xsltStackElemPtr elem) { /* * Release the list of temporary Result Tree Fragments. */ - if (elem->fragment) { + if (elem->context) { xmlDocPtr cur; while (elem->fragment != NULL) { cur = elem->fragment; elem->fragment = (xmlDocPtr) cur->next; - if (elem->context && - (cur->psvi == (void *) ((long) 1))) - { - /* - * This fragment is a result of an extension instruction - * (e.g. XSLT's function) and needs to be preserved until - * the instruction exits. - * Example: The fragment of the variable must not be freed - * since it is returned by the EXSLT function: - * - * - * - * - * - * - * - */ - xsltRegisterLocalRVT(elem->context, cur); - } else { + if (cur->psvi == XSLT_RVT_VARIABLE) { xsltReleaseRVT((xsltTransformContextPtr) elem->context, cur); - } + } else if (cur->psvi != XSLT_RVT_FUNC_RESULT) { + xmlGenericError(xmlGenericErrorContext, + "xsltFreeStackElem: Unexpected RVT flag %p\n", + cur->psvi); + } } } /* @@ -963,6 +986,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, * the Result Tree Fragment. */ variable->fragment = container; + container->psvi = XSLT_RVT_VARIABLE; oldOutput = ctxt->output; oldInsert = ctxt->insert; @@ -1149,16 +1173,23 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) xsltTransformError(ctxt, NULL, comp->inst, "Evaluating global variable %s failed\n", elem->name); ctxt->state = XSLT_STATE_STOPPED; + goto error; + } + + /* + * Mark all RVTs that are referenced from result as part + * of this variable so they won't be freed too early. + */ + xsltFlagRVTs(ctxt, result, XSLT_RVT_GLOBAL); + #ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef LIBXML_DEBUG_ENABLED - } else { - if ((xsltGenericDebugContext == stdout) || - (xsltGenericDebugContext == stderr)) - xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, - result, 0); + if ((xsltGenericDebugContext == stdout) || + (xsltGenericDebugContext == stderr)) + xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, + result, 0); #endif #endif - } } else { if (elem->tree == NULL) { result = xmlXPathNewCString(""); diff --git a/libxslt/variables.h b/libxslt/variables.h index 17b4c6f6..f80eeab6 100644 --- a/libxslt/variables.h +++ b/libxslt/variables.h @@ -34,6 +34,15 @@ extern "C" { xsltRegisterAllElement(ctxt); \ (ctxt)->xpathCtxt->extra = ctxt +/* + * Flags for memory management of RVTs + */ + +#define XSLT_RVT_LOCAL ((void *)1) +#define XSLT_RVT_VARIABLE ((void *)2) +#define XSLT_RVT_FUNC_RESULT ((void *)3) +#define XSLT_RVT_GLOBAL ((void *)4) + /* * Interfaces for the variable module. */ diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index 7123acec..b56cbdd3 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -1783,7 +1783,7 @@ struct _xsltTransformContext { xmlDocPtr localRVT; /* list of local tree fragments; will be freed when the instruction which created the fragment exits */ - xmlDocPtr localRVTBase; + xmlDocPtr localRVTBase; /* Obsolete */ int keyInitLevel; /* Needed to catch recursive keys issues */ int funcLevel; /* Needed to catch recursive functions issues */ int maxTemplateDepth; @@ -1906,6 +1906,11 @@ XSLTPUBFUN int XSLTCALL XSLTPUBFUN int XSLTCALL xsltExtensionInstructionResultFinalize( xsltTransformContextPtr ctxt); +XSLTPUBFUN int XSLTCALL + xsltFlagRVTs( + xsltTransformContextPtr ctxt, + xmlXPathObjectPtr obj, + void *val); XSLTPUBFUN void XSLTCALL xsltFreeRVTs (xsltTransformContextPtr ctxt); XSLTPUBFUN void XSLTCALL diff --git a/tests/docs/bug-192.xml b/tests/docs/bug-192.xml new file mode 100644 index 00000000..69d62f2c --- /dev/null +++ b/tests/docs/bug-192.xml @@ -0,0 +1 @@ + diff --git a/tests/exslt/functions/Makefile.am b/tests/exslt/functions/Makefile.am index 303043a1..3241284e 100644 --- a/tests/exslt/functions/Makefile.am +++ b/tests/exslt/functions/Makefile.am @@ -13,7 +13,8 @@ EXTRA_DIST = \ function.7.out function.7.xml function.7.xsl \ function.8.out function.8.xml function.8.xsl \ function.9.out function.9.xml function.9.xsl \ - function.10.out function.10.xml function.10.xsl + function.10.out function.10.xml function.10.xsl \ + function.11.out function.11.xml function.11.xsl CLEANFILES = .memdump diff --git a/tests/exslt/functions/function.11.out b/tests/exslt/functions/function.11.out new file mode 100644 index 00000000..6dde03e7 --- /dev/null +++ b/tests/exslt/functions/function.11.out @@ -0,0 +1,2 @@ + + diff --git a/tests/exslt/functions/function.11.xml b/tests/exslt/functions/function.11.xml new file mode 100644 index 00000000..8e39ecbe --- /dev/null +++ b/tests/exslt/functions/function.11.xml @@ -0,0 +1,2 @@ + + diff --git a/tests/exslt/functions/function.11.xsl b/tests/exslt/functions/function.11.xsl new file mode 100644 index 00000000..7a3437a6 --- /dev/null +++ b/tests/exslt/functions/function.11.xsl @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/general/bug-192.out b/tests/general/bug-192.out new file mode 100644 index 00000000..6c2eeca1 --- /dev/null +++ b/tests/general/bug-192.out @@ -0,0 +1 @@ +assert 'success!' == 'success!' diff --git a/tests/general/bug-192.xsl b/tests/general/bug-192.xsl new file mode 100644 index 00000000..1307211c --- /dev/null +++ b/tests/general/bug-192.xsl @@ -0,0 +1,33 @@ + + + + + + + + + + + + + success! + + + + + + + + assert 'success!' == ' + + ' + + + +