# HG changeset patch
# User Daniel Veillard <veillard@src.gnome.org>
# Date 980010136 0
#      Sat Jan 20 17:02:16 2001 +0000
# Node ID 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6
# Parent  633bc556eed679d8b110123258f2cedb2a0c1246
Working on variables implementation:
- libxslt/transform.c libxslt/variables.[ch] libxslt/xslt.c
  libxslt/xsltInternals.h libxslt/xsltutils.h: changed a few
  structure to add an execution stack with variables. Tree
  valued variables still missing.
- TODO: updated
Daniel

diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Sat Jan 20 17:59:20 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+	* libxslt/transform.c libxslt/variables.[ch] libxslt/xslt.c
+	  libxslt/xsltInternals.h libxslt/xsltutils.h: changed a few
+	  structure to add an execution stack with variables. Tree
+	  valued variables still missing.
+	* TODO: updated
+
 Fri Jan 19 13:16:57 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* libxslt/xslt.c: check version on stylesheets
diff --git a/TODO b/TODO
--- a/TODO
+++ b/TODO
@@ -2,6 +2,7 @@
   - should transforms for a given stylesheet be thread clean,
     or can a stylesheet be enriched with document specific
     informations and cleaned up later ?
+    => currently stylesheet manipulation is not reentrant.
   - seems that saving back XSLT stylesheet from a compiled form might
     be a bit ugly ...
     
diff --git a/libxslt/transform.c b/libxslt/transform.c
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -29,6 +29,7 @@
 #include "xsltutils.h"
 #include "pattern.h"
 #include "transform.h"
+#include "variables.h"
 
 #define DEBUG_PROCESS
 
@@ -39,31 +40,6 @@
 #define IS_BLANK_NODE(n)						\
     (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
 
-/*
- * Types are private:
- */
-
-typedef enum xsltOutputType {
-    XSLT_OUTPUT_XML = 0,
-    XSLT_OUTPUT_HTML,
-    XSLT_OUTPUT_TEXT
-} xsltOutputType;
-
-typedef struct _xsltTransformContext xsltTransformContext;
-typedef xsltTransformContext *xsltTransformContextPtr;
-struct _xsltTransformContext {
-    xsltStylesheetPtr style;		/* the stylesheet used */
-    xsltOutputType type;		/* the type of output */
-
-    xmlDocPtr doc;			/* the current doc */
-    xmlNodePtr node;			/* the current node */
-    xmlNodeSetPtr nodeList;		/* the current node list */
-
-    xmlDocPtr output;			/* the resulting document */
-    xmlNodePtr insert;			/* the insertion node */
-
-    xmlXPathContextPtr xpathCtxt;	/* the XPath context */
-};
 
 /************************************************************************
  *									*
@@ -104,6 +80,7 @@
 	return;
     if (ctxt->xpathCtxt != NULL)
 	xmlXPathFreeContext(ctxt->xpathCtxt);
+    xsltFreeVariableHashes(ctxt);
     memset(ctxt, -1, sizeof(xsltTransformContext));
     xmlFree(ctxt);
 }
@@ -330,7 +307,7 @@
 	/* TODO: attribute value template */
 	if (ns) {
 #if LIBXML_VERSION > 20211
-	    attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, value);
+	    attr = xmlSetNsProp(ctxt->insert, ns, ncname, value);
 #else
 	    xsltGenericError(xsltGenericErrorContext,
 		"xsl:attribute: recompile against newer libxml version\n");
@@ -403,6 +380,7 @@
 	ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
 	if (ctxt->xpathCtxt == NULL)
 	    goto error;
+	XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
     }
     xpathParserCtxt =
 	xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
@@ -643,6 +621,7 @@
 	    ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
 	    if (ctxt->xpathCtxt == NULL)
 		goto error;
+	    XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
 	}
 	xpathParserCtxt =
 	    xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
@@ -775,6 +754,7 @@
 	             xmlNodePtr list) {
     xmlNodePtr cur, insert, copy;
     xmlNodePtr oldInsert;
+    int has_variables = 0;
 
     oldInsert = insert = ctxt->insert;
     /*
@@ -818,6 +798,11 @@
 		ctxt->insert = insert;
 		xsltAttribute(ctxt, node, cur);
 		ctxt->insert = oldInsert;
+	    } else if (IS_XSLT_NAME(cur, "variable")) {
+		if (has_variables == 0) {
+		    xsltPushStack(ctxt);
+		}
+		xsltParseStylesheetVariable(ctxt, cur);
 	    } else {
 #ifdef DEBUG_PROCESS
 		xsltGenericError(xsltGenericDebugContext,
@@ -889,6 +874,9 @@
 	    }
 	} while (cur != NULL);
     }
+    if (has_variables != 0) {
+	xsltPopStack(ctxt);
+    }
 }
 
 /**
@@ -926,6 +914,7 @@
 	ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
 	if (ctxt->xpathCtxt == NULL)
 	    goto error;
+	XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
     }
     xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
     if (xpathParserCtxt == NULL)
@@ -1008,6 +997,7 @@
 	ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
 	if (ctxt->xpathCtxt == NULL)
 	    goto error;
+	XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
     }
     xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
     if (xpathParserCtxt == NULL)
diff --git a/libxslt/variables.c b/libxslt/variables.c
--- a/libxslt/variables.c
+++ b/libxslt/variables.c
@@ -32,6 +32,238 @@
  */
 
 
+typedef enum {
+    XSLT_ELEM_VARIABLE=1,
+    XSLT_ELEM_PARAM
+} xsltElem;
+
+typedef struct _xsltStackElem xsltStackElem;
+typedef xsltStackElem *xsltStackElemPtr;
+struct _xsltStackElem {
+    struct _xsltStackElem *next;/* chained list */
+    xsltElem elem;	/* type of the element */
+    int computed;	/* was the evaluation done */
+    xmlChar *name;	/* the local part of the name QName */
+    xmlChar *nameURI;	/* the URI part of the name QName */
+    xmlXPathObjectPtr value; /* The value if computed */
+    xmlChar *select;	/* the eval string */
+};
+
+typedef struct _xsltStack xsltStack;
+typedef xsltStack *xsltStackPtr;
+struct _xsltStack {
+    int cur;
+    int max;
+    xsltStackElemPtr elems[50];
+};
+
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltNewParserContext:
+ *
+ * Create a new XSLT ParserContext
+ *
+ * Returns the newly allocated xsltParserStackElem or NULL in case of error
+ */
+xsltStackElemPtr
+xsltNewStackElem(void) {
+    xsltStackElemPtr cur;
+
+    cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
+    if (cur == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+		"xsltNewStackElem : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltStackElem));
+    cur->computed = 0;
+    return(cur);
+}
+
+/**
+ * xsltFreeStackElem:
+ * @elem:  an XSLT stack element
+ *
+ * Free up the memory allocated by @elem
+ */
+void
+xsltFreeStackElem(xsltStackElemPtr elem) {
+    if (elem == NULL)
+	return;
+    if (elem->name != NULL)
+	xmlFree(elem->name);
+    if (elem->nameURI != NULL)
+	xmlFree(elem->nameURI);
+    if (elem->select != NULL)
+	xmlFree(elem->select);
+    if (elem->value != NULL)
+	xmlXPathFreeObject(elem->value);
+
+    memset(elem, -1, sizeof(xsltStackElem));
+    xmlFree(elem);
+}
+
+/**
+ * xsltFreeStackElemList:
+ * @elem:  an XSLT stack element
+ *
+ * Free up the memory allocated by @elem
+ */
+void
+xsltFreeStackElemList(xsltStackElemPtr elem) {
+    xsltStackElemPtr next;
+
+    while(elem != NULL) {
+	next = elem->next;
+	xsltFreeStackElem(elem);
+	elem = next;
+    }
+}
+
+/**
+ * xsltAddStackElem:
+ * @ctxt:  xn XSLT transformation context
+ * @elem:  a stack element
+ *
+ * add a new element at this level of the stack.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
+    xsltStackPtr stack;
+
+    if ((ctxt == NULL) || (elem == NULL))
+	return(-1);
+
+    stack = ctxt->variablesHash;
+    if (stack == NULL) {
+	/* TODO make stack size dynamic !!! */
+	stack = xmlMalloc(sizeof (xsltStack));
+	if (stack == NULL) {
+	    xsltGenericError(xsltGenericErrorContext,
+		"xsltPushStack : malloc failed\n");
+	    return(-1);
+	}
+	memset(stack, 0, sizeof(xsltStack));
+	ctxt->variablesHash = stack;
+	stack->cur = 0;
+	stack->max = 50;
+    }
+    /* TODO: check that there is no conflict with existing values
+     * at that level */
+    elem->next = stack->elems[stack->cur];
+    stack->elems[stack->cur] = elem;
+    return(0);
+}
+
+/**
+ * xsltPushStack:
+ * @ctxt:  xn XSLT transformation context
+ *
+ * Push a new level on the ctxtsheet interprestation stack
+ */
+void
+xsltPushStack(xsltTransformContextPtr ctxt) {
+    xsltStackPtr stack;
+
+    if (ctxt == NULL)
+	return;
+
+    stack = ctxt->variablesHash;
+    if (stack == NULL) {
+	/* TODO make stack size dynamic !!! */
+	stack = xmlMalloc(sizeof (xsltStack));
+	if (stack == NULL) {
+	    xsltGenericError(xsltGenericErrorContext,
+		"xsltPushStack : malloc failed\n");
+	    return;
+	}
+	memset(stack, 0, sizeof(xsltStack));
+	ctxt->variablesHash = stack;
+	stack->cur = 0;
+	stack->max = 50;
+    }
+    if (stack->cur >= stack->max + 1) {
+	TODO /* make stack size dynamic !!! */
+	xsltGenericError(xsltGenericErrorContext,
+	    "xsltPushStack : overflow\n");
+	return;
+    }
+    stack->cur++;
+    stack->elems[stack->cur] = NULL;
+}
+
+/**
+ * xsltPopStack:
+ * @ctxt:  an XSLT transformation context
+ *
+ * Pop a level on the ctxtsheet interprestation stack
+ */
+void
+xsltPopStack(xsltTransformContextPtr ctxt) {
+    xsltStackPtr stack;
+
+    if (ctxt == NULL)
+	return;
+
+    stack = ctxt->variablesHash;
+    if (stack == NULL)
+	return;
+
+    xsltFreeStackElemList(stack->elems[stack->cur]);
+    stack->elems[stack->cur] = NULL;
+    stack->cur--;
+}
+
+/**
+ * xsltStackLookup:
+ * @ctxt:  an XSLT transformation context
+ * @name:  the local part of the name
+ * @nameURI:  the URI part of the name
+ *
+ * Locate an element in the stack based on its name.
+ */
+xsltStackElemPtr
+xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
+	        const xmlChar *nameURI) {
+    xsltStackPtr stack;
+    int i;
+    xsltStackElemPtr cur;
+
+    if ((ctxt == NULL) || (name == NULL))
+	return(NULL);
+
+    stack = ctxt->variablesHash;
+    if (stack == NULL)
+	return(NULL);
+
+    for (i = stack->cur;i >= 0;i--) {
+	cur = stack->elems[i];
+	while (cur != NULL) {
+	    if (xmlStrEqual(cur->name, name)) {
+		if (nameURI == NULL) {
+		    if (cur->nameURI == NULL)
+			return(cur);
+		} else {
+		    if ((cur->nameURI != NULL) &&
+			(xmlStrEqual(cur->nameURI, nameURI)))
+			return(cur);
+		}
+
+	    }
+	    cur = cur->next;
+	}
+    }
+    return(NULL);
+}
+
 /************************************************************************
  *									*
  *			Module interfaces				*
@@ -40,10 +272,11 @@
 
 /**
  * xsltRegisterVariable:
- * @style:  the XSLT stylesheet
+ * @ctxt:  the XSLT transformation context
  * @name:  the variable name
  * @ns_uri:  the variable namespace URI
- * @value:  the variable value or NULL
+ * @select:  the expression which need to be evaluated to generate a value
+ * @value:  the variable value if select is NULL
  *
  * Register a new variable value. If @value is NULL it unregisters
  * the variable
@@ -51,26 +284,63 @@
  * Returns 0 in case of success, -1 in case of error
  */
 int
-xsltRegisterVariable(xsltStylesheetPtr style, const xmlChar *name,
-		     const xmlChar *ns_uri, xmlXPathObjectPtr value) {
-    if (style == NULL)
+xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
+		     const xmlChar *ns_uri, const xmlChar *select,
+		     xmlXPathObjectPtr value) {
+    xsltStackElemPtr elem;
+    if (ctxt == NULL)
 	return(-1);
     if (name == NULL)
 	return(-1);
 
-    if (style->variablesHash == NULL)
-	style->variablesHash = xmlHashCreate(0);
-    if (style->variablesHash == NULL)
+    elem = xsltNewStackElem();
+    if (elem == NULL)
 	return(-1);
-    return(xmlHashUpdateEntry2((xmlHashTablePtr) style->variablesHash,
-		               name, ns_uri,
-			       (void *) value,
-			       (xmlHashDeallocator) xmlXPathFreeObject));
+    elem->name = xmlStrdup(name);
+    elem->select = xmlStrdup(select);
+    if (ns_uri)
+	elem->nameURI = xmlStrdup(ns_uri);
+    elem->value = value;
+    xsltAddStackElem(ctxt, elem);
+    if (elem->select != NULL) {
+	xmlXPathObjectPtr result, tmp;
+	xmlXPathParserContextPtr xpathParserCtxt;
+
+	xpathParserCtxt = xmlXPathNewParserContext(elem->select,
+						   ctxt->xpathCtxt);
+	if (xpathParserCtxt == NULL)
+	    goto error;
+	xmlXPathEvalExpr(xpathParserCtxt);
+	result = valuePop(xpathParserCtxt);
+	do {
+	    tmp = valuePop(xpathParserCtxt);
+	    if (tmp != NULL) {
+		xmlXPathFreeObject(tmp);
+	    }
+	} while (tmp != NULL);
+
+	if (result == NULL) {
+#ifdef DEBUG_PROCESS
+	    xsltGenericDebug(xsltGenericDebugContext,
+		"Evaluating variable %s failed\n");
+#endif
+	}
+	if (xpathParserCtxt != NULL)
+	    xmlXPathFreeParserContext(xpathParserCtxt);
+	if (result != NULL) {
+	    if (elem->value != NULL)
+		xmlXPathFreeObject(elem->value);
+	    elem->value = result;
+	    elem->computed = 1;
+	}
+    }
+error:
+    return(0);
 }
 
 /**
  * xsltVariableLookup:
- * @style:  the XSLT stylesheet
+ * @ctxt:  the XSLT transformation context
  * @name:  the variable name
  * @ns_uri:  the variable namespace URI
  *
@@ -80,32 +350,162 @@
  * Returns the value or NULL if not found
  */
 xmlXPathObjectPtr
-xsltVariableLookup(xsltStylesheetPtr style, const xmlChar *name,
+xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
 		   const xmlChar *ns_uri) {
-    if (style == NULL)
+    xsltStackElemPtr elem;
+
+    if (ctxt == NULL)
 	return(NULL);
 
-    if (style->variablesHash == NULL)
-	return(NULL);
-    if (name == NULL)
+    elem = xsltStackLookup(ctxt, name, ns_uri);
+    if (elem == NULL) {
+	TODO /* searching on other ctxtsheets ? */
 	return(NULL);
-
-    return((xmlXPathObjectPtr)
-	   xmlHashLookup2((xmlHashTablePtr) style->variablesHash,
-	                  name, ns_uri));
+    }
+    if (!elem->computed) {
+#ifdef DEBUG_VARIABLE
+	xsltGenericDebug(xsltGenericDebugContext,
+		         "uncomputed variable %s\n", name);
+#endif
+	    TODO /* Variable value computation needed */
+    }
+error:
+    if (elem->value != NULL)
+	return(xmlXPathObjectCopy(elem->value));
+    return(NULL);
 }
 
 
 /**
  * xsltFreeVariableHashes:
- * @style: an XSLT stylesheet
+ * @ctxt: an XSLT transformation context
  *
  * Free up the memory used by xsltAddVariable/xsltGetVariable mechanism
  */
 void
-xsltFreeVariableHashes(xsltStylesheetPtr style) {
-    if (style->variablesHash != NULL)
-	xmlHashFree((xmlHashTablePtr) style->variablesHash,
-		    (xmlHashDeallocator) xmlXPathFreeObject);
+xsltFreeVariableHashes(xsltTransformContextPtr ctxt) {
+    xsltStackPtr stack;
+    int i;
+
+    if (ctxt == NULL)
+	return;
+
+    stack = ctxt->variablesHash;
+    if (stack == NULL)
+	return;
+
+    for (i = 0; i <= stack->cur;i++) {
+	xsltFreeStackElemList(stack->elems[i]);
+    }
+    xmlFree(stack);
 }
 
+/**
+ * xsltParseStylesheetVariable:
+ * @ctxt:  the XSLT transformation context
+ * @template:  the "variable" name
+ *
+ * parse an XSLT transformation context variable name and record
+ * its value.
+ */
+
+void
+xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
+    xmlChar *name, *ncname, *prefix;
+    xmlChar *select;
+    xmlXPathObjectPtr value = NULL;
+
+    if ((cur == NULL) || (ctxt == NULL))
+	return;
+
+    name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
+    if (name == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	    "xsl:variable : missing name attribute\n");
+	return;
+    }
+
+#ifdef DEBUG_VARIABLE
+    if (ret != NULL)
+	xsltGenericDebug(xsltGenericDebugContext,
+	    "Parsing variable %s\n", name);
+#endif
+
+    select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
+    if (select == NULL) {
+	if (cur->children == NULL)
+	    value = xmlXPathNewCString("");
+	else
+	    value = xmlXPathNewNodeSet(cur->children);
+    } else {
+	if (cur->children != NULL)
+	    xsltGenericError(xsltGenericErrorContext,
+	    "xsl:variable : content shuld be empty since select is present \n");
+    }
+
+    ncname = xmlSplitQName2(name, &prefix);
+
+    if (ncname != NULL) {
+	if (prefix != NULL) {
+	    xmlNsPtr ns;
+
+	    ns = xmlSearchNs(cur->doc, cur, prefix);
+	    if (ns == NULL) {
+		xsltGenericError(xsltGenericErrorContext,
+		    "xsl:variable : no namespace bound to prefix %s\n", prefix);
+	    } else {
+		xsltRegisterVariable(ctxt, ncname, ns->href, select, value);
+	    }
+	    xmlFree(prefix);
+	} else {
+	    xsltRegisterVariable(ctxt, ncname, NULL, select, value);
+	}
+	xmlFree(ncname);
+    } else {
+	xsltRegisterVariable(ctxt, name, NULL, select, value);
+    }
+
+    xmlFree(name);
+    if (select != NULL)
+	xmlFree(select);
+
+}
+
+/**
+ * xsltVariableLookup:
+ * @ctxt:  a void * but the the XSLT transformation context actually
+ * @name:  the variable name
+ * @ns_uri:  the variable namespace URI
+ *
+ * This is the entry point when a varibale is needed by the XPath
+ * interpretor.
+ *
+ * Returns the value or NULL if not found
+ */
+xmlXPathObjectPtr
+xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
+	                const xmlChar *ns_uri) {
+    xsltTransformContextPtr context;
+    xmlXPathObjectPtr ret;
+
+    if ((ctxt == NULL) || (name == NULL))
+	return(NULL);
+
+#ifdef DEBUG_VARIABLE
+    xsltGenericDebug(xsltGenericDebugContext,
+	    "Lookup variable %s\n", name);
+#endif
+    context = (xsltTransformContextPtr) ctxt;
+    ret = xsltVariableLookup(context, name, ns_uri);
+    if (ret == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	    "unregistered variable %s\n", name);
+    }
+#ifdef DEBUG_VARIABLE
+    if (ret != NULL)
+	xsltGenericDebug(xsltGenericDebugContext,
+	    "found variable %s\n", name);
+#endif
+    return(ret);
+}
+
diff --git a/libxslt/variables.h b/libxslt/variables.h
--- a/libxslt/variables.h
+++ b/libxslt/variables.h
@@ -10,20 +10,37 @@
 #define __XML_XSLT_VARIABLES_H__
 
 #include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
 #include "xsltInternals.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-void			xsltFreeVariableHashes	(xsltStylesheetPtr style);
-xmlXPathObjectPtr	xsltVariableLookup	(xsltStylesheetPtr style,
+#define XSLT_REGISTER_VARIABLE_LOOKUP(ctxt)			\
+    xmlXPathRegisterVariableLookup((ctxt)->xpathCtxt,		\
+	       xsltXPathVariableLookup,	(void *)(ctxt)) 
+
+/*
+ * Interfaces for the variable module.
+ */
+
+void		xsltPushStack			(xsltTransformContextPtr ctxt);
+void		xsltPopStack			(xsltTransformContextPtr ctxt);
+void		xsltParseStylesheetVariable	(xsltTransformContextPtr ctxt,
+						 xmlNodePtr cur);
+void			xsltFreeVariableHashes	(xsltTransformContextPtr ctxt);
+xmlXPathObjectPtr	xsltVariableLookup	(xsltTransformContextPtr ctxt,
 						 const xmlChar *name,
 						 const xmlChar *ns_uri);
-int			xsltRegisterVariable	(xsltStylesheetPtr style,
+int			xsltRegisterVariable	(xsltTransformContextPtr ctxt,
 						 const xmlChar *name,
 						 const xmlChar *ns_uri,
+						 const xmlChar *select,
 						 xmlXPathObjectPtr value);
+xmlXPathObjectPtr	xsltXPathVariableLookup	(void *ctxt,
+						 const xmlChar *name,
+						 const xmlChar *ns_uri);
 #ifdef __cplusplus
 }
 #endif
diff --git a/libxslt/xslt.c b/libxslt/xslt.c
--- a/libxslt/xslt.c
+++ b/libxslt/xslt.c
@@ -162,7 +162,6 @@
 	return;
 
     xsltFreeTemplateHashes(sheet);
-    xsltFreeVariableHashes(sheet);
     xsltFreeTemplateList(sheet->templates);
     if (sheet->doc != NULL)
 	xmlFreeDoc(sheet->doc);
diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h
--- a/libxslt/xsltInternals.h
+++ b/libxslt/xsltInternals.h
@@ -12,6 +12,7 @@
 
 #include <libxml/tree.h>
 #include <libxml/hash.h>
+#include <libxml/xpath.h>
 #include <libxslt/xslt.h>
 
 #ifdef __cplusplus
@@ -65,12 +66,6 @@
     void *templatesHash;	/* hash table or wherever compiled templates
 				   informations are stored */
     /*
-     * Variable descriptions
-     */
-    void *variablesHash;	/* hash table or wherever variables
-				   informations are stored */
-
-    /*
      * Output related stuff.
      */
     xmlChar *method;		/* the output method */
@@ -87,6 +82,33 @@
 
 
 /*
+ * The in-memory structure corresponding to an XSLT Transformation
+ */
+typedef enum xsltOutputType {
+    XSLT_OUTPUT_XML = 0,
+    XSLT_OUTPUT_HTML,
+    XSLT_OUTPUT_TEXT
+} xsltOutputType;
+
+typedef struct _xsltTransformContext xsltTransformContext;
+typedef xsltTransformContext *xsltTransformContextPtr;
+struct _xsltTransformContext {
+    xsltStylesheetPtr style;		/* the stylesheet used */
+    xsltOutputType type;		/* the type of output */
+
+    xmlDocPtr doc;			/* the current doc */
+    xmlNodePtr node;			/* the current node */
+    xmlNodeSetPtr nodeList;		/* the current node list */
+
+    xmlDocPtr output;			/* the resulting document */
+    xmlNodePtr insert;			/* the insertion node */
+
+    xmlXPathContextPtr xpathCtxt;	/* the XPath context */
+    void *variablesHash;		/* hash table or wherever variables
+				   	   informations are stored */
+};
+
+/*
  * Functions associated to the internal types
  */
 xsltStylesheetPtr	xsltParseStylesheetFile	(const xmlChar* filename);
diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h
--- a/libxslt/xsltutils.h
+++ b/libxslt/xsltutils.h
@@ -24,6 +24,10 @@
 void xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs);
 xmlAttrPtr xmlSetNsProp	(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
 			 const xmlChar *value);
+/*********
+void xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
+	             xmlXPathVariableLookupFunc f, void *data)
+ *********/
 
 /*
  * Useful macros