xref: /reactos/dll/3rdparty/libxslt/pattern.c (revision 40462c92)
1 /*
2  * pattern.c: Implemetation of the template match compilation and lookup
3  *
4  * Reference:
5  *   http://www.w3.org/TR/1999/REC-xslt-19991116
6  *
7  * See Copyright for the status of this software.
8  *
9  * daniel@veillard.com
10  */
11 
12 /*
13  * TODO: handle pathological cases like *[*[@a="b"]]
14  * TODO: detect [number] at compilation, optimize accordingly
15  */
16 
17 #include "precomp.h"
18 
19 #ifdef WITH_XSLT_DEBUG
20 #define WITH_XSLT_DEBUG_PATTERN
21 #endif
22 
23 /*
24  * Types are private:
25  */
26 
27 typedef enum {
28     XSLT_OP_END=0,
29     XSLT_OP_ROOT,
30     XSLT_OP_ELEM,
31     XSLT_OP_ATTR,
32     XSLT_OP_PARENT,
33     XSLT_OP_ANCESTOR,
34     XSLT_OP_ID,
35     XSLT_OP_KEY,
36     XSLT_OP_NS,
37     XSLT_OP_ALL,
38     XSLT_OP_PI,
39     XSLT_OP_COMMENT,
40     XSLT_OP_TEXT,
41     XSLT_OP_NODE,
42     XSLT_OP_PREDICATE
43 } xsltOp;
44 
45 typedef enum {
46     AXIS_CHILD=1,
47     AXIS_ATTRIBUTE
48 } xsltAxis;
49 
50 typedef struct _xsltStepState xsltStepState;
51 typedef xsltStepState *xsltStepStatePtr;
52 struct _xsltStepState {
53     int step;
54     xmlNodePtr node;
55 };
56 
57 typedef struct _xsltStepStates xsltStepStates;
58 typedef xsltStepStates *xsltStepStatesPtr;
59 struct _xsltStepStates {
60     int nbstates;
61     int maxstates;
62     xsltStepStatePtr states;
63 };
64 
65 typedef struct _xsltStepOp xsltStepOp;
66 typedef xsltStepOp *xsltStepOpPtr;
67 struct _xsltStepOp {
68     xsltOp op;
69     xmlChar *value;
70     xmlChar *value2;
71     xmlChar *value3;
72     xmlXPathCompExprPtr comp;
73     /*
74      * Optimisations for count
75      */
76     int        previousExtra;
77     int        indexExtra;
78     int        lenExtra;
79 };
80 
81 struct _xsltCompMatch {
82     struct _xsltCompMatch *next; /* siblings in the name hash */
83     float priority;              /* the priority */
84     const xmlChar *pattern;       /* the pattern */
85     const xmlChar *mode;         /* the mode */
86     const xmlChar *modeURI;      /* the mode URI */
87     xsltTemplatePtr template;    /* the associated template */
88     xmlNodePtr node;             /* the containing element */
89 
90     int direct;
91     /* TODO fix the statically allocated size steps[] */
92     int nbStep;
93     int maxStep;
94     xmlNsPtr *nsList;		/* the namespaces in scope */
95     int nsNr;			/* the number of namespaces in scope */
96     xsltStepOpPtr steps;        /* ops for computation */
97 };
98 
99 typedef struct _xsltParserContext xsltParserContext;
100 typedef xsltParserContext *xsltParserContextPtr;
101 struct _xsltParserContext {
102     xsltStylesheetPtr style;		/* the stylesheet */
103     xsltTransformContextPtr ctxt;	/* the transformation or NULL */
104     const xmlChar *cur;			/* the current char being parsed */
105     const xmlChar *base;		/* the full expression */
106     xmlDocPtr      doc;			/* the source document */
107     xmlNodePtr    elem;			/* the source element */
108     int error;				/* error code */
109     xsltCompMatchPtr comp;		/* the result */
110 };
111 
112 /************************************************************************
113  *									*
114  *			Type functions					*
115  *									*
116  ************************************************************************/
117 
118 /**
119  * xsltNewCompMatch:
120  *
121  * Create a new XSLT CompMatch
122  *
123  * Returns the newly allocated xsltCompMatchPtr or NULL in case of error
124  */
125 static xsltCompMatchPtr
126 xsltNewCompMatch(void) {
127     xsltCompMatchPtr cur;
128 
129     cur = (xsltCompMatchPtr) xmlMalloc(sizeof(xsltCompMatch));
130     if (cur == NULL) {
131 	xsltTransformError(NULL, NULL, NULL,
132 		"xsltNewCompMatch : out of memory error\n");
133 	return(NULL);
134     }
135     memset(cur, 0, sizeof(xsltCompMatch));
136     cur->maxStep = 10;
137     cur->nbStep = 0;
138     cur-> steps = (xsltStepOpPtr) xmlMalloc(sizeof(xsltStepOp) *
139                                             cur->maxStep);
140     if (cur->steps == NULL) {
141 	xsltTransformError(NULL, NULL, NULL,
142 		"xsltNewCompMatch : out of memory error\n");
143 	xmlFree(cur);
144 	return(NULL);
145     }
146     cur->nsNr = 0;
147     cur->nsList = NULL;
148     cur->direct = 0;
149     return(cur);
150 }
151 
152 /**
153  * xsltFreeCompMatch:
154  * @comp:  an XSLT comp
155  *
156  * Free up the memory allocated by @comp
157  */
158 static void
159 xsltFreeCompMatch(xsltCompMatchPtr comp) {
160     xsltStepOpPtr op;
161     int i;
162 
163     if (comp == NULL)
164 	return;
165     if (comp->pattern != NULL)
166 	xmlFree((xmlChar *)comp->pattern);
167     if (comp->nsList != NULL)
168 	xmlFree(comp->nsList);
169     for (i = 0;i < comp->nbStep;i++) {
170 	op = &comp->steps[i];
171 	if (op->value != NULL)
172 	    xmlFree(op->value);
173 	if (op->value2 != NULL)
174 	    xmlFree(op->value2);
175 	if (op->value3 != NULL)
176 	    xmlFree(op->value3);
177 	if (op->comp != NULL)
178 	    xmlXPathFreeCompExpr(op->comp);
179     }
180     xmlFree(comp->steps);
181     memset(comp, -1, sizeof(xsltCompMatch));
182     xmlFree(comp);
183 }
184 
185 /**
186  * xsltFreeCompMatchList:
187  * @comp:  an XSLT comp list
188  *
189  * Free up the memory allocated by all the elements of @comp
190  */
191 void
192 xsltFreeCompMatchList(xsltCompMatchPtr comp) {
193     xsltCompMatchPtr cur;
194 
195     while (comp != NULL) {
196 	cur = comp;
197 	comp = comp->next;
198 	xsltFreeCompMatch(cur);
199     }
200 }
201 
202 static void
203 xsltFreeCompMatchListEntry(void *payload,
204                            const xmlChar *name ATTRIBUTE_UNUSED) {
205     xsltFreeCompMatchList((xsltCompMatchPtr) payload);
206 }
207 
208 /**
209  * xsltNormalizeCompSteps:
210  * @payload: pointer to template hash table entry
211  * @data: pointer to the stylesheet
212  * @name: template match name
213  *
214  * This is a hashtable scanner function to normalize the compiled
215  * steps of an imported stylesheet.
216  */
217 void xsltNormalizeCompSteps(void *payload,
218         void *data, const xmlChar *name ATTRIBUTE_UNUSED) {
219     xsltCompMatchPtr comp = payload;
220     xsltStylesheetPtr style = data;
221     int ix;
222 
223     for (ix = 0; ix < comp->nbStep; ix++) {
224         comp->steps[ix].previousExtra += style->extrasNr;
225         comp->steps[ix].indexExtra += style->extrasNr;
226         comp->steps[ix].lenExtra += style->extrasNr;
227     }
228 }
229 
230 /**
231  * xsltNewParserContext:
232  * @style:  the stylesheet
233  * @ctxt:  the transformation context, if done at run-time
234  *
235  * Create a new XSLT ParserContext
236  *
237  * Returns the newly allocated xsltParserContextPtr or NULL in case of error
238  */
239 static xsltParserContextPtr
240 xsltNewParserContext(xsltStylesheetPtr style, xsltTransformContextPtr ctxt) {
241     xsltParserContextPtr cur;
242 
243     cur = (xsltParserContextPtr) xmlMalloc(sizeof(xsltParserContext));
244     if (cur == NULL) {
245 	xsltTransformError(NULL, NULL, NULL,
246 		"xsltNewParserContext : malloc failed\n");
247 	return(NULL);
248     }
249     memset(cur, 0, sizeof(xsltParserContext));
250     cur->style = style;
251     cur->ctxt = ctxt;
252     return(cur);
253 }
254 
255 /**
256  * xsltFreeParserContext:
257  * @ctxt:  an XSLT parser context
258  *
259  * Free up the memory allocated by @ctxt
260  */
261 static void
262 xsltFreeParserContext(xsltParserContextPtr ctxt) {
263     if (ctxt == NULL)
264 	return;
265     memset(ctxt, -1, sizeof(xsltParserContext));
266     xmlFree(ctxt);
267 }
268 
269 /**
270  * xsltCompMatchAdd:
271  * @comp:  the compiled match expression
272  * @op:  an op
273  * @value:  the first value
274  * @value2:  the second value
275  * @novar:  flag to set XML_XPATH_NOVAR
276  *
277  * Add an step to an XSLT Compiled Match
278  *
279  * Returns -1 in case of failure, 0 otherwise.
280  */
281 static int
282 xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp,
283                  xsltOp op, xmlChar * value, xmlChar * value2, int novar)
284 {
285     if (comp->nbStep >= comp->maxStep) {
286         xsltStepOpPtr tmp;
287 
288 	tmp = (xsltStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
289 	                                 sizeof(xsltStepOp));
290 	if (tmp == NULL) {
291 	    xsltGenericError(xsltGenericErrorContext,
292 	     "xsltCompMatchAdd: memory re-allocation failure.\n");
293 	    if (ctxt->style != NULL)
294 		ctxt->style->errors++;
295 	    if (value)
296 	        xmlFree(value);
297 	    if (value2)
298 	        xmlFree(value2);
299 	    return (-1);
300 	}
301         comp->maxStep *= 2;
302 	comp->steps = tmp;
303     }
304     comp->steps[comp->nbStep].op = op;
305     comp->steps[comp->nbStep].value = value;
306     comp->steps[comp->nbStep].value2 = value2;
307     comp->steps[comp->nbStep].value3 = NULL;
308     comp->steps[comp->nbStep].comp = NULL;
309     if (ctxt->ctxt != NULL) {
310 	comp->steps[comp->nbStep].previousExtra =
311 	    xsltAllocateExtraCtxt(ctxt->ctxt);
312 	comp->steps[comp->nbStep].indexExtra =
313 	    xsltAllocateExtraCtxt(ctxt->ctxt);
314 	comp->steps[comp->nbStep].lenExtra =
315 	    xsltAllocateExtraCtxt(ctxt->ctxt);
316     } else {
317 	comp->steps[comp->nbStep].previousExtra =
318 	    xsltAllocateExtra(ctxt->style);
319 	comp->steps[comp->nbStep].indexExtra =
320 	    xsltAllocateExtra(ctxt->style);
321 	comp->steps[comp->nbStep].lenExtra =
322 	    xsltAllocateExtra(ctxt->style);
323     }
324     if (op == XSLT_OP_PREDICATE) {
325         int flags = 0;
326 
327 #ifdef XML_XPATH_NOVAR
328 	if (novar != 0)
329 	    flags = XML_XPATH_NOVAR;
330 #endif
331 	comp->steps[comp->nbStep].comp = xsltXPathCompileFlags(ctxt->style,
332                 value, flags);
333 	if (comp->steps[comp->nbStep].comp == NULL) {
334 	    xsltTransformError(NULL, ctxt->style, ctxt->elem,
335 		    "Failed to compile predicate\n");
336 	    if (ctxt->style != NULL)
337 		ctxt->style->errors++;
338 	}
339     }
340     comp->nbStep++;
341     return (0);
342 }
343 
344 /**
345  * xsltSwapTopCompMatch:
346  * @comp:  the compiled match expression
347  *
348  * reverse the two top steps.
349  */
350 static void
351 xsltSwapTopCompMatch(xsltCompMatchPtr comp) {
352     int i;
353     int j = comp->nbStep - 1;
354 
355     if (j > 0) {
356 	register xmlChar *tmp;
357 	register xsltOp op;
358 	register xmlXPathCompExprPtr expr;
359 	register int t;
360 	i = j - 1;
361 	tmp = comp->steps[i].value;
362 	comp->steps[i].value = comp->steps[j].value;
363 	comp->steps[j].value = tmp;
364 	tmp = comp->steps[i].value2;
365 	comp->steps[i].value2 = comp->steps[j].value2;
366 	comp->steps[j].value2 = tmp;
367 	tmp = comp->steps[i].value3;
368 	comp->steps[i].value3 = comp->steps[j].value3;
369 	comp->steps[j].value3 = tmp;
370 	op = comp->steps[i].op;
371 	comp->steps[i].op = comp->steps[j].op;
372 	comp->steps[j].op = op;
373 	expr = comp->steps[i].comp;
374 	comp->steps[i].comp = comp->steps[j].comp;
375 	comp->steps[j].comp = expr;
376 	t = comp->steps[i].previousExtra;
377 	comp->steps[i].previousExtra = comp->steps[j].previousExtra;
378 	comp->steps[j].previousExtra = t;
379 	t = comp->steps[i].indexExtra;
380 	comp->steps[i].indexExtra = comp->steps[j].indexExtra;
381 	comp->steps[j].indexExtra = t;
382 	t = comp->steps[i].lenExtra;
383 	comp->steps[i].lenExtra = comp->steps[j].lenExtra;
384 	comp->steps[j].lenExtra = t;
385     }
386 }
387 
388 /**
389  * xsltReverseCompMatch:
390  * @ctxt: the parser context
391  * @comp:  the compiled match expression
392  *
393  * reverse all the stack of expressions
394  */
395 static void
396 xsltReverseCompMatch(xsltParserContextPtr ctxt, xsltCompMatchPtr comp) {
397     int i = 0;
398     int j = comp->nbStep - 1;
399 
400     while (j > i) {
401 	register xmlChar *tmp;
402 	register xsltOp op;
403 	register xmlXPathCompExprPtr expr;
404 	register int t;
405 
406 	tmp = comp->steps[i].value;
407 	comp->steps[i].value = comp->steps[j].value;
408 	comp->steps[j].value = tmp;
409 	tmp = comp->steps[i].value2;
410 	comp->steps[i].value2 = comp->steps[j].value2;
411 	comp->steps[j].value2 = tmp;
412 	tmp = comp->steps[i].value3;
413 	comp->steps[i].value3 = comp->steps[j].value3;
414 	comp->steps[j].value3 = tmp;
415 	op = comp->steps[i].op;
416 	comp->steps[i].op = comp->steps[j].op;
417 	comp->steps[j].op = op;
418 	expr = comp->steps[i].comp;
419 	comp->steps[i].comp = comp->steps[j].comp;
420 	comp->steps[j].comp = expr;
421 	t = comp->steps[i].previousExtra;
422 	comp->steps[i].previousExtra = comp->steps[j].previousExtra;
423 	comp->steps[j].previousExtra = t;
424 	t = comp->steps[i].indexExtra;
425 	comp->steps[i].indexExtra = comp->steps[j].indexExtra;
426 	comp->steps[j].indexExtra = t;
427 	t = comp->steps[i].lenExtra;
428 	comp->steps[i].lenExtra = comp->steps[j].lenExtra;
429 	comp->steps[j].lenExtra = t;
430 	j--;
431 	i++;
432     }
433     xsltCompMatchAdd(ctxt, comp, XSLT_OP_END, NULL, NULL, 0);
434 
435     /*
436      * Detect consecutive XSLT_OP_PREDICATE and predicates on ops which
437      * haven't been optimized yet indicating a direct matching should be done.
438      */
439     for (i = 0;i < comp->nbStep - 1;i++) {
440         xsltOp op = comp->steps[i].op;
441 
442         if ((op != XSLT_OP_ELEM) &&
443             (op != XSLT_OP_ALL) &&
444 	    (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) {
445 
446 	    comp->direct = 1;
447 	    if (comp->pattern[0] != '/') {
448 		xmlChar *query;
449 
450 		query = xmlStrdup((const xmlChar *)"//");
451 		query = xmlStrcat(query, comp->pattern);
452 
453 		xmlFree((xmlChar *) comp->pattern);
454 		comp->pattern = query;
455 	    }
456 	    break;
457 	}
458     }
459 }
460 
461 /************************************************************************
462  *									*
463  *		The interpreter for the precompiled patterns		*
464  *									*
465  ************************************************************************/
466 
467 static int
468 xsltPatPushState(xsltTransformContextPtr ctxt, xsltStepStates *states,
469                  int step, xmlNodePtr node) {
470     if ((states->states == NULL) || (states->maxstates <= 0)) {
471         states->maxstates = 4;
472 	states->nbstates = 0;
473 	states->states = xmlMalloc(4 * sizeof(xsltStepState));
474     }
475     else if (states->maxstates <= states->nbstates) {
476         xsltStepState *tmp;
477 
478 	tmp = (xsltStepStatePtr) xmlRealloc(states->states,
479 			       2 * states->maxstates * sizeof(xsltStepState));
480 	if (tmp == NULL) {
481 	    xsltGenericError(xsltGenericErrorContext,
482 	     "xsltPatPushState: memory re-allocation failure.\n");
483 	    ctxt->state = XSLT_STATE_STOPPED;
484 	    return(-1);
485 	}
486 	states->states = tmp;
487 	states->maxstates *= 2;
488     }
489     states->states[states->nbstates].step = step;
490     states->states[states->nbstates++].node = node;
491 #if 0
492     fprintf(stderr, "Push: %d, %s\n", step, node->name);
493 #endif
494     return(0);
495 }
496 
497 static void
498 xmlXPathFreeObjectWrapper(void *obj) {
499     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
500 }
501 
502 /**
503  * xsltTestCompMatchDirect:
504  * @ctxt:  a XSLT process context
505  * @comp: the precompiled pattern
506  * @node: a node
507  * @nsList: the namespaces in scope
508  * @nsNr: the number of namespaces in scope
509  *
510  * Test whether the node matches the pattern, do a direct evalutation
511  * and not a step by step evaluation.
512  *
513  * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
514  */
515 static int
516 xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
517 	                xmlNodePtr node, xmlNsPtr *nsList, int nsNr) {
518     xsltStepOpPtr sel = NULL;
519     xmlDocPtr prevdoc;
520     xmlDocPtr doc;
521     xmlXPathObjectPtr list;
522     int ix, j;
523     int nocache = 0;
524     int isRVT;
525 
526     doc = node->doc;
527     if (XSLT_IS_RES_TREE_FRAG(doc))
528 	isRVT = 1;
529     else
530 	isRVT = 0;
531     sel = &comp->steps[0]; /* store extra in first step arbitrarily */
532 
533     prevdoc = (xmlDocPtr)
534 	XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
535     ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
536     list = (xmlXPathObjectPtr)
537 	XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra);
538 
539     if ((list == NULL) || (prevdoc != doc)) {
540 	xmlXPathObjectPtr newlist;
541 	xmlNodePtr parent = node->parent;
542 	xmlDocPtr olddoc;
543 	xmlNodePtr oldnode;
544 	int oldNsNr, oldContextSize, oldProximityPosition;
545 	xmlNsPtr *oldNamespaces;
546 
547 	oldnode = ctxt->xpathCtxt->node;
548 	olddoc = ctxt->xpathCtxt->doc;
549 	oldNsNr = ctxt->xpathCtxt->nsNr;
550 	oldNamespaces = ctxt->xpathCtxt->namespaces;
551 	oldContextSize = ctxt->xpathCtxt->contextSize;
552 	oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
553 	ctxt->xpathCtxt->node = node;
554 	ctxt->xpathCtxt->doc = doc;
555 	ctxt->xpathCtxt->namespaces = nsList;
556 	ctxt->xpathCtxt->nsNr = nsNr;
557 	newlist = xmlXPathEval(comp->pattern, ctxt->xpathCtxt);
558 	ctxt->xpathCtxt->node = oldnode;
559 	ctxt->xpathCtxt->doc = olddoc;
560 	ctxt->xpathCtxt->namespaces = oldNamespaces;
561 	ctxt->xpathCtxt->nsNr = oldNsNr;
562 	ctxt->xpathCtxt->contextSize = oldContextSize;
563 	ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
564 	if (newlist == NULL)
565 	    return(-1);
566 	if (newlist->type != XPATH_NODESET) {
567 	    xmlXPathFreeObject(newlist);
568 	    return(-1);
569 	}
570 	ix = 0;
571 
572 	if ((parent == NULL) || (node->doc == NULL) || isRVT)
573 	    nocache = 1;
574 
575 	if (nocache == 0) {
576 	    if (list != NULL)
577 		xmlXPathFreeObject(list);
578 	    list = newlist;
579 
580 	    XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) =
581 		(void *) list;
582 	    XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
583 		(void *) doc;
584 	    XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
585 		0;
586 	    XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) =
587 		xmlXPathFreeObjectWrapper;
588 	} else
589 	    list = newlist;
590     }
591     if ((list->nodesetval == NULL) ||
592 	(list->nodesetval->nodeNr <= 0)) {
593 	if (nocache == 1)
594 	    xmlXPathFreeObject(list);
595 	return(0);
596     }
597     /* TODO: store the index and use it for the scan */
598     if (ix == 0) {
599 	for (j = 0;j < list->nodesetval->nodeNr;j++) {
600 	    if (list->nodesetval->nodeTab[j] == node) {
601 		if (nocache == 1)
602 		    xmlXPathFreeObject(list);
603 		return(1);
604 	    }
605 	}
606     } else {
607     }
608     if (nocache == 1)
609 	xmlXPathFreeObject(list);
610     return(0);
611 }
612 
613 /**
614  * xsltTestPredicateMatch:
615  * @ctxt: a XSLT process context
616  * @comp: the precompiled pattern
617  * @node: a node
618  * @step: the predicate step
619  * @sel:  the previous step
620  *
621  * Test whether the node matches the predicate
622  *
623  * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
624  */
625 static int
626 xsltTestPredicateMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
627                        xmlNodePtr node, xsltStepOpPtr step,
628                        xsltStepOpPtr sel) {
629     xmlNodePtr oldNode;
630     xmlDocPtr doc;
631     int oldCS, oldCP;
632     int pos = 0, len = 0;
633     int isRVT;
634     int match;
635 
636     if (step->value == NULL)
637         return(0);
638     if (step->comp == NULL)
639         return(0);
640 
641     doc = node->doc;
642     if (XSLT_IS_RES_TREE_FRAG(doc))
643         isRVT = 1;
644     else
645         isRVT = 0;
646 
647     /*
648      * Recompute contextSize and proximityPosition.
649      *
650      * TODO: Make this work for additional ops. Currently, only XSLT_OP_ELEM
651      * and XSLT_OP_ALL are supported.
652      */
653     oldCS = ctxt->xpathCtxt->contextSize;
654     oldCP = ctxt->xpathCtxt->proximityPosition;
655     if ((sel != NULL) &&
656         (sel->op == XSLT_OP_ELEM) &&
657         (sel->value != NULL) &&
658         (node->type == XML_ELEMENT_NODE) &&
659         (node->parent != NULL)) {
660         xmlNodePtr previous;
661         int nocache = 0;
662 
663         previous = (xmlNodePtr)
664             XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
665         if ((previous != NULL) &&
666             (previous->parent == node->parent)) {
667             /*
668              * just walk back to adjust the index
669              */
670             int indx = 0;
671             xmlNodePtr sibling = node;
672 
673             while (sibling != NULL) {
674                 if (sibling == previous)
675                     break;
676                 if ((sibling->type == XML_ELEMENT_NODE) &&
677                     (previous->name != NULL) &&
678                     (sibling->name != NULL) &&
679                     (previous->name[0] == sibling->name[0]) &&
680                     (xmlStrEqual(previous->name, sibling->name)))
681                 {
682                     if ((sel->value2 == NULL) ||
683                         ((sibling->ns != NULL) &&
684                          (xmlStrEqual(sel->value2, sibling->ns->href))))
685                         indx++;
686                 }
687                 sibling = sibling->prev;
688             }
689             if (sibling == NULL) {
690                 /* hum going backward in document order ... */
691                 indx = 0;
692                 sibling = node;
693                 while (sibling != NULL) {
694                     if (sibling == previous)
695                         break;
696                     if ((sibling->type == XML_ELEMENT_NODE) &&
697                         (previous->name != NULL) &&
698                         (sibling->name != NULL) &&
699                         (previous->name[0] == sibling->name[0]) &&
700                         (xmlStrEqual(previous->name, sibling->name)))
701                     {
702                         if ((sel->value2 == NULL) ||
703                             ((sibling->ns != NULL) &&
704                             (xmlStrEqual(sel->value2,
705                             sibling->ns->href))))
706                         {
707                             indx--;
708                         }
709                     }
710                     sibling = sibling->next;
711                 }
712             }
713             if (sibling != NULL) {
714                 pos = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) + indx;
715                 /*
716                  * If the node is in a Value Tree we need to
717                  * save len, but cannot cache the node!
718                  * (bugs 153137 and 158840)
719                  */
720                 if (node->doc != NULL) {
721                     len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival);
722                     if (!isRVT) {
723                         XSLT_RUNTIME_EXTRA(ctxt,
724                             sel->previousExtra, ptr) = node;
725                         XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
726                     }
727                 }
728             } else
729                 pos = 0;
730         } else {
731             /*
732              * recompute the index
733              */
734             xmlNodePtr parent = node->parent;
735             xmlNodePtr siblings = NULL;
736 
737             if (parent) siblings = parent->children;
738 
739             while (siblings != NULL) {
740                 if (siblings->type == XML_ELEMENT_NODE) {
741                     if (siblings == node) {
742                         len++;
743                         pos = len;
744                     } else if ((node->name != NULL) &&
745                                (siblings->name != NULL) &&
746                         (node->name[0] == siblings->name[0]) &&
747                         (xmlStrEqual(node->name, siblings->name))) {
748                         if ((sel->value2 == NULL) ||
749                             ((siblings->ns != NULL) &&
750                              (xmlStrEqual(sel->value2, siblings->ns->href))))
751                             len++;
752                     }
753                 }
754                 siblings = siblings->next;
755             }
756             if ((parent == NULL) || (node->doc == NULL))
757                 nocache = 1;
758             else {
759                 while (parent->parent != NULL)
760                     parent = parent->parent;
761                 if (((parent->type != XML_DOCUMENT_NODE) &&
762                      (parent->type != XML_HTML_DOCUMENT_NODE)) ||
763                      (parent != (xmlNodePtr) node->doc))
764                     nocache = 1;
765             }
766         }
767         if (pos != 0) {
768             ctxt->xpathCtxt->contextSize = len;
769             ctxt->xpathCtxt->proximityPosition = pos;
770             /*
771              * If the node is in a Value Tree we cannot
772              * cache it !
773              */
774             if ((!isRVT) && (node->doc != NULL) &&
775                 (nocache == 0)) {
776                 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
777                 XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
778                 XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len;
779             }
780         }
781     } else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) &&
782                (node->type == XML_ELEMENT_NODE)) {
783         xmlNodePtr previous;
784         int nocache = 0;
785 
786         previous = (xmlNodePtr)
787             XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
788         if ((previous != NULL) &&
789             (previous->parent == node->parent)) {
790             /*
791              * just walk back to adjust the index
792              */
793             int indx = 0;
794             xmlNodePtr sibling = node;
795 
796             while (sibling != NULL) {
797                 if (sibling == previous)
798                     break;
799                 if (sibling->type == XML_ELEMENT_NODE)
800                     indx++;
801                 sibling = sibling->prev;
802             }
803             if (sibling == NULL) {
804                 /* hum going backward in document order ... */
805                 indx = 0;
806                 sibling = node;
807                 while (sibling != NULL) {
808                     if (sibling == previous)
809                         break;
810                     if (sibling->type == XML_ELEMENT_NODE)
811                         indx--;
812                     sibling = sibling->next;
813                 }
814             }
815             if (sibling != NULL) {
816                 pos = XSLT_RUNTIME_EXTRA(ctxt,
817                     sel->indexExtra, ival) + indx;
818                 /*
819                  * If the node is in a Value Tree we cannot
820                  * cache it !
821                  */
822                 if ((node->doc != NULL) && !isRVT) {
823                     len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival);
824                     XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
825                     XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
826                 }
827             } else
828                 pos = 0;
829         } else {
830             /*
831              * recompute the index
832              */
833             xmlNodePtr parent = node->parent;
834             xmlNodePtr siblings = NULL;
835 
836             if (parent) siblings = parent->children;
837 
838             while (siblings != NULL) {
839                 if (siblings->type == XML_ELEMENT_NODE) {
840                     len++;
841                     if (siblings == node) {
842                         pos = len;
843                     }
844                 }
845                 siblings = siblings->next;
846             }
847             if ((parent == NULL) || (node->doc == NULL))
848                 nocache = 1;
849             else {
850                 while (parent->parent != NULL)
851                     parent = parent->parent;
852                 if (((parent->type != XML_DOCUMENT_NODE) &&
853                      (parent->type != XML_HTML_DOCUMENT_NODE)) ||
854                      (parent != (xmlNodePtr) node->doc))
855                     nocache = 1;
856             }
857         }
858         if (pos != 0) {
859             ctxt->xpathCtxt->contextSize = len;
860             ctxt->xpathCtxt->proximityPosition = pos;
861             /*
862              * If the node is in a Value Tree we cannot
863              * cache it !
864              */
865             if ((node->doc != NULL) && (nocache == 0) && !isRVT) {
866                 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
867                 XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
868                 XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len;
869             }
870         }
871     }
872 
873     oldNode = ctxt->node;
874     ctxt->node = node;
875 
876     match = xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList, comp->nsNr);
877 
878     if (pos != 0) {
879         ctxt->xpathCtxt->contextSize = oldCS;
880         ctxt->xpathCtxt->proximityPosition = oldCP;
881     }
882     ctxt->node = oldNode;
883 
884     return match;
885 }
886 
887 /**
888  * xsltTestCompMatch:
889  * @ctxt:  a XSLT process context
890  * @comp: the precompiled pattern
891  * @node: a node
892  * @mode:  the mode name or NULL
893  * @modeURI:  the mode URI or NULL
894  *
895  * Test whether the node matches the pattern
896  *
897  * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
898  */
899 static int
900 xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
901 	          xmlNodePtr matchNode, const xmlChar *mode,
902 		  const xmlChar *modeURI) {
903     int i;
904     int found = 0;
905     xmlNodePtr node = matchNode;
906     xmlNodePtr oldInst;
907     xsltStepOpPtr step, sel = NULL;
908     xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */
909 
910     if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) {
911 	xsltTransformError(ctxt, NULL, node,
912 		"xsltTestCompMatch: null arg\n");
913         return(-1);
914     }
915     if (mode != NULL) {
916 	if (comp->mode == NULL)
917 	    return(0);
918 	/*
919 	 * both mode strings must be interned on the stylesheet dictionary
920 	 */
921 	if (comp->mode != mode)
922 	    return(0);
923     } else {
924 	if (comp->mode != NULL)
925 	    return(0);
926     }
927     if (modeURI != NULL) {
928 	if (comp->modeURI == NULL)
929 	    return(0);
930 	/*
931 	 * both modeURI strings must be interned on the stylesheet dictionary
932 	 */
933 	if (comp->modeURI != modeURI)
934 	    return(0);
935     } else {
936 	if (comp->modeURI != NULL)
937 	    return(0);
938     }
939 
940     /* Some XPath functions rely on inst being set correctly. */
941     oldInst = ctxt->inst;
942     ctxt->inst = comp->node;
943 
944     i = 0;
945 restart:
946     for (;i < comp->nbStep;i++) {
947 	step = &comp->steps[i];
948 	if (step->op != XSLT_OP_PREDICATE)
949 	    sel = step;
950 	switch (step->op) {
951             case XSLT_OP_END:
952 		goto found;
953             case XSLT_OP_ROOT:
954 		if ((node->type == XML_DOCUMENT_NODE) ||
955 #ifdef LIBXML_DOCB_ENABLED
956 		    (node->type == XML_DOCB_DOCUMENT_NODE) ||
957 #endif
958 		    (node->type == XML_HTML_DOCUMENT_NODE))
959 		    continue;
960 		if ((node->type == XML_ELEMENT_NODE) && (node->name[0] == ' '))
961 		    continue;
962 		goto rollback;
963             case XSLT_OP_ELEM:
964 		if (node->type != XML_ELEMENT_NODE)
965 		    goto rollback;
966 		if (step->value == NULL)
967 		    continue;
968 		if (step->value[0] != node->name[0])
969 		    goto rollback;
970 		if (!xmlStrEqual(step->value, node->name))
971 		    goto rollback;
972 
973 		/* Namespace test */
974 		if (node->ns == NULL) {
975 		    if (step->value2 != NULL)
976 			goto rollback;
977 		} else if (node->ns->href != NULL) {
978 		    if (step->value2 == NULL)
979 			goto rollback;
980 		    if (!xmlStrEqual(step->value2, node->ns->href))
981 			goto rollback;
982 		}
983 		continue;
984             case XSLT_OP_ATTR:
985 		if (node->type != XML_ATTRIBUTE_NODE)
986 		    goto rollback;
987 		if (step->value != NULL) {
988 		    if (step->value[0] != node->name[0])
989 			goto rollback;
990 		    if (!xmlStrEqual(step->value, node->name))
991 			goto rollback;
992 		}
993 		/* Namespace test */
994 		if (node->ns == NULL) {
995 		    if (step->value2 != NULL)
996 			goto rollback;
997 		} else if (step->value2 != NULL) {
998 		    if (!xmlStrEqual(step->value2, node->ns->href))
999 			goto rollback;
1000 		}
1001 		continue;
1002             case XSLT_OP_PARENT:
1003 		if ((node->type == XML_DOCUMENT_NODE) ||
1004 		    (node->type == XML_HTML_DOCUMENT_NODE) ||
1005 #ifdef LIBXML_DOCB_ENABLED
1006 		    (node->type == XML_DOCB_DOCUMENT_NODE) ||
1007 #endif
1008 		    (node->type == XML_NAMESPACE_DECL))
1009 		    goto rollback;
1010 		node = node->parent;
1011 		if (node == NULL)
1012 		    goto rollback;
1013 		if (step->value == NULL)
1014 		    continue;
1015 		if (step->value[0] != node->name[0])
1016 		    goto rollback;
1017 		if (!xmlStrEqual(step->value, node->name))
1018 		    goto rollback;
1019 		/* Namespace test */
1020 		if (node->ns == NULL) {
1021 		    if (step->value2 != NULL)
1022 			goto rollback;
1023 		} else if (node->ns->href != NULL) {
1024 		    if (step->value2 == NULL)
1025 			goto rollback;
1026 		    if (!xmlStrEqual(step->value2, node->ns->href))
1027 			goto rollback;
1028 		}
1029 		continue;
1030             case XSLT_OP_ANCESTOR:
1031 		/* TODO: implement coalescing of ANCESTOR/NODE ops */
1032 		if (step->value == NULL) {
1033 		    step = &comp->steps[i+1];
1034 		    if (step->op == XSLT_OP_ROOT)
1035 			goto found;
1036 		    /* added NS, ID and KEY as a result of bug 168208 */
1037 		    if ((step->op != XSLT_OP_ELEM) &&
1038 			(step->op != XSLT_OP_ALL) &&
1039 			(step->op != XSLT_OP_NS) &&
1040 			(step->op != XSLT_OP_ID) &&
1041 			(step->op != XSLT_OP_KEY))
1042 			goto rollback;
1043 		}
1044 		if (node == NULL)
1045 		    goto rollback;
1046 		if ((node->type == XML_DOCUMENT_NODE) ||
1047 		    (node->type == XML_HTML_DOCUMENT_NODE) ||
1048 #ifdef LIBXML_DOCB_ENABLED
1049 		    (node->type == XML_DOCB_DOCUMENT_NODE) ||
1050 #endif
1051 		    (node->type == XML_NAMESPACE_DECL))
1052 		    goto rollback;
1053 		node = node->parent;
1054 		if ((step->op != XSLT_OP_ELEM) && step->op != XSLT_OP_ALL) {
1055 		    xsltPatPushState(ctxt, &states, i, node);
1056 		    continue;
1057 		}
1058 		i++;
1059 		if (step->value == NULL) {
1060 		    xsltPatPushState(ctxt, &states, i - 1, node);
1061 		    continue;
1062 		}
1063 		while (node != NULL) {
1064 		    if ((node->type == XML_ELEMENT_NODE) &&
1065 			(step->value[0] == node->name[0]) &&
1066 			(xmlStrEqual(step->value, node->name))) {
1067 			/* Namespace test */
1068 			if (node->ns == NULL) {
1069 			    if (step->value2 == NULL)
1070 				break;
1071 			} else if (node->ns->href != NULL) {
1072 			    if ((step->value2 != NULL) &&
1073 			        (xmlStrEqual(step->value2, node->ns->href)))
1074 				break;
1075 			}
1076 		    }
1077 		    node = node->parent;
1078 		}
1079 		if (node == NULL)
1080 		    goto rollback;
1081 		xsltPatPushState(ctxt, &states, i - 1, node);
1082 		continue;
1083             case XSLT_OP_ID: {
1084 		/* TODO Handle IDs decently, must be done differently */
1085 		xmlAttrPtr id;
1086 
1087 		if (node->type != XML_ELEMENT_NODE)
1088 		    goto rollback;
1089 
1090 		id = xmlGetID(node->doc, step->value);
1091 		if ((id == NULL) || (id->parent != node))
1092 		    goto rollback;
1093 		break;
1094 	    }
1095             case XSLT_OP_KEY: {
1096 		xmlNodeSetPtr list;
1097 		int indx;
1098 
1099 		list = xsltGetKey(ctxt, step->value,
1100 			          step->value3, step->value2);
1101 		if (list == NULL)
1102 		    goto rollback;
1103 		for (indx = 0;indx < list->nodeNr;indx++)
1104 		    if (list->nodeTab[indx] == node)
1105 			break;
1106 		if (indx >= list->nodeNr)
1107 		    goto rollback;
1108 		break;
1109 	    }
1110             case XSLT_OP_NS:
1111 		if (node->type != XML_ELEMENT_NODE)
1112 		    goto rollback;
1113 		if (node->ns == NULL) {
1114 		    if (step->value != NULL)
1115 			goto rollback;
1116 		} else if (node->ns->href != NULL) {
1117 		    if (step->value == NULL)
1118 			goto rollback;
1119 		    if (!xmlStrEqual(step->value, node->ns->href))
1120 			goto rollback;
1121 		}
1122 		break;
1123             case XSLT_OP_ALL:
1124 		if (node->type != XML_ELEMENT_NODE)
1125 		    goto rollback;
1126 		break;
1127 	    case XSLT_OP_PREDICATE: {
1128 		/*
1129 		 * When there is cascading XSLT_OP_PREDICATE or a predicate
1130 		 * after an op which hasn't been optimized yet, then use a
1131 		 * direct computation approach. It's not done directly
1132 		 * at the beginning of the routine to filter out as much
1133 		 * as possible this costly computation.
1134 		 */
1135 		if (comp->direct) {
1136 		    found = xsltTestCompMatchDirect(ctxt, comp, matchNode,
1137 						    comp->nsList, comp->nsNr);
1138                     goto exit;
1139 		}
1140 
1141 		if (!xsltTestPredicateMatch(ctxt, comp, node, step, sel))
1142 		    goto rollback;
1143 
1144 		break;
1145 	    }
1146             case XSLT_OP_PI:
1147 		if (node->type != XML_PI_NODE)
1148 		    goto rollback;
1149 		if (step->value != NULL) {
1150 		    if (!xmlStrEqual(step->value, node->name))
1151 			goto rollback;
1152 		}
1153 		break;
1154             case XSLT_OP_COMMENT:
1155 		if (node->type != XML_COMMENT_NODE)
1156 		    goto rollback;
1157 		break;
1158             case XSLT_OP_TEXT:
1159 		if ((node->type != XML_TEXT_NODE) &&
1160 		    (node->type != XML_CDATA_SECTION_NODE))
1161 		    goto rollback;
1162 		break;
1163             case XSLT_OP_NODE:
1164 		switch (node->type) {
1165 		    case XML_ELEMENT_NODE:
1166 		    case XML_CDATA_SECTION_NODE:
1167 		    case XML_PI_NODE:
1168 		    case XML_COMMENT_NODE:
1169 		    case XML_TEXT_NODE:
1170 			break;
1171 		    default:
1172 			goto rollback;
1173 		}
1174 		break;
1175 	}
1176     }
1177 found:
1178     found = 1;
1179 exit:
1180     ctxt->inst = oldInst;
1181     if (states.states != NULL) {
1182         /* Free the rollback states */
1183 	xmlFree(states.states);
1184     }
1185     return found;
1186 rollback:
1187     /* got an error try to rollback */
1188     if (states.states == NULL || states.nbstates <= 0) {
1189         found = 0;
1190 	goto exit;
1191     }
1192     states.nbstates--;
1193     i = states.states[states.nbstates].step;
1194     node = states.states[states.nbstates].node;
1195 #if 0
1196     fprintf(stderr, "Pop: %d, %s\n", i, node->name);
1197 #endif
1198     goto restart;
1199 }
1200 
1201 /**
1202  * xsltTestCompMatchList:
1203  * @ctxt:  a XSLT process context
1204  * @node: a node
1205  * @comp: the precompiled pattern list
1206  *
1207  * Test whether the node matches one of the patterns in the list
1208  *
1209  * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
1210  */
1211 int
1212 xsltTestCompMatchList(xsltTransformContextPtr ctxt, xmlNodePtr node,
1213 	              xsltCompMatchPtr comp) {
1214     int ret;
1215 
1216     if ((ctxt == NULL) || (node == NULL))
1217 	return(-1);
1218     while (comp != NULL) {
1219 	ret = xsltTestCompMatch(ctxt, comp, node, NULL, NULL);
1220 	if (ret == 1)
1221 	    return(1);
1222 	comp = comp->next;
1223     }
1224     return(0);
1225 }
1226 
1227 /**
1228  * xsltCompMatchClearCache:
1229  * @ctxt:  a XSLT process context
1230  * @comp: the precompiled pattern list
1231  *
1232  * Clear pattern match cache.
1233  */
1234 void
1235 xsltCompMatchClearCache(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp) {
1236     xsltStepOpPtr sel;
1237     xmlXPathObjectPtr list;
1238 
1239     if ((ctxt == NULL) || (comp == NULL))
1240         return;
1241 
1242     sel = &comp->steps[0];
1243     list = (xmlXPathObjectPtr) XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra);
1244 
1245     if (list != NULL) {
1246         xmlXPathFreeObject(list);
1247 
1248         XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) = NULL;
1249         XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = NULL;
1250         XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = 0;
1251         XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) = NULL;
1252     }
1253 }
1254 
1255 /************************************************************************
1256  *									*
1257  *			Dedicated parser for templates			*
1258  *									*
1259  ************************************************************************/
1260 
1261 #define CUR (*ctxt->cur)
1262 #define SKIP(val) ctxt->cur += (val)
1263 #define NXT(val) ctxt->cur[(val)]
1264 #define CUR_PTR ctxt->cur
1265 
1266 #define SKIP_BLANKS							\
1267     while (IS_BLANK_CH(CUR)) NEXT
1268 
1269 #define CURRENT (*ctxt->cur)
1270 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
1271 
1272 
1273 #define PUSH(op, val, val2, novar)						\
1274     if (xsltCompMatchAdd(ctxt, ctxt->comp, (op), (val), (val2), (novar))) goto error;
1275 
1276 #define SWAP()						\
1277     xsltSwapTopCompMatch(ctxt->comp);
1278 
1279 #define XSLT_ERROR(X)							\
1280     { xsltError(ctxt, __FILE__, __LINE__, X);			\
1281       ctxt->error = (X); return; }
1282 
1283 #define XSLT_ERROR0(X)							\
1284     { xsltError(ctxt, __FILE__, __LINE__, X);			\
1285       ctxt->error = (X); return(0); }
1286 
1287 /**
1288  * xsltScanLiteral:
1289  * @ctxt:  the XPath Parser context
1290  *
1291  * Parse an XPath Litteral:
1292  *
1293  * [29] Literal ::= '"' [^"]* '"'
1294  *                | "'" [^']* "'"
1295  *
1296  * Returns the Literal parsed or NULL
1297  */
1298 
1299 static xmlChar *
1300 xsltScanLiteral(xsltParserContextPtr ctxt) {
1301     const xmlChar *q, *cur;
1302     xmlChar *ret = NULL;
1303     int val, len;
1304 
1305     SKIP_BLANKS;
1306     if (CUR == '"') {
1307         NEXT;
1308 	cur = q = CUR_PTR;
1309 	val = xmlStringCurrentChar(NULL, cur, &len);
1310 	while ((IS_CHAR(val)) && (val != '"')) {
1311 	    cur += len;
1312 	    val = xmlStringCurrentChar(NULL, cur, &len);
1313 	}
1314 	if (!IS_CHAR(val)) {
1315 	    ctxt->error = 1;
1316 	    return(NULL);
1317 	} else {
1318 	    ret = xmlStrndup(q, cur - q);
1319         }
1320 	cur += len;
1321 	CUR_PTR = cur;
1322     } else if (CUR == '\'') {
1323         NEXT;
1324 	cur = q = CUR_PTR;
1325 	val = xmlStringCurrentChar(NULL, cur, &len);
1326 	while ((IS_CHAR(val)) && (val != '\'')) {
1327 	    cur += len;
1328 	    val = xmlStringCurrentChar(NULL, cur, &len);
1329 	}
1330 	if (!IS_CHAR(val)) {
1331 	    ctxt->error = 1;
1332 	    return(NULL);
1333 	} else {
1334 	    ret = xmlStrndup(q, cur - q);
1335         }
1336 	cur += len;
1337 	CUR_PTR = cur;
1338     } else {
1339 	/* XP_ERROR(XPATH_START_LITERAL_ERROR); */
1340 	ctxt->error = 1;
1341 	return(NULL);
1342     }
1343     return(ret);
1344 }
1345 
1346 /**
1347  * xsltScanNCName:
1348  * @ctxt:  the XPath Parser context
1349  *
1350  * Parses a non qualified name
1351  *
1352  * Returns the Name parsed or NULL
1353  */
1354 
1355 static xmlChar *
1356 xsltScanNCName(xsltParserContextPtr ctxt) {
1357     const xmlChar *q, *cur;
1358     xmlChar *ret = NULL;
1359     int val, len;
1360 
1361     SKIP_BLANKS;
1362 
1363     cur = q = CUR_PTR;
1364     val = xmlStringCurrentChar(NULL, cur, &len);
1365     if (!IS_LETTER(val) && (val != '_'))
1366 	return(NULL);
1367 
1368     while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
1369            (val == '.') || (val == '-') ||
1370 	   (val == '_') ||
1371 	   (IS_COMBINING(val)) ||
1372 	   (IS_EXTENDER(val))) {
1373 	cur += len;
1374 	val = xmlStringCurrentChar(NULL, cur, &len);
1375     }
1376     ret = xmlStrndup(q, cur - q);
1377     CUR_PTR = cur;
1378     return(ret);
1379 }
1380 
1381 /*
1382  * xsltCompileIdKeyPattern:
1383  * @ctxt:  the compilation context
1384  * @name:  a preparsed name
1385  * @aid:  whether id/key are allowed there
1386  * @novar:  flag to prohibit xslt var
1387  *
1388  * Compile the XSLT LocationIdKeyPattern
1389  * [3] IdKeyPattern ::= 'id' '(' Literal ')'
1390  *                    | 'key' '(' Literal ',' Literal ')'
1391  *
1392  * also handle NodeType and PI from:
1393  *
1394  * [7]  NodeTest ::= NameTest
1395  *                 | NodeType '(' ')'
1396  *                 | 'processing-instruction' '(' Literal ')'
1397  */
1398 static void
1399 xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name,
1400 		int aid, int novar, xsltAxis axis) {
1401     xmlChar *lit = NULL;
1402     xmlChar *lit2 = NULL;
1403 
1404     if (CUR != '(') {
1405 	xsltTransformError(NULL, NULL, NULL,
1406 		"xsltCompileIdKeyPattern : ( expected\n");
1407 	ctxt->error = 1;
1408 	return;
1409     }
1410     if ((aid) && (xmlStrEqual(name, (const xmlChar *)"id"))) {
1411 	if (axis != 0) {
1412 	    xsltTransformError(NULL, NULL, NULL,
1413 		    "xsltCompileIdKeyPattern : NodeTest expected\n");
1414 	    ctxt->error = 1;
1415 	    return;
1416 	}
1417 	NEXT;
1418 	SKIP_BLANKS;
1419         lit = xsltScanLiteral(ctxt);
1420 	if (ctxt->error) {
1421 	    xsltTransformError(NULL, NULL, NULL,
1422 		    "xsltCompileIdKeyPattern : Literal expected\n");
1423 	    return;
1424 	}
1425 	SKIP_BLANKS;
1426 	if (CUR != ')') {
1427 	    xsltTransformError(NULL, NULL, NULL,
1428 		    "xsltCompileIdKeyPattern : ) expected\n");
1429 	    xmlFree(lit);
1430 	    ctxt->error = 1;
1431 	    return;
1432 	}
1433 	NEXT;
1434 	PUSH(XSLT_OP_ID, lit, NULL, novar);
1435 	lit = NULL;
1436     } else if ((aid) && (xmlStrEqual(name, (const xmlChar *)"key"))) {
1437 	if (axis != 0) {
1438 	    xsltTransformError(NULL, NULL, NULL,
1439 		    "xsltCompileIdKeyPattern : NodeTest expected\n");
1440 	    ctxt->error = 1;
1441 	    return;
1442 	}
1443 	NEXT;
1444 	SKIP_BLANKS;
1445         lit = xsltScanLiteral(ctxt);
1446 	if (ctxt->error) {
1447 	    xsltTransformError(NULL, NULL, NULL,
1448 		    "xsltCompileIdKeyPattern : Literal expected\n");
1449 	    return;
1450 	}
1451 	SKIP_BLANKS;
1452 	if (CUR != ',') {
1453 	    xsltTransformError(NULL, NULL, NULL,
1454 		    "xsltCompileIdKeyPattern : , expected\n");
1455 	    xmlFree(lit);
1456 	    ctxt->error = 1;
1457 	    return;
1458 	}
1459 	NEXT;
1460 	SKIP_BLANKS;
1461         lit2 = xsltScanLiteral(ctxt);
1462 	if (ctxt->error) {
1463 	    xsltTransformError(NULL, NULL, NULL,
1464 		    "xsltCompileIdKeyPattern : Literal expected\n");
1465 	    xmlFree(lit);
1466 	    return;
1467 	}
1468 	SKIP_BLANKS;
1469 	if (CUR != ')') {
1470 	    xsltTransformError(NULL, NULL, NULL,
1471 		    "xsltCompileIdKeyPattern : ) expected\n");
1472 	    xmlFree(lit);
1473 	    xmlFree(lit2);
1474 	    ctxt->error = 1;
1475 	    return;
1476 	}
1477 	NEXT;
1478 	/* URGENT TODO: support namespace in keys */
1479 	PUSH(XSLT_OP_KEY, lit, lit2, novar);
1480 	lit = NULL;
1481 	lit2 = NULL;
1482     } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) {
1483 	NEXT;
1484 	SKIP_BLANKS;
1485 	if (CUR != ')') {
1486 	    lit = xsltScanLiteral(ctxt);
1487 	    if (ctxt->error) {
1488 		xsltTransformError(NULL, NULL, NULL,
1489 			"xsltCompileIdKeyPattern : Literal expected\n");
1490 		return;
1491 	    }
1492 	    SKIP_BLANKS;
1493 	    if (CUR != ')') {
1494 		xsltTransformError(NULL, NULL, NULL,
1495 			"xsltCompileIdKeyPattern : ) expected\n");
1496 		ctxt->error = 1;
1497                 xmlFree(lit);
1498 		return;
1499 	    }
1500 	}
1501 	NEXT;
1502 	PUSH(XSLT_OP_PI, lit, NULL, novar);
1503 	lit = NULL;
1504     } else if (xmlStrEqual(name, (const xmlChar *)"text")) {
1505 	NEXT;
1506 	SKIP_BLANKS;
1507 	if (CUR != ')') {
1508 	    xsltTransformError(NULL, NULL, NULL,
1509 		    "xsltCompileIdKeyPattern : ) expected\n");
1510 	    ctxt->error = 1;
1511 	    return;
1512 	}
1513 	NEXT;
1514 	PUSH(XSLT_OP_TEXT, NULL, NULL, novar);
1515     } else if (xmlStrEqual(name, (const xmlChar *)"comment")) {
1516 	NEXT;
1517 	SKIP_BLANKS;
1518 	if (CUR != ')') {
1519 	    xsltTransformError(NULL, NULL, NULL,
1520 		    "xsltCompileIdKeyPattern : ) expected\n");
1521 	    ctxt->error = 1;
1522 	    return;
1523 	}
1524 	NEXT;
1525 	PUSH(XSLT_OP_COMMENT, NULL, NULL, novar);
1526     } else if (xmlStrEqual(name, (const xmlChar *)"node")) {
1527 	NEXT;
1528 	SKIP_BLANKS;
1529 	if (CUR != ')') {
1530 	    xsltTransformError(NULL, NULL, NULL,
1531 		    "xsltCompileIdKeyPattern : ) expected\n");
1532 	    ctxt->error = 1;
1533 	    return;
1534 	}
1535 	NEXT;
1536 	if (axis == AXIS_ATTRIBUTE) {
1537 	    PUSH(XSLT_OP_ATTR, NULL, NULL, novar);
1538 	}
1539 	else {
1540 	    PUSH(XSLT_OP_NODE, NULL, NULL, novar);
1541 	}
1542     } else if (aid) {
1543 	xsltTransformError(NULL, NULL, NULL,
1544 	    "xsltCompileIdKeyPattern : expecting 'key' or 'id' or node type\n");
1545 	ctxt->error = 1;
1546 	return;
1547     } else {
1548 	xsltTransformError(NULL, NULL, NULL,
1549 	    "xsltCompileIdKeyPattern : node type\n");
1550 	ctxt->error = 1;
1551 	return;
1552     }
1553 error:
1554     return;
1555 }
1556 
1557 /**
1558  * xsltCompileStepPattern:
1559  * @ctxt:  the compilation context
1560  * @token:  a posible precompiled name
1561  * @novar: flag to prohibit xslt variables from pattern
1562  *
1563  * Compile the XSLT StepPattern and generates a precompiled
1564  * form suitable for fast matching.
1565  *
1566  * [5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate*
1567  * [6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier
1568  *                                     | ('child' | 'attribute') '::'
1569  * from XPath
1570  * [7]  NodeTest ::= NameTest
1571  *                 | NodeType '(' ')'
1572  *                 | 'processing-instruction' '(' Literal ')'
1573  * [8] Predicate ::= '[' PredicateExpr ']'
1574  * [9] PredicateExpr ::= Expr
1575  * [13] AbbreviatedAxisSpecifier ::= '@'?
1576  * [37] NameTest ::= '*' | NCName ':' '*' | QName
1577  */
1578 
1579 static void
1580 xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) {
1581     xmlChar *name = NULL;
1582     const xmlChar *URI = NULL;
1583     xmlChar *URL = NULL;
1584     int level;
1585     xsltAxis axis = 0;
1586 
1587     SKIP_BLANKS;
1588     if ((token == NULL) && (CUR == '@')) {
1589 	NEXT;
1590         axis = AXIS_ATTRIBUTE;
1591     }
1592 parse_node_test:
1593     if (token == NULL)
1594 	token = xsltScanNCName(ctxt);
1595     if (token == NULL) {
1596 	if (CUR == '*') {
1597 	    NEXT;
1598 	    if (axis == AXIS_ATTRIBUTE) {
1599                 PUSH(XSLT_OP_ATTR, NULL, NULL, novar);
1600             }
1601             else {
1602                 PUSH(XSLT_OP_ALL, NULL, NULL, novar);
1603             }
1604 	    goto parse_predicate;
1605 	} else {
1606 	    xsltTransformError(NULL, NULL, NULL,
1607 		    "xsltCompileStepPattern : Name expected\n");
1608 	    ctxt->error = 1;
1609 	    goto error;
1610 	}
1611     }
1612 
1613 
1614     SKIP_BLANKS;
1615     if (CUR == '(') {
1616 	xsltCompileIdKeyPattern(ctxt, token, 0, novar, axis);
1617 	xmlFree(token);
1618 	token = NULL;
1619 	if (ctxt->error)
1620 	    goto error;
1621     } else if (CUR == ':') {
1622 	NEXT;
1623 	if (CUR != ':') {
1624 	    xmlChar *prefix = token;
1625 	    xmlNsPtr ns;
1626 
1627 	    /*
1628 	     * This is a namespace match
1629 	     */
1630 	    token = xsltScanNCName(ctxt);
1631 	    ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
1632 	    if (ns == NULL) {
1633 		xsltTransformError(NULL, NULL, NULL,
1634 	    "xsltCompileStepPattern : no namespace bound to prefix %s\n",
1635 				 prefix);
1636 		xmlFree(prefix);
1637 		prefix=NULL;
1638 		ctxt->error = 1;
1639 		goto error;
1640 	    } else {
1641 		URL = xmlStrdup(ns->href);
1642 	    }
1643 	    xmlFree(prefix);
1644 	    prefix=NULL;
1645 	    if (token == NULL) {
1646 		if (CUR == '*') {
1647 		    NEXT;
1648                     if (axis == AXIS_ATTRIBUTE) {
1649                         PUSH(XSLT_OP_ATTR, NULL, URL, novar);
1650 			URL = NULL;
1651                     }
1652                     else {
1653                         PUSH(XSLT_OP_NS, URL, NULL, novar);
1654 			URL = NULL;
1655                     }
1656 		} else {
1657 		    xsltTransformError(NULL, NULL, NULL,
1658 			    "xsltCompileStepPattern : Name expected\n");
1659 		    ctxt->error = 1;
1660                     xmlFree(URL);
1661 		    goto error;
1662 		}
1663 	    } else {
1664                 if (axis == AXIS_ATTRIBUTE) {
1665                     PUSH(XSLT_OP_ATTR, token, URL, novar);
1666 		    token = NULL;
1667 		    URL = NULL;
1668                 }
1669                 else {
1670                     PUSH(XSLT_OP_ELEM, token, URL, novar);
1671 		    token = NULL;
1672 		    URL = NULL;
1673                 }
1674 	    }
1675 	} else {
1676 	    if (axis != 0) {
1677 		xsltTransformError(NULL, NULL, NULL,
1678 		    "xsltCompileStepPattern : NodeTest expected\n");
1679 		ctxt->error = 1;
1680 		goto error;
1681 	    }
1682 	    NEXT;
1683 	    if (xmlStrEqual(token, (const xmlChar *) "child")) {
1684 	        axis = AXIS_CHILD;
1685 	    } else if (xmlStrEqual(token, (const xmlChar *) "attribute")) {
1686 	        axis = AXIS_ATTRIBUTE;
1687 	    } else {
1688 		xsltTransformError(NULL, NULL, NULL,
1689 		    "xsltCompileStepPattern : 'child' or 'attribute' expected\n");
1690 		ctxt->error = 1;
1691 		goto error;
1692 	    }
1693 	    xmlFree(token);
1694 	    token = NULL;
1695             SKIP_BLANKS;
1696             token = xsltScanNCName(ctxt);
1697 	    goto parse_node_test;
1698 	}
1699     } else {
1700 	URI = xsltGetQNameURI(ctxt->elem, &token);
1701 	if (token == NULL) {
1702 	    ctxt->error = 1;
1703 	    goto error;
1704 	}
1705 	if (URI != NULL)
1706 	    URL = xmlStrdup(URI);
1707         if (axis == AXIS_ATTRIBUTE) {
1708             PUSH(XSLT_OP_ATTR, token, URL, novar);
1709 	    token = NULL;
1710 	    URL = NULL;
1711         }
1712         else {
1713             PUSH(XSLT_OP_ELEM, token, URL, novar);
1714 	    token = NULL;
1715 	    URL = NULL;
1716         }
1717     }
1718 parse_predicate:
1719     SKIP_BLANKS;
1720     level = 0;
1721     while (CUR == '[') {
1722 	const xmlChar *q;
1723 	xmlChar *ret = NULL;
1724 
1725 	level++;
1726 	NEXT;
1727 	q = CUR_PTR;
1728 	while (CUR != 0) {
1729 	    /* Skip over nested predicates */
1730 	    if (CUR == '[')
1731 		level++;
1732 	    else if (CUR == ']') {
1733 		level--;
1734 		if (level == 0)
1735 		    break;
1736 	    } else if (CUR == '"') {
1737 		NEXT;
1738 		while ((CUR != 0) && (CUR != '"'))
1739 		    NEXT;
1740 	    } else if (CUR == '\'') {
1741 		NEXT;
1742 		while ((CUR != 0) && (CUR != '\''))
1743 		    NEXT;
1744 	    }
1745 	    NEXT;
1746 	}
1747 	if (CUR == 0) {
1748 	    xsltTransformError(NULL, NULL, NULL,
1749 		    "xsltCompileStepPattern : ']' expected\n");
1750 	    ctxt->error = 1;
1751 	    return;
1752         }
1753 	ret = xmlStrndup(q, CUR_PTR - q);
1754 	PUSH(XSLT_OP_PREDICATE, ret, NULL, novar);
1755 	ret = NULL;
1756 	/* push the predicate lower than local test */
1757 	SWAP();
1758 	NEXT;
1759 	SKIP_BLANKS;
1760     }
1761     return;
1762 error:
1763     if (token != NULL)
1764 	xmlFree(token);
1765     if (name != NULL)
1766 	xmlFree(name);
1767 }
1768 
1769 /**
1770  * xsltCompileRelativePathPattern:
1771  * @comp:  the compilation context
1772  * @token:  a posible precompiled name
1773  * @novar:  flag to prohibit xslt variables
1774  *
1775  * Compile the XSLT RelativePathPattern and generates a precompiled
1776  * form suitable for fast matching.
1777  *
1778  * [4] RelativePathPattern ::= StepPattern
1779  *                           | RelativePathPattern '/' StepPattern
1780  *                           | RelativePathPattern '//' StepPattern
1781  */
1782 static void
1783 xsltCompileRelativePathPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) {
1784     xsltCompileStepPattern(ctxt, token, novar);
1785     if (ctxt->error)
1786 	goto error;
1787     SKIP_BLANKS;
1788     while ((CUR != 0) && (CUR != '|')) {
1789 	if ((CUR == '/') && (NXT(1) == '/')) {
1790 	    PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar);
1791 	    NEXT;
1792 	    NEXT;
1793 	    SKIP_BLANKS;
1794 	    xsltCompileStepPattern(ctxt, NULL, novar);
1795 	} else if (CUR == '/') {
1796 	    PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
1797 	    NEXT;
1798 	    SKIP_BLANKS;
1799 	    xsltCompileStepPattern(ctxt, NULL, novar);
1800 	} else {
1801 	    ctxt->error = 1;
1802 	}
1803 	if (ctxt->error)
1804 	    goto error;
1805 	SKIP_BLANKS;
1806     }
1807 error:
1808     return;
1809 }
1810 
1811 /**
1812  * xsltCompileLocationPathPattern:
1813  * @ctxt:  the compilation context
1814  * @novar:  flag to prohibit xslt variables
1815  *
1816  * Compile the XSLT LocationPathPattern and generates a precompiled
1817  * form suitable for fast matching.
1818  *
1819  * [2] LocationPathPattern ::= '/' RelativePathPattern?
1820  *                           | IdKeyPattern (('/' | '//') RelativePathPattern)?
1821  *                           | '//'? RelativePathPattern
1822  */
1823 static void
1824 xsltCompileLocationPathPattern(xsltParserContextPtr ctxt, int novar) {
1825     SKIP_BLANKS;
1826     if ((CUR == '/') && (NXT(1) == '/')) {
1827 	/*
1828 	 * since we reverse the query
1829 	 * a leading // can be safely ignored
1830 	 */
1831 	NEXT;
1832 	NEXT;
1833 	ctxt->comp->priority = 0.5;	/* '//' means not 0 priority */
1834 	xsltCompileRelativePathPattern(ctxt, NULL, novar);
1835     } else if (CUR == '/') {
1836 	/*
1837 	 * We need to find root as the parent
1838 	 */
1839 	NEXT;
1840 	SKIP_BLANKS;
1841 	PUSH(XSLT_OP_ROOT, NULL, NULL, novar);
1842 	if ((CUR != 0) && (CUR != '|')) {
1843 	    PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
1844 	    xsltCompileRelativePathPattern(ctxt, NULL, novar);
1845 	}
1846     } else if (CUR == '*') {
1847 	xsltCompileRelativePathPattern(ctxt, NULL, novar);
1848     } else if (CUR == '@') {
1849 	xsltCompileRelativePathPattern(ctxt, NULL, novar);
1850     } else {
1851 	xmlChar *name;
1852 	name = xsltScanNCName(ctxt);
1853 	if (name == NULL) {
1854 	    xsltTransformError(NULL, NULL, NULL,
1855 		    "xsltCompileLocationPathPattern : Name expected\n");
1856 	    ctxt->error = 1;
1857 	    return;
1858 	}
1859 	SKIP_BLANKS;
1860 	if ((CUR == '(') && !xmlXPathIsNodeType(name)) {
1861 	    xsltCompileIdKeyPattern(ctxt, name, 1, novar, 0);
1862 	    xmlFree(name);
1863 	    name = NULL;
1864             if (ctxt->error)
1865                 return;
1866 	    if ((CUR == '/') && (NXT(1) == '/')) {
1867 		PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar);
1868 		NEXT;
1869 		NEXT;
1870 		SKIP_BLANKS;
1871 		xsltCompileRelativePathPattern(ctxt, NULL, novar);
1872 	    } else if (CUR == '/') {
1873 		PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
1874 		NEXT;
1875 		SKIP_BLANKS;
1876 		xsltCompileRelativePathPattern(ctxt, NULL, novar);
1877 	    }
1878 	    return;
1879 	}
1880 	xsltCompileRelativePathPattern(ctxt, name, novar);
1881     }
1882 error:
1883     return;
1884 }
1885 
1886 /**
1887  * xsltCompilePatternInternal:
1888  * @pattern: an XSLT pattern
1889  * @doc:  the containing document
1890  * @node:  the containing element
1891  * @style:  the stylesheet
1892  * @runtime:  the transformation context, if done at run-time
1893  * @novar:  flag to prohibit xslt variables
1894  *
1895  * Compile the XSLT pattern and generates a list of precompiled form suitable
1896  * for fast matching.
1897  *
1898  * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern
1899  *
1900  * Returns the generated pattern list or NULL in case of failure
1901  */
1902 
1903 static xsltCompMatchPtr
1904 xsltCompilePatternInternal(const xmlChar *pattern, xmlDocPtr doc,
1905 	           xmlNodePtr node, xsltStylesheetPtr style,
1906 		   xsltTransformContextPtr runtime, int novar) {
1907     xsltParserContextPtr ctxt = NULL;
1908     xsltCompMatchPtr element, first = NULL, previous = NULL;
1909     int current, start, end, level, j;
1910 
1911     if (pattern == NULL) {
1912 	xsltTransformError(NULL, NULL, node,
1913 			 "xsltCompilePattern : NULL pattern\n");
1914 	return(NULL);
1915     }
1916 
1917     ctxt = xsltNewParserContext(style, runtime);
1918     if (ctxt == NULL)
1919 	return(NULL);
1920     ctxt->doc = doc;
1921     ctxt->elem = node;
1922     current = end = 0;
1923     while (pattern[current] != 0) {
1924 	start = current;
1925 	while (IS_BLANK_CH(pattern[current]))
1926 	    current++;
1927 	end = current;
1928 	level = 0;
1929 	while ((pattern[end] != 0) && ((pattern[end] != '|') || (level != 0))) {
1930 	    if (pattern[end] == '[')
1931 		level++;
1932 	    else if (pattern[end] == ']')
1933 		level--;
1934 	    else if (pattern[end] == '\'') {
1935 		end++;
1936 		while ((pattern[end] != 0) && (pattern[end] != '\''))
1937 		    end++;
1938 	    } else if (pattern[end] == '"') {
1939 		end++;
1940 		while ((pattern[end] != 0) && (pattern[end] != '"'))
1941 		    end++;
1942 	    }
1943 	    if (pattern[end] == 0)
1944 	        break;
1945 	    end++;
1946 	}
1947 	if (current == end) {
1948 	    xsltTransformError(NULL, NULL, node,
1949 			     "xsltCompilePattern : NULL pattern\n");
1950 	    goto error;
1951 	}
1952 	element = xsltNewCompMatch();
1953 	if (element == NULL) {
1954 	    goto error;
1955 	}
1956 	if (first == NULL)
1957 	    first = element;
1958 	else if (previous != NULL)
1959 	    previous->next = element;
1960 	previous = element;
1961 
1962 	ctxt->comp = element;
1963 	ctxt->base = xmlStrndup(&pattern[start], end - start);
1964 	if (ctxt->base == NULL)
1965 	    goto error;
1966 	ctxt->cur = &(ctxt->base)[current - start];
1967 	element->pattern = ctxt->base;
1968         element->node = node;
1969 	element->nsList = xmlGetNsList(doc, node);
1970 	j = 0;
1971 	if (element->nsList != NULL) {
1972 	    while (element->nsList[j] != NULL)
1973 		j++;
1974 	}
1975 	element->nsNr = j;
1976 
1977 
1978 #ifdef WITH_XSLT_DEBUG_PATTERN
1979 	xsltGenericDebug(xsltGenericDebugContext,
1980 			 "xsltCompilePattern : parsing '%s'\n",
1981 			 element->pattern);
1982 #endif
1983 	/*
1984 	 Preset default priority to be zero.
1985 	 This may be changed by xsltCompileLocationPathPattern.
1986 	 */
1987 	element->priority = 0;
1988 	xsltCompileLocationPathPattern(ctxt, novar);
1989 	if (ctxt->error) {
1990 	    xsltTransformError(NULL, style, node,
1991 			     "xsltCompilePattern : failed to compile '%s'\n",
1992 			     element->pattern);
1993 	    if (style != NULL) style->errors++;
1994 	    goto error;
1995 	}
1996 
1997 	/*
1998 	 * Reverse for faster interpretation.
1999 	 */
2000 	xsltReverseCompMatch(ctxt, element);
2001 
2002 	/*
2003 	 * Set-up the priority
2004 	 */
2005 	if (element->priority == 0) {	/* if not yet determined */
2006 	    if (((element->steps[0].op == XSLT_OP_ELEM) ||
2007 		 (element->steps[0].op == XSLT_OP_ATTR) ||
2008 		 (element->steps[0].op == XSLT_OP_PI)) &&
2009 		(element->steps[0].value != NULL) &&
2010 		(element->steps[1].op == XSLT_OP_END)) {
2011 		;	/* previously preset */
2012 	    } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
2013 		       (element->steps[0].value2 != NULL) &&
2014 		       (element->steps[1].op == XSLT_OP_END)) {
2015 			element->priority = -0.25;
2016 	    } else if ((element->steps[0].op == XSLT_OP_NS) &&
2017 		       (element->steps[0].value != NULL) &&
2018 		       (element->steps[1].op == XSLT_OP_END)) {
2019 			element->priority = -0.25;
2020 	    } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
2021 		       (element->steps[0].value == NULL) &&
2022 		       (element->steps[0].value2 == NULL) &&
2023 		       (element->steps[1].op == XSLT_OP_END)) {
2024 			element->priority = -0.5;
2025 	    } else if (((element->steps[0].op == XSLT_OP_PI) ||
2026 		       (element->steps[0].op == XSLT_OP_TEXT) ||
2027 		       (element->steps[0].op == XSLT_OP_ALL) ||
2028 		       (element->steps[0].op == XSLT_OP_NODE) ||
2029 		       (element->steps[0].op == XSLT_OP_COMMENT)) &&
2030 		       (element->steps[1].op == XSLT_OP_END)) {
2031 			element->priority = -0.5;
2032 	    } else {
2033 		element->priority = 0.5;
2034 	    }
2035 	}
2036 #ifdef WITH_XSLT_DEBUG_PATTERN
2037 	xsltGenericDebug(xsltGenericDebugContext,
2038 		     "xsltCompilePattern : parsed %s, default priority %f\n",
2039 			 element->pattern, element->priority);
2040 #endif
2041 	if (pattern[end] == '|')
2042 	    end++;
2043 	current = end;
2044     }
2045     if (end == 0) {
2046 	xsltTransformError(NULL, style, node,
2047 			 "xsltCompilePattern : NULL pattern\n");
2048 	if (style != NULL) style->errors++;
2049 	goto error;
2050     }
2051 
2052     xsltFreeParserContext(ctxt);
2053     return(first);
2054 
2055 error:
2056     if (ctxt != NULL)
2057 	xsltFreeParserContext(ctxt);
2058     if (first != NULL)
2059 	xsltFreeCompMatchList(first);
2060     return(NULL);
2061 }
2062 
2063 /**
2064  * xsltCompilePattern:
2065  * @pattern: an XSLT pattern
2066  * @doc:  the containing document
2067  * @node:  the containing element
2068  * @style:  the stylesheet
2069  * @runtime:  the transformation context, if done at run-time
2070  *
2071  * Compile the XSLT pattern and generates a list of precompiled form suitable
2072  * for fast matching.
2073  *
2074  * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern
2075  *
2076  * Returns the generated pattern list or NULL in case of failure
2077  */
2078 
2079 xsltCompMatchPtr
2080 xsltCompilePattern(const xmlChar *pattern, xmlDocPtr doc,
2081 	           xmlNodePtr node, xsltStylesheetPtr style,
2082 		   xsltTransformContextPtr runtime) {
2083     return (xsltCompilePatternInternal(pattern, doc, node, style, runtime, 0));
2084 }
2085 
2086 /************************************************************************
2087  *									*
2088  *			Module interfaces				*
2089  *									*
2090  ************************************************************************/
2091 
2092 /**
2093  * xsltAddTemplate:
2094  * @style: an XSLT stylesheet
2095  * @cur: an XSLT template
2096  * @mode:  the mode name or NULL
2097  * @modeURI:  the mode URI or NULL
2098  *
2099  * Register the XSLT pattern associated to @cur
2100  *
2101  * Returns -1 in case of error, 0 otherwise
2102  */
2103 int
2104 xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
2105 	        const xmlChar *mode, const xmlChar *modeURI) {
2106     xsltCompMatchPtr pat, list, next;
2107     /*
2108      * 'top' will point to style->xxxMatch ptr - declaring as 'void'
2109      *  avoids gcc 'type-punned pointer' warning.
2110      */
2111     void **top = NULL;
2112     const xmlChar *name = NULL;
2113     float priority;              /* the priority */
2114 
2115     if ((style == NULL) || (cur == NULL))
2116 	return(-1);
2117 
2118     /* Register named template */
2119     if (cur->name != NULL) {
2120         if (style->namedTemplates == NULL) {
2121             style->namedTemplates = xmlHashCreate(10);
2122             if (style->namedTemplates == NULL)
2123                 return(-1);
2124         }
2125         else {
2126             void *dup = xmlHashLookup2(style->namedTemplates, cur->name,
2127                                        cur->nameURI);
2128             if (dup != NULL) {
2129                 xsltTransformError(NULL, style, cur->elem,
2130                                    "xsl:template: error duplicate name '%s'\n",
2131                                    cur->name);
2132                 style->errors++;
2133                 return(-1);
2134             }
2135         }
2136 
2137         xmlHashAddEntry2(style->namedTemplates, cur->name, cur->nameURI, cur);
2138     }
2139 
2140     if (cur->match == NULL) {
2141             if (cur->name == NULL) {
2142                 xsltTransformError(NULL, style, cur->elem,
2143                     "xsl:template: need to specify match or name attribute\n");
2144                 style->errors++;
2145                 return(-1);
2146             }
2147 	return(0);
2148     }
2149 
2150     priority = cur->priority;
2151     pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem,
2152 		    style, NULL, 1);
2153     if (pat == NULL)
2154 	return(-1);
2155     while (pat) {
2156 	next = pat->next;
2157 	pat->next = NULL;
2158 	name = NULL;
2159 
2160 	pat->template = cur;
2161 	if (mode != NULL)
2162 	    pat->mode = xmlDictLookup(style->dict, mode, -1);
2163 	if (modeURI != NULL)
2164 	    pat->modeURI = xmlDictLookup(style->dict, modeURI, -1);
2165 	if (priority != XSLT_PAT_NO_PRIORITY)
2166 	    pat->priority = priority;
2167 
2168 	/*
2169 	 * insert it in the hash table list corresponding to its lookup name
2170 	 */
2171 	switch (pat->steps[0].op) {
2172         case XSLT_OP_ATTR:
2173 	    if (pat->steps[0].value != NULL)
2174 		name = pat->steps[0].value;
2175 	    else
2176 		top = &(style->attrMatch);
2177 	    break;
2178         case XSLT_OP_PARENT:
2179         case XSLT_OP_ANCESTOR:
2180 	    top = &(style->elemMatch);
2181 	    break;
2182         case XSLT_OP_ROOT:
2183 	    top = &(style->rootMatch);
2184 	    break;
2185         case XSLT_OP_KEY:
2186 	    top = &(style->keyMatch);
2187 	    break;
2188         case XSLT_OP_ID:
2189 	    /* TODO optimize ID !!! */
2190         case XSLT_OP_NS:
2191         case XSLT_OP_ALL:
2192 	    top = &(style->elemMatch);
2193 	    break;
2194         case XSLT_OP_END:
2195 	case XSLT_OP_PREDICATE:
2196 	    xsltTransformError(NULL, style, NULL,
2197 			     "xsltAddTemplate: invalid compiled pattern\n");
2198 	    xsltFreeCompMatch(pat);
2199 	    return(-1);
2200 	    /*
2201 	     * TODO: some flags at the top level about type based patterns
2202 	     *       would be faster than inclusion in the hash table.
2203 	     */
2204 	case XSLT_OP_PI:
2205 	    if (pat->steps[0].value != NULL)
2206 		name = pat->steps[0].value;
2207 	    else
2208 		top = &(style->piMatch);
2209 	    break;
2210 	case XSLT_OP_COMMENT:
2211 	    top = &(style->commentMatch);
2212 	    break;
2213 	case XSLT_OP_TEXT:
2214 	    top = &(style->textMatch);
2215 	    break;
2216         case XSLT_OP_ELEM:
2217 	case XSLT_OP_NODE:
2218 	    if (pat->steps[0].value != NULL)
2219 		name = pat->steps[0].value;
2220 	    else
2221 		top = &(style->elemMatch);
2222 	    break;
2223 	}
2224 	if (name != NULL) {
2225 	    if (style->templatesHash == NULL) {
2226 		style->templatesHash = xmlHashCreate(1024);
2227 		if (style->templatesHash == NULL) {
2228 		    xsltFreeCompMatch(pat);
2229 		    return(-1);
2230 		}
2231 		xmlHashAddEntry3(style->templatesHash, name, mode, modeURI, pat);
2232 	    } else {
2233 		list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash,
2234 							 name, mode, modeURI);
2235 		if (list == NULL) {
2236 		    xmlHashAddEntry3(style->templatesHash, name,
2237 				     mode, modeURI, pat);
2238 		} else {
2239 		    /*
2240 		     * Note '<=' since one must choose among the matching
2241 		     * template rules that are left, the one that occurs
2242 		     * last in the stylesheet
2243 		     */
2244 		    if (list->priority <= pat->priority) {
2245 			pat->next = list;
2246 			xmlHashUpdateEntry3(style->templatesHash, name,
2247 					    mode, modeURI, pat, NULL);
2248 		    } else {
2249 			while (list->next != NULL) {
2250 			    if (list->next->priority <= pat->priority)
2251 				break;
2252 			    list = list->next;
2253 			}
2254 			pat->next = list->next;
2255 			list->next = pat;
2256 		    }
2257 		}
2258 	    }
2259 	} else if (top != NULL) {
2260 	    list = *top;
2261 	    if (list == NULL) {
2262 		*top = pat;
2263 		pat->next = NULL;
2264 	    } else if (list->priority <= pat->priority) {
2265 		pat->next = list;
2266 		*top = pat;
2267 	    } else {
2268 		while (list->next != NULL) {
2269 		    if (list->next->priority <= pat->priority)
2270 			break;
2271 		    list = list->next;
2272 		}
2273 		pat->next = list->next;
2274 		list->next = pat;
2275 	    }
2276 	} else {
2277 	    xsltTransformError(NULL, style, NULL,
2278 			     "xsltAddTemplate: invalid compiled pattern\n");
2279 	    xsltFreeCompMatch(pat);
2280 	    return(-1);
2281 	}
2282 #ifdef WITH_XSLT_DEBUG_PATTERN
2283 	if (mode)
2284 	    xsltGenericDebug(xsltGenericDebugContext,
2285 			 "added pattern : '%s' mode '%s' priority %f\n",
2286 			     pat->pattern, pat->mode, pat->priority);
2287 	else
2288 	    xsltGenericDebug(xsltGenericDebugContext,
2289 			 "added pattern : '%s' priority %f\n",
2290 			     pat->pattern, pat->priority);
2291 #endif
2292 
2293 	pat = next;
2294     }
2295     return(0);
2296 }
2297 
2298 static int
2299 xsltComputeAllKeys(xsltTransformContextPtr ctxt, xmlNodePtr contextNode)
2300 {
2301     if ((ctxt == NULL) || (contextNode == NULL)) {
2302 	xsltTransformError(ctxt, NULL, ctxt->inst,
2303 	    "Internal error in xsltComputeAllKeys(): "
2304 	    "Bad arguments.\n");
2305 	return(-1);
2306     }
2307 
2308     if (ctxt->document == NULL) {
2309 	/*
2310 	* The document info will only be NULL if we have a RTF.
2311 	*/
2312 	if (contextNode->doc->_private != NULL)
2313 	    goto doc_info_mismatch;
2314 	/*
2315 	* On-demand creation of the document info (needed for keys).
2316 	*/
2317 	ctxt->document = xsltNewDocument(ctxt, contextNode->doc);
2318 	if (ctxt->document == NULL)
2319 	    return(-1);
2320     }
2321     return xsltInitAllDocKeys(ctxt);
2322 
2323 doc_info_mismatch:
2324     xsltTransformError(ctxt, NULL, ctxt->inst,
2325 	"Internal error in xsltComputeAllKeys(): "
2326 	"The context's document info doesn't match the "
2327 	"document info of the current result tree.\n");
2328     ctxt->state = XSLT_STATE_STOPPED;
2329     return(-1);
2330 }
2331 
2332 /**
2333  * xsltGetTemplate:
2334  * @ctxt:  a XSLT process context
2335  * @node:  the node being processed
2336  * @style:  the current style
2337  *
2338  * Finds the template applying to this node, if @style is non-NULL
2339  * it means one needs to look for the next imported template in scope.
2340  *
2341  * Returns the xsltTemplatePtr or NULL if not found
2342  */
2343 xsltTemplatePtr
2344 xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
2345 	        xsltStylesheetPtr style)
2346 {
2347     xsltStylesheetPtr curstyle;
2348     xsltTemplatePtr ret = NULL;
2349     const xmlChar *name = NULL;
2350     xsltCompMatchPtr list = NULL;
2351     float priority;
2352     int keyed = 0;
2353 
2354     if ((ctxt == NULL) || (node == NULL))
2355 	return(NULL);
2356 
2357     if (style == NULL) {
2358 	curstyle = ctxt->style;
2359     } else {
2360 	curstyle = xsltNextImport(style);
2361     }
2362 
2363     while ((curstyle != NULL) && (curstyle != style)) {
2364 	priority = XSLT_PAT_NO_PRIORITY;
2365 	/* TODO : handle IDs/keys here ! */
2366 	if (curstyle->templatesHash != NULL) {
2367 	    /*
2368 	     * Use the top name as selector
2369 	     */
2370 	    switch (node->type) {
2371 		case XML_ELEMENT_NODE:
2372 		    if (node->name[0] == ' ')
2373 			break;
2374                     /* Intentional fall-through */
2375 		case XML_ATTRIBUTE_NODE:
2376 		case XML_PI_NODE:
2377 		    name = node->name;
2378 		    break;
2379 		case XML_DOCUMENT_NODE:
2380 		case XML_HTML_DOCUMENT_NODE:
2381 		case XML_TEXT_NODE:
2382 		case XML_CDATA_SECTION_NODE:
2383 		case XML_COMMENT_NODE:
2384 		case XML_ENTITY_REF_NODE:
2385 		case XML_ENTITY_NODE:
2386 		case XML_DOCUMENT_TYPE_NODE:
2387 		case XML_DOCUMENT_FRAG_NODE:
2388 		case XML_NOTATION_NODE:
2389 		case XML_DTD_NODE:
2390 		case XML_ELEMENT_DECL:
2391 		case XML_ATTRIBUTE_DECL:
2392 		case XML_ENTITY_DECL:
2393 		case XML_NAMESPACE_DECL:
2394 		case XML_XINCLUDE_START:
2395 		case XML_XINCLUDE_END:
2396 		    break;
2397 		default:
2398 		    return(NULL);
2399 
2400 	    }
2401 	}
2402 	if (name != NULL) {
2403 	    /*
2404 	     * find the list of applicable expressions based on the name
2405 	     */
2406 	    list = (xsltCompMatchPtr) xmlHashLookup3(curstyle->templatesHash,
2407 					     name, ctxt->mode, ctxt->modeURI);
2408 	} else
2409 	    list = NULL;
2410 	while (list != NULL) {
2411 	    if (xsltTestCompMatch(ctxt, list, node,
2412 			          ctxt->mode, ctxt->modeURI) == 1) {
2413 		ret = list->template;
2414 		priority = list->priority;
2415 		break;
2416 	    }
2417 	    list = list->next;
2418 	}
2419 	list = NULL;
2420 
2421 	/*
2422 	 * find alternate generic matches
2423 	 */
2424 	switch (node->type) {
2425 	    case XML_ELEMENT_NODE:
2426 		if (node->name[0] == ' ')
2427 		    list = curstyle->rootMatch;
2428 		else
2429 		    list = curstyle->elemMatch;
2430 		if (node->psvi != NULL) keyed = 1;
2431 		break;
2432 	    case XML_ATTRIBUTE_NODE: {
2433 	        xmlAttrPtr attr;
2434 
2435 		list = curstyle->attrMatch;
2436 		attr = (xmlAttrPtr) node;
2437 		if (attr->psvi != NULL) keyed = 1;
2438 		break;
2439 	    }
2440 	    case XML_PI_NODE:
2441 		list = curstyle->piMatch;
2442 		if (node->psvi != NULL) keyed = 1;
2443 		break;
2444 	    case XML_DOCUMENT_NODE:
2445 	    case XML_HTML_DOCUMENT_NODE: {
2446 	        xmlDocPtr doc;
2447 
2448 		list = curstyle->rootMatch;
2449 		doc = (xmlDocPtr) node;
2450 		if (doc->psvi != NULL) keyed = 1;
2451 		break;
2452 	    }
2453 	    case XML_TEXT_NODE:
2454 	    case XML_CDATA_SECTION_NODE:
2455 		list = curstyle->textMatch;
2456 		if (node->psvi != NULL) keyed = 1;
2457 		break;
2458 	    case XML_COMMENT_NODE:
2459 		list = curstyle->commentMatch;
2460 		if (node->psvi != NULL) keyed = 1;
2461 		break;
2462 	    case XML_ENTITY_REF_NODE:
2463 	    case XML_ENTITY_NODE:
2464 	    case XML_DOCUMENT_TYPE_NODE:
2465 	    case XML_DOCUMENT_FRAG_NODE:
2466 	    case XML_NOTATION_NODE:
2467 	    case XML_DTD_NODE:
2468 	    case XML_ELEMENT_DECL:
2469 	    case XML_ATTRIBUTE_DECL:
2470 	    case XML_ENTITY_DECL:
2471 	    case XML_NAMESPACE_DECL:
2472 	    case XML_XINCLUDE_START:
2473 	    case XML_XINCLUDE_END:
2474 		break;
2475 	    default:
2476 		break;
2477 	}
2478 	while ((list != NULL) &&
2479 	       ((ret == NULL)  || (list->priority > priority))) {
2480 	    if (xsltTestCompMatch(ctxt, list, node,
2481 			          ctxt->mode, ctxt->modeURI) == 1) {
2482 		ret = list->template;
2483 		priority = list->priority;
2484 		break;
2485 	    }
2486 	    list = list->next;
2487 	}
2488 	/*
2489 	 * Some of the tests for elements can also apply to documents
2490 	 */
2491 	if ((node->type == XML_DOCUMENT_NODE) ||
2492 	    (node->type == XML_HTML_DOCUMENT_NODE) ||
2493 	    (node->type == XML_TEXT_NODE)) {
2494 	    list = curstyle->elemMatch;
2495 	    while ((list != NULL) &&
2496 		   ((ret == NULL)  || (list->priority > priority))) {
2497 		if (xsltTestCompMatch(ctxt, list, node,
2498 				      ctxt->mode, ctxt->modeURI) == 1) {
2499 		    ret = list->template;
2500 		    priority = list->priority;
2501 		    break;
2502 		}
2503 		list = list->next;
2504 	    }
2505 	} else if ((node->type == XML_PI_NODE) ||
2506 		   (node->type == XML_COMMENT_NODE)) {
2507 	    list = curstyle->elemMatch;
2508 	    while ((list != NULL) &&
2509 		   ((ret == NULL)  || (list->priority > priority))) {
2510 		if (xsltTestCompMatch(ctxt, list, node,
2511 				      ctxt->mode, ctxt->modeURI) == 1) {
2512 		    ret = list->template;
2513 		    priority = list->priority;
2514 		    break;
2515 		}
2516 		list = list->next;
2517 	    }
2518 	}
2519 
2520 keyed_match:
2521 	if (keyed) {
2522 	    list = curstyle->keyMatch;
2523 	    while ((list != NULL) &&
2524 		   ((ret == NULL)  || (list->priority > priority))) {
2525 		if (xsltTestCompMatch(ctxt, list, node,
2526 				      ctxt->mode, ctxt->modeURI) == 1) {
2527 		    ret = list->template;
2528 		    priority = list->priority;
2529 		    break;
2530 		}
2531 		list = list->next;
2532 	    }
2533 	}
2534 	else if (ctxt->hasTemplKeyPatterns &&
2535 	    ((ctxt->document == NULL) ||
2536 	     (ctxt->document->nbKeysComputed < ctxt->nbKeys)))
2537 	{
2538 	    /*
2539 	    * Compute all remaining keys for this document.
2540 	    *
2541 	    * REVISIT TODO: I think this could be further optimized.
2542 	    */
2543 	    if (xsltComputeAllKeys(ctxt, node) == -1)
2544 		goto error;
2545 
2546 	    switch (node->type) {
2547 		case XML_ELEMENT_NODE:
2548 		    if (node->psvi != NULL) keyed = 1;
2549 		    break;
2550 		case XML_ATTRIBUTE_NODE:
2551 		    if (((xmlAttrPtr) node)->psvi != NULL) keyed = 1;
2552 		    break;
2553 		case XML_TEXT_NODE:
2554 		case XML_CDATA_SECTION_NODE:
2555 		case XML_COMMENT_NODE:
2556 		case XML_PI_NODE:
2557 		    if (node->psvi != NULL) keyed = 1;
2558 		    break;
2559 		case XML_DOCUMENT_NODE:
2560 		case XML_HTML_DOCUMENT_NODE:
2561 		    if (((xmlDocPtr) node)->psvi != NULL) keyed = 1;
2562 		    break;
2563 		default:
2564 		    break;
2565 	    }
2566 	    if (keyed)
2567 		goto keyed_match;
2568 	}
2569 	if (ret != NULL)
2570 	    return(ret);
2571 
2572 	/*
2573 	 * Cycle on next curstylesheet import.
2574 	 */
2575 	curstyle = xsltNextImport(curstyle);
2576     }
2577 
2578 error:
2579     return(NULL);
2580 }
2581 
2582 /**
2583  * xsltCleanupTemplates:
2584  * @style: an XSLT stylesheet
2585  *
2586  * Cleanup the state of the templates used by the stylesheet and
2587  * the ones it imports.
2588  */
2589 void
2590 xsltCleanupTemplates(xsltStylesheetPtr style ATTRIBUTE_UNUSED) {
2591 }
2592 
2593 /**
2594  * xsltFreeTemplateHashes:
2595  * @style: an XSLT stylesheet
2596  *
2597  * Free up the memory used by xsltAddTemplate/xsltGetTemplate mechanism
2598  */
2599 void
2600 xsltFreeTemplateHashes(xsltStylesheetPtr style) {
2601     if (style->templatesHash != NULL)
2602 	xmlHashFree((xmlHashTablePtr) style->templatesHash,
2603 		    xsltFreeCompMatchListEntry);
2604     if (style->rootMatch != NULL)
2605         xsltFreeCompMatchList(style->rootMatch);
2606     if (style->keyMatch != NULL)
2607         xsltFreeCompMatchList(style->keyMatch);
2608     if (style->elemMatch != NULL)
2609         xsltFreeCompMatchList(style->elemMatch);
2610     if (style->attrMatch != NULL)
2611         xsltFreeCompMatchList(style->attrMatch);
2612     if (style->parentMatch != NULL)
2613         xsltFreeCompMatchList(style->parentMatch);
2614     if (style->textMatch != NULL)
2615         xsltFreeCompMatchList(style->textMatch);
2616     if (style->piMatch != NULL)
2617         xsltFreeCompMatchList(style->piMatch);
2618     if (style->commentMatch != NULL)
2619         xsltFreeCompMatchList(style->commentMatch);
2620     if (style->namedTemplates != NULL)
2621         xmlHashFree(style->namedTemplates, NULL);
2622 }
2623 
2624