blob: dcaba9cd732d79f7f91dca1b280fb0c3a927794d [file] [log] [blame]
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001/*
2 * pattern.c: Implemetation of selectors for nodes
3 *
4 * Reference:
5 * http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/
6 * to some extent
7 * http://www.w3.org/TR/1999/REC-xml-19991116
8 *
9 * See Copyright for the status of this software.
10 *
11 * daniel@veillard.com
12 */
13
Daniel Veillardf9d16912005-01-30 22:36:30 +000014/*
15 * TODO:
16 * - compilation flags to check for specific syntaxes
17 * using flags of xmlPatterncompile()
18 * - making clear how pattern starting with / or . need to be handled,
19 * currently push(NULL, NULL) means a reset of the streaming context
20 * and indicating we are on / (the document node), probably need
21 * something similar for .
Daniel Veillardd4301ab2005-02-03 22:24:10 +000022 * - get rid of the "compile" starting with lowercase
23 * - get rid of the Strdup/Strndup in case of dictionary
Daniel Veillardf9d16912005-01-30 22:36:30 +000024 */
25
Daniel Veillardb3de70c2003-12-02 22:32:15 +000026#define IN_LIBXML
27#include "libxml.h"
28
29#include <string.h>
30#include <libxml/xmlmemory.h>
31#include <libxml/tree.h>
32#include <libxml/hash.h>
33#include <libxml/dict.h>
34#include <libxml/xmlerror.h>
35#include <libxml/parserInternals.h>
36#include <libxml/pattern.h>
37
Daniel Veillardd4301ab2005-02-03 22:24:10 +000038#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardb3de70c2003-12-02 22:32:15 +000039
Daniel Veillardd4301ab2005-02-03 22:24:10 +000040/* #define DEBUG_STREAMING */
Daniel Veillard2fc6df92005-01-30 18:42:55 +000041
Daniel Veillardb3de70c2003-12-02 22:32:15 +000042#define ERROR(a, b, c, d)
43#define ERROR5(a, b, c, d, e)
44
Daniel Veillard2fc6df92005-01-30 18:42:55 +000045#define XML_STREAM_STEP_DESC 1
46#define XML_STREAM_STEP_FINAL 2
47#define XML_STREAM_STEP_ROOT 4
48
49typedef struct _xmlStreamStep xmlStreamStep;
50typedef xmlStreamStep *xmlStreamStepPtr;
51struct _xmlStreamStep {
52 int flags; /* properties of that step */
53 const xmlChar *name; /* first string value if NULL accept all */
54 const xmlChar *ns; /* second string value */
55};
56
57typedef struct _xmlStreamComp xmlStreamComp;
58typedef xmlStreamComp *xmlStreamCompPtr;
59struct _xmlStreamComp {
60 xmlDict *dict; /* the dictionnary if any */
61 int nbStep; /* number of steps in the automata */
62 int maxStep; /* allocated number of steps */
63 xmlStreamStepPtr steps; /* the array of steps */
64};
65
66struct _xmlStreamCtxt {
Daniel Veillardf1f08cf2005-02-05 16:35:04 +000067 struct _xmlStreamCtxt *next;/* link to next sub pattern if | */
Daniel Veillard2fc6df92005-01-30 18:42:55 +000068 xmlStreamCompPtr comp; /* the compiled stream */
69 int nbState; /* number of state in the automata */
70 int maxState; /* allocated number of state */
71 int level; /* how deep are we ? */
72 int *states; /* the array of step indexes */
73};
74
75static void xmlFreeStreamComp(xmlStreamCompPtr comp);
76
Daniel Veillardb3de70c2003-12-02 22:32:15 +000077/*
78 * Types are private:
79 */
80
81typedef enum {
82 XML_OP_END=0,
83 XML_OP_ROOT,
84 XML_OP_ELEM,
85 XML_OP_CHILD,
86 XML_OP_ATTR,
87 XML_OP_PARENT,
88 XML_OP_ANCESTOR,
89 XML_OP_NS,
90 XML_OP_ALL
91} xmlPatOp;
92
93
Daniel Veillardd4301ab2005-02-03 22:24:10 +000094typedef struct _xmlStepState xmlStepState;
95typedef xmlStepState *xmlStepStatePtr;
96struct _xmlStepState {
97 int step;
98 xmlNodePtr node;
99};
100
101typedef struct _xmlStepStates xmlStepStates;
102typedef xmlStepStates *xmlStepStatesPtr;
103struct _xmlStepStates {
104 int nbstates;
105 int maxstates;
106 xmlStepStatePtr states;
107};
108
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000109typedef struct _xmlStepOp xmlStepOp;
110typedef xmlStepOp *xmlStepOpPtr;
111struct _xmlStepOp {
112 xmlPatOp op;
113 const xmlChar *value;
114 const xmlChar *value2;
115};
116
Daniel Veillard56de87e2005-02-16 00:22:29 +0000117#define PAT_FROM_ROOT 1
118#define PAT_FROM_CUR 2
119
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000120struct _xmlPattern {
121 void *data; /* the associated template */
Daniel Veillard2fc6df92005-01-30 18:42:55 +0000122 xmlDictPtr dict; /* the optional dictionnary */
Daniel Veillardf1f08cf2005-02-05 16:35:04 +0000123 struct _xmlPattern *next; /* next pattern if | is used */
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000124 const xmlChar *pattern; /* the pattern */
125
Daniel Veillard56de87e2005-02-16 00:22:29 +0000126 int flags; /* flags */
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000127 int nbStep;
128 int maxStep;
Daniel Veillardc7c9fb12005-01-12 21:04:15 +0000129 xmlStepOpPtr steps; /* ops for computation */
Daniel Veillard2fc6df92005-01-30 18:42:55 +0000130 xmlStreamCompPtr stream; /* the streaming data if any */
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000131};
132
133typedef struct _xmlPatParserContext xmlPatParserContext;
134typedef xmlPatParserContext *xmlPatParserContextPtr;
135struct _xmlPatParserContext {
136 const xmlChar *cur; /* the current char being parsed */
137 const xmlChar *base; /* the full expression */
138 int error; /* error code */
139 xmlDictPtr dict; /* the dictionnary if any */
140 xmlPatternPtr comp; /* the result */
141 xmlNodePtr elem; /* the current node if any */
Daniel Veillardffa7b7e2003-12-05 16:10:21 +0000142 const xmlChar **namespaces; /* the namespaces definitions */
143 int nb_namespaces; /* the number of namespaces */
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000144};
145
146/************************************************************************
147 * *
148 * Type functions *
149 * *
150 ************************************************************************/
151
152/**
153 * xmlNewPattern:
154 *
155 * Create a new XSLT Pattern
156 *
157 * Returns the newly allocated xmlPatternPtr or NULL in case of error
158 */
159static xmlPatternPtr
160xmlNewPattern(void) {
161 xmlPatternPtr cur;
162
163 cur = (xmlPatternPtr) xmlMalloc(sizeof(xmlPattern));
164 if (cur == NULL) {
165 ERROR(NULL, NULL, NULL,
166 "xmlNewPattern : malloc failed\n");
167 return(NULL);
168 }
169 memset(cur, 0, sizeof(xmlPattern));
170 cur->maxStep = 10;
Daniel Veillardc7c9fb12005-01-12 21:04:15 +0000171 cur->steps = (xmlStepOpPtr) xmlMalloc(cur->maxStep * sizeof(xmlStepOp));
172 if (cur->steps == NULL) {
173 xmlFree(cur);
174 ERROR(NULL, NULL, NULL,
175 "xmlNewPattern : malloc failed\n");
176 return(NULL);
177 }
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000178 return(cur);
179}
180
181/**
182 * xmlFreePattern:
183 * @comp: an XSLT comp
184 *
185 * Free up the memory allocated by @comp
186 */
187void
188xmlFreePattern(xmlPatternPtr comp) {
189 xmlStepOpPtr op;
190 int i;
191
192 if (comp == NULL)
193 return;
Daniel Veillardf1f08cf2005-02-05 16:35:04 +0000194 if (comp->next != NULL)
195 xmlFreePattern(comp->next);
Daniel Veillard2fc6df92005-01-30 18:42:55 +0000196 if (comp->stream != NULL)
197 xmlFreeStreamComp(comp->stream);
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000198 if (comp->pattern != NULL)
199 xmlFree((xmlChar *)comp->pattern);
Daniel Veillardc7c9fb12005-01-12 21:04:15 +0000200 if (comp->steps != NULL) {
Daniel Veillard2fc6df92005-01-30 18:42:55 +0000201 if (comp->dict == NULL) {
202 for (i = 0;i < comp->nbStep;i++) {
203 op = &comp->steps[i];
204 if (op->value != NULL)
205 xmlFree((xmlChar *) op->value);
206 if (op->value2 != NULL)
207 xmlFree((xmlChar *) op->value2);
208 }
Daniel Veillardc7c9fb12005-01-12 21:04:15 +0000209 }
210 xmlFree(comp->steps);
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000211 }
Daniel Veillard2fc6df92005-01-30 18:42:55 +0000212 if (comp->dict != NULL)
213 xmlDictFree(comp->dict);
214
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000215 memset(comp, -1, sizeof(xmlPattern));
216 xmlFree(comp);
217}
218
219/**
220 * xmlFreePatternList:
221 * @comp: an XSLT comp list
222 *
223 * Free up the memory allocated by all the elements of @comp
224 */
225void
226xmlFreePatternList(xmlPatternPtr comp) {
227 xmlPatternPtr cur;
228
229 while (comp != NULL) {
230 cur = comp;
231 comp = comp->next;
232 xmlFreePattern(cur);
233 }
234}
235
236/**
237 * xmlNewPatParserContext:
238 * @pattern: the pattern context
Daniel Veillardffa7b7e2003-12-05 16:10:21 +0000239 * @dict: the inherited dictionnary or NULL
Daniel Veillard2fc6df92005-01-30 18:42:55 +0000240 * @namespaces: the prefix definitions, array of [URI, prefix] terminated
241 * with [NULL, NULL] or NULL if no namespace is used
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000242 *
243 * Create a new XML pattern parser context
244 *
245 * Returns the newly allocated xmlPatParserContextPtr or NULL in case of error
246 */
247static xmlPatParserContextPtr
Daniel Veillardffa7b7e2003-12-05 16:10:21 +0000248xmlNewPatParserContext(const xmlChar *pattern, xmlDictPtr dict,
249 const xmlChar **namespaces) {
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000250 xmlPatParserContextPtr cur;
251
252 if (pattern == NULL)
253 return(NULL);
254
255 cur = (xmlPatParserContextPtr) xmlMalloc(sizeof(xmlPatParserContext));
256 if (cur == NULL) {
257 ERROR(NULL, NULL, NULL,
258 "xmlNewPatParserContext : malloc failed\n");
259 return(NULL);
260 }
261 memset(cur, 0, sizeof(xmlPatParserContext));
262 cur->dict = dict;
263 cur->cur = pattern;
264 cur->base = pattern;
Daniel Veillardffa7b7e2003-12-05 16:10:21 +0000265 if (namespaces != NULL) {
266 int i;
267 for (i = 0;namespaces[2 * i] != NULL;i++);
268 cur->nb_namespaces = i;
269 } else {
270 cur->nb_namespaces = 0;
271 }
272 cur->namespaces = namespaces;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000273 return(cur);
274}
275
276/**
277 * xmlFreePatParserContext:
278 * @ctxt: an XSLT parser context
279 *
280 * Free up the memory allocated by @ctxt
281 */
282static void
283xmlFreePatParserContext(xmlPatParserContextPtr ctxt) {
284 if (ctxt == NULL)
285 return;
286 memset(ctxt, -1, sizeof(xmlPatParserContext));
287 xmlFree(ctxt);
288}
289
290/**
291 * xmlPatternAdd:
292 * @comp: the compiled match expression
293 * @op: an op
294 * @value: the first value
295 * @value2: the second value
296 *
297 * Add an step to an XSLT Compiled Match
298 *
299 * Returns -1 in case of failure, 0 otherwise.
300 */
301static int
302xmlPatternAdd(xmlPatParserContextPtr ctxt ATTRIBUTE_UNUSED,
303 xmlPatternPtr comp,
304 xmlPatOp op, xmlChar * value, xmlChar * value2)
305{
Daniel Veillardc7c9fb12005-01-12 21:04:15 +0000306 if (comp->nbStep >= comp->maxStep) {
307 xmlStepOpPtr temp;
308 temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
309 sizeof(xmlStepOp));
310 if (temp == NULL) {
311 ERROR(ctxt, NULL, NULL,
312 "xmlPatternAdd: realloc failed\n");
313 return (-1);
314 }
315 comp->steps = temp;
316 comp->maxStep *= 2;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000317 }
318 comp->steps[comp->nbStep].op = op;
319 comp->steps[comp->nbStep].value = value;
320 comp->steps[comp->nbStep].value2 = value2;
321 comp->nbStep++;
322 return (0);
323}
324
325#if 0
326/**
327 * xsltSwapTopPattern:
328 * @comp: the compiled match expression
329 *
330 * reverse the two top steps.
331 */
332static void
333xsltSwapTopPattern(xmlPatternPtr comp) {
334 int i;
335 int j = comp->nbStep - 1;
336
337 if (j > 0) {
338 register const xmlChar *tmp;
339 register xmlPatOp op;
340 i = j - 1;
341 tmp = comp->steps[i].value;
342 comp->steps[i].value = comp->steps[j].value;
343 comp->steps[j].value = tmp;
344 tmp = comp->steps[i].value2;
345 comp->steps[i].value2 = comp->steps[j].value2;
346 comp->steps[j].value2 = tmp;
347 op = comp->steps[i].op;
348 comp->steps[i].op = comp->steps[j].op;
349 comp->steps[j].op = op;
350 }
351}
352#endif
353
354/**
355 * xmlReversePattern:
356 * @comp: the compiled match expression
357 *
358 * reverse all the stack of expressions
Daniel Veillardc7c9fb12005-01-12 21:04:15 +0000359 *
360 * returns 0 in case of success and -1 in case of error.
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000361 */
Daniel Veillardc7c9fb12005-01-12 21:04:15 +0000362static int
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000363xmlReversePattern(xmlPatternPtr comp) {
Daniel Veillard56de87e2005-02-16 00:22:29 +0000364 int i, j;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000365
Daniel Veillard56de87e2005-02-16 00:22:29 +0000366 /*
367 * remove the leading // for //a or .//a
368 */
369 if ((comp->nbStep > 0) && (comp->steps[0].op == XML_OP_ANCESTOR)) {
370 for (i = 0, j = 1;j < comp->nbStep;i++,j++) {
371 comp->steps[i].value = comp->steps[j].value;
372 comp->steps[i].value2 = comp->steps[j].value2;
373 comp->steps[i].op = comp->steps[j].op;
374 }
375 comp->nbStep--;
376 }
Daniel Veillardc7c9fb12005-01-12 21:04:15 +0000377 if (comp->nbStep >= comp->maxStep) {
378 xmlStepOpPtr temp;
379 temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
380 sizeof(xmlStepOp));
381 if (temp == NULL) {
382 ERROR(ctxt, NULL, NULL,
383 "xmlReversePattern: realloc failed\n");
384 return (-1);
385 }
386 comp->steps = temp;
387 comp->maxStep *= 2;
388 }
Daniel Veillard56de87e2005-02-16 00:22:29 +0000389 i = 0;
390 j = comp->nbStep - 1;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000391 while (j > i) {
392 register const xmlChar *tmp;
393 register xmlPatOp op;
394 tmp = comp->steps[i].value;
395 comp->steps[i].value = comp->steps[j].value;
396 comp->steps[j].value = tmp;
397 tmp = comp->steps[i].value2;
398 comp->steps[i].value2 = comp->steps[j].value2;
399 comp->steps[j].value2 = tmp;
400 op = comp->steps[i].op;
401 comp->steps[i].op = comp->steps[j].op;
402 comp->steps[j].op = op;
403 j--;
404 i++;
405 }
Daniel Veillardc7c9fb12005-01-12 21:04:15 +0000406 comp->steps[comp->nbStep].value = NULL;
407 comp->steps[comp->nbStep].value2 = NULL;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000408 comp->steps[comp->nbStep++].op = XML_OP_END;
Daniel Veillardc7c9fb12005-01-12 21:04:15 +0000409 return(0);
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000410}
411
412/************************************************************************
413 * *
414 * The interpreter for the precompiled patterns *
415 * *
416 ************************************************************************/
417
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000418static int
419xmlPatPushState(xmlStepStates *states, int step, xmlNodePtr node) {
420 if ((states->states == NULL) || (states->maxstates <= 0)) {
421 states->maxstates = 4;
422 states->nbstates = 0;
423 states->states = xmlMalloc(4 * sizeof(xmlStepState));
424 }
425 else if (states->maxstates <= states->nbstates) {
426 xmlStepState *tmp;
427
428 tmp = (xmlStepStatePtr) xmlRealloc(states->states,
429 2 * states->maxstates * sizeof(xmlStepState));
430 if (tmp == NULL)
431 return(-1);
432 states->states = tmp;
433 states->maxstates *= 2;
434 }
435 states->states[states->nbstates].step = step;
436 states->states[states->nbstates++].node = node;
437#if 0
438 fprintf(stderr, "Push: %d, %s\n", step, node->name);
439#endif
440 return(0);
441}
442
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000443/**
444 * xmlPatMatch:
445 * @comp: the precompiled pattern
446 * @node: a node
447 *
448 * Test wether the node matches the pattern
449 *
450 * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
451 */
452static int
453xmlPatMatch(xmlPatternPtr comp, xmlNodePtr node) {
454 int i;
455 xmlStepOpPtr step;
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000456 xmlStepStates states = {0, 0, NULL}; /* // may require backtrack */
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000457
458 if ((comp == NULL) || (node == NULL)) return(-1);
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000459 i = 0;
460restart:
461 for (;i < comp->nbStep;i++) {
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000462 step = &comp->steps[i];
463 switch (step->op) {
464 case XML_OP_END:
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000465 goto found;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000466 case XML_OP_ROOT:
Daniel Veillard2fc6df92005-01-30 18:42:55 +0000467 if (node->type == XML_NAMESPACE_DECL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000468 goto rollback;
Daniel Veillard2fc6df92005-01-30 18:42:55 +0000469 node = node->parent;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000470 if ((node->type == XML_DOCUMENT_NODE) ||
471#ifdef LIBXML_DOCB_ENABLED
472 (node->type == XML_DOCB_DOCUMENT_NODE) ||
473#endif
474 (node->type == XML_HTML_DOCUMENT_NODE))
475 continue;
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000476 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000477 case XML_OP_ELEM:
478 if (node->type != XML_ELEMENT_NODE)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000479 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000480 if (step->value == NULL)
481 continue;
482 if (step->value[0] != node->name[0])
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000483 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000484 if (!xmlStrEqual(step->value, node->name))
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000485 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000486
487 /* Namespace test */
488 if (node->ns == NULL) {
489 if (step->value2 != NULL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000490 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000491 } else if (node->ns->href != NULL) {
492 if (step->value2 == NULL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000493 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000494 if (!xmlStrEqual(step->value2, node->ns->href))
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000495 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000496 }
497 continue;
498 case XML_OP_CHILD: {
499 xmlNodePtr lst;
500
501 if ((node->type != XML_ELEMENT_NODE) &&
502 (node->type != XML_DOCUMENT_NODE) &&
503#ifdef LIBXML_DOCB_ENABLED
504 (node->type != XML_DOCB_DOCUMENT_NODE) &&
505#endif
506 (node->type != XML_HTML_DOCUMENT_NODE))
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000507 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000508
509 lst = node->children;
510
511 if (step->value != NULL) {
512 while (lst != NULL) {
513 if ((lst->type == XML_ELEMENT_NODE) &&
514 (step->value[0] == lst->name[0]) &&
515 (xmlStrEqual(step->value, lst->name)))
516 break;
517 lst = lst->next;
518 }
519 if (lst != NULL)
520 continue;
521 }
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000522 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000523 }
524 case XML_OP_ATTR:
525 if (node->type != XML_ATTRIBUTE_NODE)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000526 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000527 if (step->value != NULL) {
528 if (step->value[0] != node->name[0])
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000529 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000530 if (!xmlStrEqual(step->value, node->name))
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000531 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000532 }
533 /* Namespace test */
534 if (node->ns == NULL) {
535 if (step->value2 != NULL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000536 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000537 } else if (step->value2 != NULL) {
538 if (!xmlStrEqual(step->value2, node->ns->href))
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000539 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000540 }
541 continue;
542 case XML_OP_PARENT:
543 if ((node->type == XML_DOCUMENT_NODE) ||
544 (node->type == XML_HTML_DOCUMENT_NODE) ||
545#ifdef LIBXML_DOCB_ENABLED
546 (node->type == XML_DOCB_DOCUMENT_NODE) ||
547#endif
548 (node->type == XML_NAMESPACE_DECL))
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000549 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000550 node = node->parent;
551 if (node == NULL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000552 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000553 if (step->value == NULL)
554 continue;
555 if (step->value[0] != node->name[0])
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000556 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000557 if (!xmlStrEqual(step->value, node->name))
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000558 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000559 /* Namespace test */
560 if (node->ns == NULL) {
561 if (step->value2 != NULL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000562 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000563 } else if (node->ns->href != NULL) {
564 if (step->value2 == NULL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000565 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000566 if (!xmlStrEqual(step->value2, node->ns->href))
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000567 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000568 }
569 continue;
570 case XML_OP_ANCESTOR:
571 /* TODO: implement coalescing of ANCESTOR/NODE ops */
572 if (step->value == NULL) {
573 i++;
574 step = &comp->steps[i];
575 if (step->op == XML_OP_ROOT)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000576 goto found;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000577 if (step->op != XML_OP_ELEM)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000578 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000579 if (step->value == NULL)
580 return(-1);
581 }
582 if (node == NULL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000583 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000584 if ((node->type == XML_DOCUMENT_NODE) ||
585 (node->type == XML_HTML_DOCUMENT_NODE) ||
586#ifdef LIBXML_DOCB_ENABLED
587 (node->type == XML_DOCB_DOCUMENT_NODE) ||
588#endif
589 (node->type == XML_NAMESPACE_DECL))
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000590 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000591 node = node->parent;
592 while (node != NULL) {
593 if (node == NULL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000594 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000595 if ((node->type == XML_ELEMENT_NODE) &&
596 (step->value[0] == node->name[0]) &&
597 (xmlStrEqual(step->value, node->name))) {
598 /* Namespace test */
599 if (node->ns == NULL) {
600 if (step->value2 == NULL)
601 break;
602 } else if (node->ns->href != NULL) {
603 if ((step->value2 != NULL) &&
604 (xmlStrEqual(step->value2, node->ns->href)))
605 break;
606 }
607 }
608 node = node->parent;
609 }
610 if (node == NULL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000611 goto rollback;
612 /*
613 * prepare a potential rollback from here
614 * for ancestors of that node.
615 */
616 if (step->op == XML_OP_ANCESTOR)
617 xmlPatPushState(&states, i, node);
618 else
619 xmlPatPushState(&states, i - 1, node);
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000620 continue;
621 case XML_OP_NS:
622 if (node->type != XML_ELEMENT_NODE)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000623 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000624 if (node->ns == NULL) {
625 if (step->value != NULL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000626 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000627 } else if (node->ns->href != NULL) {
628 if (step->value == NULL)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000629 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000630 if (!xmlStrEqual(step->value, node->ns->href))
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000631 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000632 }
633 break;
634 case XML_OP_ALL:
635 if (node->type != XML_ELEMENT_NODE)
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000636 goto rollback;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000637 break;
638 }
639 }
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000640found:
641 if (states.states != NULL) {
642 /* Free the rollback states */
643 xmlFree(states.states);
644 }
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000645 return(1);
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000646rollback:
647 /* got an error try to rollback */
648 if (states.states == NULL)
649 return(0);
650 if (states.nbstates <= 0) {
651 xmlFree(states.states);
652 return(0);
653 }
654 states.nbstates--;
655 i = states.states[states.nbstates].step;
656 node = states.states[states.nbstates].node;
657#if 0
658 fprintf(stderr, "Pop: %d, %s\n", i, node->name);
659#endif
660 goto restart;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000661}
662
663/************************************************************************
664 * *
665 * Dedicated parser for templates *
666 * *
667 ************************************************************************/
668
669#define TODO \
670 xmlGenericError(xmlGenericErrorContext, \
671 "Unimplemented block at %s:%d\n", \
672 __FILE__, __LINE__);
673#define CUR (*ctxt->cur)
674#define SKIP(val) ctxt->cur += (val)
675#define NXT(val) ctxt->cur[(val)]
676#define CUR_PTR ctxt->cur
677
678#define SKIP_BLANKS \
Daniel Veillard427174f2003-12-10 10:42:59 +0000679 while (IS_BLANK_CH(CUR)) NEXT
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000680
681#define CURRENT (*ctxt->cur)
682#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
683
684
685#define PUSH(op, val, val2) \
686 if (xmlPatternAdd(ctxt, ctxt->comp, (op), (val), (val2))) goto error;
687
688#define XSLT_ERROR(X) \
689 { xsltError(ctxt, __FILE__, __LINE__, X); \
690 ctxt->error = (X); return; }
691
692#define XSLT_ERROR0(X) \
693 { xsltError(ctxt, __FILE__, __LINE__, X); \
694 ctxt->error = (X); return(0); }
695
696#if 0
697/**
698 * xmlPatScanLiteral:
699 * @ctxt: the XPath Parser context
700 *
701 * Parse an XPath Litteral:
702 *
703 * [29] Literal ::= '"' [^"]* '"'
704 * | "'" [^']* "'"
705 *
706 * Returns the Literal parsed or NULL
707 */
708
709static xmlChar *
710xmlPatScanLiteral(xmlPatParserContextPtr ctxt) {
711 const xmlChar *q, *cur;
712 xmlChar *ret = NULL;
713 int val, len;
714
715 SKIP_BLANKS;
716 if (CUR == '"') {
717 NEXT;
718 cur = q = CUR_PTR;
719 val = xmlStringCurrentChar(NULL, cur, &len);
720 while ((IS_CHAR(val)) && (val != '"')) {
721 cur += len;
722 val = xmlStringCurrentChar(NULL, cur, &len);
723 }
724 if (!IS_CHAR(val)) {
725 ctxt->error = 1;
726 return(NULL);
727 } else {
728 ret = xmlStrndup(q, cur - q);
729 }
730 cur += len;
731 CUR_PTR = cur;
732 } else if (CUR == '\'') {
733 NEXT;
734 cur = q = CUR_PTR;
735 val = xmlStringCurrentChar(NULL, cur, &len);
736 while ((IS_CHAR(val)) && (val != '\'')) {
737 cur += len;
738 val = xmlStringCurrentChar(NULL, cur, &len);
739 }
740 if (!IS_CHAR(val)) {
741 ctxt->error = 1;
742 return(NULL);
743 } else {
744 ret = xmlStrndup(q, cur - q);
745 }
746 cur += len;
747 CUR_PTR = cur;
748 } else {
749 /* XP_ERROR(XPATH_START_LITERAL_ERROR); */
750 ctxt->error = 1;
751 return(NULL);
752 }
753 return(ret);
754}
755#endif
756
757/**
758 * xmlPatScanName:
759 * @ctxt: the XPath Parser context
760 *
761 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' |
762 * CombiningChar | Extender
763 *
764 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
765 *
766 * [6] Names ::= Name (S Name)*
767 *
768 * Returns the Name parsed or NULL
769 */
770
771static xmlChar *
772xmlPatScanName(xmlPatParserContextPtr ctxt) {
773 const xmlChar *q, *cur;
774 xmlChar *ret = NULL;
775 int val, len;
776
777 SKIP_BLANKS;
778
779 cur = q = CUR_PTR;
780 val = xmlStringCurrentChar(NULL, cur, &len);
781 if (!IS_LETTER(val) && (val != '_') && (val != ':'))
782 return(NULL);
783
784 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
785 (val == '.') || (val == '-') ||
786 (val == '_') ||
787 (IS_COMBINING(val)) ||
788 (IS_EXTENDER(val))) {
789 cur += len;
790 val = xmlStringCurrentChar(NULL, cur, &len);
791 }
792 ret = xmlStrndup(q, cur - q);
793 CUR_PTR = cur;
794 return(ret);
795}
796
797/**
798 * xmlPatScanNCName:
799 * @ctxt: the XPath Parser context
800 *
801 * Parses a non qualified name
802 *
803 * Returns the Name parsed or NULL
804 */
805
806static xmlChar *
807xmlPatScanNCName(xmlPatParserContextPtr ctxt) {
808 const xmlChar *q, *cur;
809 xmlChar *ret = NULL;
810 int val, len;
811
812 SKIP_BLANKS;
813
814 cur = q = CUR_PTR;
815 val = xmlStringCurrentChar(NULL, cur, &len);
816 if (!IS_LETTER(val) && (val != '_'))
817 return(NULL);
818
819 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
820 (val == '.') || (val == '-') ||
821 (val == '_') ||
822 (IS_COMBINING(val)) ||
823 (IS_EXTENDER(val))) {
824 cur += len;
825 val = xmlStringCurrentChar(NULL, cur, &len);
826 }
827 ret = xmlStrndup(q, cur - q);
828 CUR_PTR = cur;
829 return(ret);
830}
831
832#if 0
833/**
834 * xmlPatScanQName:
835 * @ctxt: the XPath Parser context
836 * @prefix: the place to store the prefix
837 *
838 * Parse a qualified name
839 *
840 * Returns the Name parsed or NULL
841 */
842
843static xmlChar *
844xmlPatScanQName(xmlPatParserContextPtr ctxt, xmlChar **prefix) {
845 xmlChar *ret = NULL;
846
847 *prefix = NULL;
848 ret = xmlPatScanNCName(ctxt);
849 if (CUR == ':') {
850 *prefix = ret;
851 NEXT;
852 ret = xmlPatScanNCName(ctxt);
853 }
854 return(ret);
855}
856#endif
857
858/**
859 * xmlCompileStepPattern:
860 * @ctxt: the compilation context
861 *
862 * Compile the Step Pattern and generates a precompiled
863 * form suitable for fast matching.
864 *
865 * [3] Step ::= '.' | NameTest
866 * [4] NameTest ::= QName | '*' | NCName ':' '*'
867 */
868
869static void
870xmlCompileStepPattern(xmlPatParserContextPtr ctxt) {
871 xmlChar *token = NULL;
872 xmlChar *name = NULL;
873 const xmlChar *URI = NULL;
874 xmlChar *URL = NULL;
875
876 SKIP_BLANKS;
877 if (CUR == '.') {
878 NEXT;
879 PUSH(XML_OP_ELEM, NULL, NULL);
880 return;
881 }
882 name = xmlPatScanNCName(ctxt);
883 if (name == NULL) {
884 if (CUR == '*') {
885 NEXT;
886 PUSH(XML_OP_ALL, NULL, NULL);
887 return;
888 } else {
889 ERROR(NULL, NULL, NULL,
890 "xmlCompileStepPattern : Name expected\n");
891 ctxt->error = 1;
892 return;
893 }
894 }
895 SKIP_BLANKS;
896 if (CUR == ':') {
897 NEXT;
898 if (CUR != ':') {
899 xmlChar *prefix = name;
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000900 int i;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000901
902 /*
903 * This is a namespace match
904 */
905 token = xmlPatScanName(ctxt);
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000906 for (i = 0;i < ctxt->nb_namespaces;i++) {
907 if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
Daniel Veillard0996a162005-02-05 14:00:10 +0000908 URL = xmlStrdup(ctxt->namespaces[2 * i]);
Daniel Veillardd4301ab2005-02-03 22:24:10 +0000909 break;
910 }
911 }
912 if (i >= ctxt->nb_namespaces) {
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000913 ERROR5(NULL, NULL, NULL,
914 "xmlCompileStepPattern : no namespace bound to prefix %s\n",
915 prefix);
916 ctxt->error = 1;
917 goto error;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000918 }
919 xmlFree(prefix);
920 if (token == NULL) {
921 if (CUR == '*') {
922 NEXT;
923 PUSH(XML_OP_NS, URL, NULL);
924 } else {
925 ERROR(NULL, NULL, NULL,
926 "xmlCompileStepPattern : Name expected\n");
927 ctxt->error = 1;
928 goto error;
929 }
930 } else {
931 PUSH(XML_OP_ELEM, token, URL);
932 }
933 } else {
934 NEXT;
935 if (xmlStrEqual(token, (const xmlChar *) "child")) {
936 xmlFree(token);
937 token = xmlPatScanName(ctxt);
938 if (token == NULL) {
939 if (CUR == '*') {
940 NEXT;
941 PUSH(XML_OP_ALL, token, NULL);
942 return;
943 } else {
944 ERROR(NULL, NULL, NULL,
945 "xmlCompileStepPattern : QName expected\n");
946 ctxt->error = 1;
947 goto error;
948 }
949 }
950 TODO
Daniel Veillard56de87e2005-02-16 00:22:29 +0000951 ctxt->error = 1;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000952 /* URI = xsltGetQNameURI(ctxt->elem, &token); */
953 if (token == NULL) {
954 ctxt->error = 1;
955 goto error;
956 } else {
957 name = xmlStrdup(token);
958 if (URI != NULL)
959 URL = xmlStrdup(URI);
960 }
961 PUSH(XML_OP_CHILD, name, URL);
962 } else if (xmlStrEqual(token, (const xmlChar *) "attribute")) {
963 xmlFree(token);
964 token = xmlPatScanName(ctxt);
965 if (token == NULL) {
966 ERROR(NULL, NULL, NULL,
967 "xmlCompileStepPattern : QName expected\n");
968 ctxt->error = 1;
969 goto error;
970 }
971 TODO
Daniel Veillard56de87e2005-02-16 00:22:29 +0000972 ctxt->error = 1;
Daniel Veillardb3de70c2003-12-02 22:32:15 +0000973 /* URI = xsltGetQNameURI(ctxt->elem, &token); */
974 if (token == NULL) {
975 ctxt->error = 1;
976 goto error;
977 } else {
978 name = xmlStrdup(token);
979 if (URI != NULL)
980 URL = xmlStrdup(URI);
981 }
982 PUSH(XML_OP_ATTR, name, URL);
983 } else {
984 ERROR(NULL, NULL, NULL,
985 "xmlCompileStepPattern : 'child' or 'attribute' expected\n");
986 ctxt->error = 1;
987 goto error;
988 }
989 xmlFree(token);
990 }
991 } else if (CUR == '*') {
992 NEXT;
993 PUSH(XML_OP_ALL, token, NULL);
994 } else {
995 if (name == NULL) {
996 ctxt->error = 1;
997 goto error;
998 }
999 PUSH(XML_OP_ELEM, name, NULL);
1000 }
1001 return;
1002error:
1003 if (token != NULL)
1004 xmlFree(token);
1005 if (name != NULL)
1006 xmlFree(name);
1007}
1008
1009/**
1010 * xmlCompilePathPattern:
1011 * @ctxt: the compilation context
1012 *
1013 * Compile the Path Pattern and generates a precompiled
1014 * form suitable for fast matching.
1015 *
1016 * [5] Path ::= ('.//')? ( Step '/' )* ( Step | '@' NameTest )
1017 */
1018static void
1019xmlCompilePathPattern(xmlPatParserContextPtr ctxt) {
1020 SKIP_BLANKS;
Daniel Veillard56de87e2005-02-16 00:22:29 +00001021 if (CUR == '/') {
1022 ctxt->comp->flags |= PAT_FROM_ROOT;
1023 } else if (CUR == '.') {
1024 ctxt->comp->flags |= PAT_FROM_CUR;
1025 }
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001026 if ((CUR == '/') && (NXT(1) == '/')) {
Daniel Veillard56de87e2005-02-16 00:22:29 +00001027 PUSH(XML_OP_ANCESTOR, NULL, NULL);
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001028 NEXT;
1029 NEXT;
1030 } else if ((CUR == '.') && (NXT(1) == '/') && (NXT(2) == '/')) {
Daniel Veillard56de87e2005-02-16 00:22:29 +00001031 PUSH(XML_OP_ANCESTOR, NULL, NULL);
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001032 NEXT;
1033 NEXT;
1034 NEXT;
1035 }
1036 if (CUR == '@') {
1037 TODO
Daniel Veillard56de87e2005-02-16 00:22:29 +00001038 ctxt->error = 1;
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001039 } else {
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001040 if (CUR == '/') {
1041 PUSH(XML_OP_ROOT, NULL, NULL);
1042 NEXT;
1043 }
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001044 xmlCompileStepPattern(ctxt);
1045 SKIP_BLANKS;
1046 while (CUR == '/') {
1047 if ((CUR == '/') && (NXT(1) == '/')) {
1048 PUSH(XML_OP_ANCESTOR, NULL, NULL);
1049 NEXT;
1050 NEXT;
1051 SKIP_BLANKS;
1052 xmlCompileStepPattern(ctxt);
1053 } else {
1054 PUSH(XML_OP_PARENT, NULL, NULL);
1055 NEXT;
1056 SKIP_BLANKS;
1057 if ((CUR != 0) || (CUR == '|')) {
1058 xmlCompileStepPattern(ctxt);
1059 }
1060 }
1061 }
1062 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00001063 if (CUR != 0) {
1064 ERROR5(NULL, NULL, NULL,
1065 "Failed to compile pattern %s\n", ctxt->base);
1066 ctxt->error = 1;
1067 }
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001068error:
1069 return;
1070}
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001071
1072/************************************************************************
1073 * *
1074 * The streaming code *
1075 * *
1076 ************************************************************************/
1077
1078#ifdef DEBUG_STREAMING
1079static void
1080xmlDebugStreamComp(xmlStreamCompPtr stream) {
1081 int i;
1082
1083 if (stream == NULL) {
1084 printf("Stream: NULL\n");
1085 return;
1086 }
1087 printf("Stream: %d steps\n", stream->nbStep);
1088 for (i = 0;i < stream->nbStep;i++) {
1089 if (stream->steps[i].ns != NULL) {
1090 printf("{%s}", stream->steps[i].ns);
1091 }
1092 if (stream->steps[i].name == NULL) {
1093 printf("* ");
1094 } else {
1095 printf("%s ", stream->steps[i].name);
1096 }
1097 if (stream->steps[i].flags & XML_STREAM_STEP_ROOT)
1098 printf("root ");
1099 if (stream->steps[i].flags & XML_STREAM_STEP_DESC)
1100 printf("// ");
1101 if (stream->steps[i].flags & XML_STREAM_STEP_FINAL)
1102 printf("final ");
1103 printf("\n");
1104 }
1105}
1106static void
1107xmlDebugStreamCtxt(xmlStreamCtxtPtr ctxt, int match) {
1108 int i;
1109
1110 if (ctxt == NULL) {
1111 printf("Stream: NULL\n");
1112 return;
1113 }
1114 printf("Stream: level %d, %d states: ", ctxt->level, ctxt->nbState);
1115 if (match)
1116 printf("matches\n");
1117 else
1118 printf("\n");
1119 for (i = 0;i < ctxt->nbState;i++) {
1120 if (ctxt->states[2 * i] < 0)
1121 printf(" %d: free\n", i);
1122 else {
1123 printf(" %d: step %d, level %d", i, ctxt->states[2 * i],
1124 ctxt->states[(2 * i) + 1]);
1125 if (ctxt->comp->steps[ctxt->states[2 * i]].flags &
1126 XML_STREAM_STEP_DESC)
1127 printf(" //\n");
1128 else
1129 printf("\n");
1130 }
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001131 }
1132}
1133#endif
1134/**
1135 * xmlNewStreamComp:
1136 * @size: the number of expected steps
1137 *
1138 * build a new compiled pattern for streaming
1139 *
1140 * Returns the new structure or NULL in case of error.
1141 */
1142static xmlStreamCompPtr
1143xmlNewStreamComp(int size) {
1144 xmlStreamCompPtr cur;
1145
1146 if (size < 4)
1147 size = 4;
1148
1149 cur = (xmlStreamCompPtr) xmlMalloc(sizeof(xmlStreamComp));
1150 if (cur == NULL) {
1151 ERROR(NULL, NULL, NULL,
1152 "xmlNewStreamComp: malloc failed\n");
1153 return(NULL);
1154 }
1155 memset(cur, 0, sizeof(xmlStreamComp));
1156 cur->steps = (xmlStreamStepPtr) xmlMalloc(size * sizeof(xmlStreamStep));
1157 if (cur->steps == NULL) {
1158 xmlFree(cur);
1159 ERROR(NULL, NULL, NULL,
1160 "xmlNewStreamComp: malloc failed\n");
1161 return(NULL);
1162 }
1163 cur->nbStep = 0;
1164 cur->maxStep = size;
1165 return(cur);
1166}
1167
1168/**
1169 * xmlFreeStreamComp:
1170 * @comp: the compiled pattern for streaming
1171 *
1172 * Free the compiled pattern for streaming
1173 */
1174static void
1175xmlFreeStreamComp(xmlStreamCompPtr comp) {
1176 if (comp != NULL) {
1177 if (comp->steps != NULL)
1178 xmlFree(comp->steps);
1179 if (comp->dict != NULL)
1180 xmlDictFree(comp->dict);
1181 xmlFree(comp);
1182 }
1183}
1184
1185/**
1186 * xmlStreamCompAddStep:
1187 * @comp: the compiled pattern for streaming
1188 * @name: the first string, the name, or NULL for *
1189 * @ns: the second step, the namespace name
1190 * @flags: the flags for that step
1191 *
1192 * Add a new step to the compiled pattern
1193 *
1194 * Returns -1 in case of error or the step index if successful
1195 */
1196static int
1197xmlStreamCompAddStep(xmlStreamCompPtr comp, const xmlChar *name,
1198 const xmlChar *ns, int flags) {
1199 xmlStreamStepPtr cur;
1200
1201 if (comp->nbStep >= comp->maxStep) {
1202 cur = (xmlStreamStepPtr) xmlRealloc(comp->steps,
1203 comp->maxStep * 2 * sizeof(xmlStreamStep));
1204 if (cur == NULL) {
1205 ERROR(NULL, NULL, NULL,
1206 "xmlNewStreamComp: malloc failed\n");
1207 return(-1);
1208 }
1209 comp->steps = cur;
1210 comp->maxStep *= 2;
1211 }
1212 cur = &comp->steps[comp->nbStep++];
1213 cur->flags = flags;
1214 cur->name = name;
1215 cur->ns = ns;
1216 return(comp->nbStep - 1);
1217}
1218
1219/**
1220 * xmlStreamCompile:
1221 * @comp: the precompiled pattern
1222 *
1223 * Tries to stream compile a pattern
1224 *
1225 * Returns -1 in case of failure and 0 in case of success.
1226 */
1227static int
1228xmlStreamCompile(xmlPatternPtr comp) {
1229 xmlStreamCompPtr stream;
1230 int i, s = 0, root = 0, desc = 0;
1231
1232 if ((comp == NULL) || (comp->steps == NULL))
1233 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +00001234 /*
1235 * special case for .
1236 */
1237 if ((comp->nbStep == 1) &&
1238 (comp->steps[0].op == XML_OP_ELEM) &&
1239 (comp->steps[0].value == NULL) &&
1240 (comp->steps[0].value2 == NULL)) {
1241 stream = xmlNewStreamComp(0);
1242 if (stream == NULL)
1243 return(-1);
1244 comp->stream = stream;
1245 return(0);
1246 }
1247
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001248 stream = xmlNewStreamComp((comp->nbStep / 2) + 1);
1249 if (stream == NULL)
1250 return(-1);
1251 if (comp->dict != NULL) {
1252 stream->dict = comp->dict;
1253 xmlDictReference(stream->dict);
1254 }
1255 for (i = 0;i < comp->nbStep;i++) {
1256 switch (comp->steps[i].op) {
1257 case XML_OP_END:
1258 break;
1259 case XML_OP_ROOT:
1260 if (i != 0)
1261 goto error;
1262 root = 1;
1263 break;
1264 case XML_OP_CHILD:
1265 case XML_OP_ATTR:
1266 case XML_OP_NS:
1267 goto error;
1268 case XML_OP_ELEM:
1269 s = xmlStreamCompAddStep(stream, comp->steps[i].value,
1270 comp->steps[i].value2, desc);
1271 desc = 0;
1272 if (s < 0)
1273 goto error;
1274 break;
1275 case XML_OP_ALL:
1276 s = xmlStreamCompAddStep(stream, NULL, NULL, desc);
1277 desc = 0;
1278 if (s < 0)
1279 goto error;
1280 break;
1281 case XML_OP_PARENT:
1282 break;
1283 case XML_OP_ANCESTOR:
1284 desc = XML_STREAM_STEP_DESC;
1285 break;
1286 }
1287 }
1288 stream->steps[s].flags |= XML_STREAM_STEP_FINAL;
1289 if (root)
1290 stream->steps[0].flags |= XML_STREAM_STEP_ROOT;
1291#ifdef DEBUG_STREAMING
1292 xmlDebugStreamComp(stream);
1293#endif
1294 comp->stream = stream;
1295 return(0);
1296error:
1297 xmlFreeStreamComp(stream);
1298 return(0);
1299}
1300
1301/**
1302 * xmlNewStreamCtxt:
1303 * @size: the number of expected states
1304 *
1305 * build a new stream context
1306 *
1307 * Returns the new structure or NULL in case of error.
1308 */
1309static xmlStreamCtxtPtr
1310xmlNewStreamCtxt(xmlStreamCompPtr stream) {
1311 xmlStreamCtxtPtr cur;
1312
1313 cur = (xmlStreamCtxtPtr) xmlMalloc(sizeof(xmlStreamCtxt));
1314 if (cur == NULL) {
1315 ERROR(NULL, NULL, NULL,
1316 "xmlNewStreamCtxt: malloc failed\n");
1317 return(NULL);
1318 }
1319 memset(cur, 0, sizeof(xmlStreamCtxt));
1320 cur->states = (int *) xmlMalloc(4 * 2 * sizeof(int));
1321 if (cur->states == NULL) {
1322 xmlFree(cur);
1323 ERROR(NULL, NULL, NULL,
1324 "xmlNewStreamCtxt: malloc failed\n");
1325 return(NULL);
1326 }
1327 cur->nbState = 0;
1328 cur->maxState = 4;
1329 cur->level = 0;
1330 cur->comp = stream;
1331 return(cur);
1332}
1333
1334/**
1335 * xmlFreeStreamCtxt:
1336 * @stream: the stream context
1337 *
1338 * Free the stream context
1339 */
1340void
1341xmlFreeStreamCtxt(xmlStreamCtxtPtr stream) {
Daniel Veillard2b2e02d2005-02-05 23:20:22 +00001342 xmlStreamCtxtPtr next;
1343
1344 while (stream != NULL) {
1345 next = stream->next;
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001346 if (stream->states != NULL)
1347 xmlFree(stream->states);
1348 xmlFree(stream);
Daniel Veillard2b2e02d2005-02-05 23:20:22 +00001349 stream = next;
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001350 }
1351}
1352
1353/**
1354 * xmlStreamCtxtAddState:
1355 * @comp: the stream context
1356 * @idx: the step index for that streaming state
1357 *
1358 * Add a new state to the stream context
1359 *
1360 * Returns -1 in case of error or the state index if successful
1361 */
1362static int
1363xmlStreamCtxtAddState(xmlStreamCtxtPtr comp, int idx, int level) {
1364 int i;
1365 for (i = 0;i < comp->nbState;i++) {
1366 if (comp->states[2 * i] < 0) {
1367 comp->states[2 * i] = idx;
1368 comp->states[2 * i + 1] = level;
1369 return(i);
1370 }
1371 }
1372 if (comp->nbState >= comp->maxState) {
1373 int *cur;
1374
1375 cur = (int *) xmlRealloc(comp->states,
1376 comp->maxState * 4 * sizeof(int));
1377 if (cur == NULL) {
1378 ERROR(NULL, NULL, NULL,
1379 "xmlNewStreamCtxt: malloc failed\n");
1380 return(-1);
1381 }
1382 comp->states = cur;
1383 comp->maxState *= 2;
1384 }
1385 comp->states[2 * comp->nbState] = idx;
1386 comp->states[2 * comp->nbState++ + 1] = level;
1387 return(comp->nbState - 1);
1388}
1389
1390/**
1391 * xmlStreamPush:
1392 * @stream: the stream context
1393 * @name: the current name
1394 * @ns: the namespace name
1395 *
1396 * push new data onto the stream. NOTE: if the call xmlPatterncompile()
1397 * indicated a dictionnary, then strings for name and ns will be expected
1398 * to come from the dictionary.
1399 * Both @name and @ns being NULL means the / i.e. the root of the document.
1400 * This can also act as a reset.
1401 *
1402 * Returns: -1 in case of error, 1 if the current state in the stream is a
1403 * match and 0 otherwise.
1404 */
1405int
1406xmlStreamPush(xmlStreamCtxtPtr stream,
1407 const xmlChar *name, const xmlChar *ns) {
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001408 int ret = 0, err = 0, tmp, i, m, match, step, desc, final;
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001409 xmlStreamCompPtr comp;
Daniel Veillard2b2e02d2005-02-05 23:20:22 +00001410#ifdef DEBUG_STREAMING
1411 xmlStreamCtxtPtr orig = stream;
1412#endif
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001413
1414 if ((stream == NULL) || (stream->nbState < 0))
1415 return(-1);
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001416
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001417 while (stream != NULL) {
1418 comp = stream->comp;
1419 if ((name == NULL) && (ns == NULL)) {
1420 stream->nbState = 0;
1421 stream->level = 0;
1422 if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) {
1423 tmp = xmlStreamCtxtAddState(stream, 0, 0);
1424 if (tmp < 0)
1425 err++;
Daniel Veillard56de87e2005-02-16 00:22:29 +00001426 if (comp->nbStep == 0)
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001427 ret = 1;
Daniel Veillard2b2e02d2005-02-05 23:20:22 +00001428 stream = stream->next;
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001429 continue; /* while */
1430 }
Daniel Veillard2b2e02d2005-02-05 23:20:22 +00001431 stream = stream->next;
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001432 continue; /* while */
1433 }
1434 /*
1435 * Check evolution of existing states
1436 */
1437 m = stream->nbState;
1438 for (i = 0;i < m;i++) {
1439 match = 0;
1440 step = stream->states[2 * i];
1441 /* dead states */
1442 if (step < 0) continue;
1443 /* skip new states just added */
1444 if (stream->states[(2 * i) + 1] > stream->level)
1445 continue;
1446 /* skip continuations */
1447 desc = comp->steps[step].flags & XML_STREAM_STEP_DESC;
1448 if ((stream->states[(2 * i) + 1] < stream->level) && (!desc))
1449 continue;
1450
1451 /* discard old states */
1452 /* something needed about old level discarded */
1453
1454 if (comp->dict) {
1455 if (comp->steps[step].name == NULL) {
1456 if (comp->steps[step].ns == NULL)
1457 match = 1;
1458 else
1459 match = (comp->steps[step].ns == ns);
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001460 } else {
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001461 match = ((comp->steps[step].name == name) &&
1462 (comp->steps[step].ns == ns));
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001463 }
1464 } else {
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001465 if (comp->steps[step].name == NULL) {
1466 if (comp->steps[step].ns == NULL)
1467 match = 1;
1468 else
1469 match = xmlStrEqual(comp->steps[step].ns, ns);
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001470 } else {
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001471 match = ((xmlStrEqual(comp->steps[step].name, name)) &&
1472 (xmlStrEqual(comp->steps[step].ns, ns)));
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001473 }
1474 }
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001475 if (match) {
1476 final = comp->steps[step].flags & XML_STREAM_STEP_FINAL;
1477 if (desc) {
1478 if (final) {
1479 ret = 1;
1480 } else {
1481 /* descending match create a new state */
1482 xmlStreamCtxtAddState(stream, step + 1,
1483 stream->level + 1);
1484 }
1485 } else {
1486 if (final) {
1487 ret = 1;
1488 } else {
1489 xmlStreamCtxtAddState(stream, step + 1,
1490 stream->level + 1);
1491 }
1492 }
1493 }
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001494 }
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001495
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001496 /*
1497 * Check creating a new state.
1498 */
1499 stream->level++;
1500 if (!(comp->steps[0].flags & XML_STREAM_STEP_ROOT)) {
1501 match = 0;
1502 if (comp->dict) {
1503 if (comp->steps[0].name == NULL) {
1504 if (comp->steps[0].ns == NULL)
1505 match = 1;
1506 else
1507 match = (comp->steps[0].ns == ns);
1508 } else {
1509 match = ((comp->steps[0].name == name) &&
1510 (comp->steps[0].ns == ns));
1511 }
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001512 } else {
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001513 if (comp->steps[0].name == NULL) {
1514 if (comp->steps[0].ns == NULL)
1515 match = 1;
1516 else
1517 match = xmlStrEqual(comp->steps[0].ns, ns);
1518 } else {
1519 match = ((xmlStrEqual(comp->steps[0].name, name)) &&
1520 (xmlStrEqual(comp->steps[0].ns, ns)));
1521 }
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001522 }
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001523 if (match) {
1524 if (comp->steps[0].flags & XML_STREAM_STEP_FINAL)
1525 ret = 1;
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001526 else
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001527 xmlStreamCtxtAddState(stream, 1, stream->level);
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001528 }
1529 }
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001530
1531 stream = stream->next;
1532 } /* while stream != NULL */
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001533
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001534 if (err > 0)
1535 ret = -1;
Daniel Veillard2b2e02d2005-02-05 23:20:22 +00001536#ifdef DEBUG_STREAMING
1537 xmlDebugStreamCtxt(orig, ret);
1538#endif
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001539 return(ret);
1540}
1541
1542/**
1543 * xmlStreamPop:
1544 * @stream: the stream context
1545 *
1546 * push one level from the stream.
1547 *
1548 * Returns: -1 in case of error, 0 otherwise.
1549 */
1550int
1551xmlStreamPop(xmlStreamCtxtPtr stream) {
Daniel Veillard9740d1d2005-02-01 16:21:43 +00001552 int i, m;
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001553 int ret;
Daniel Veillard9740d1d2005-02-01 16:21:43 +00001554
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001555 if (stream == NULL)
1556 return(-1);
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001557 ret = 0;
1558 while (stream != NULL) {
1559 stream->level--;
1560 if (stream->level < 0)
1561 ret = -1;
1562
1563 /*
1564 * Check evolution of existing states
1565 */
1566 m = stream->nbState;
1567 for (i = 0;i < m;i++) {
1568 if (stream->states[(2 * i)] < 0) break;
1569 /* discard obsoleted states */
1570 if (stream->states[(2 * i) + 1] > stream->level)
1571 stream->states[(2 * i)] = -1;
1572 }
1573 stream = stream->next;
Daniel Veillard9740d1d2005-02-01 16:21:43 +00001574 }
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001575 return(0);
1576}
1577
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001578/************************************************************************
1579 * *
1580 * The public interfaces *
1581 * *
1582 ************************************************************************/
1583
1584/**
1585 * xmlPatterncompile:
1586 * @pattern: the pattern to compile
1587 * @dict: an optional dictionnary for interned strings
1588 * @flags: compilation flags, undefined yet
Daniel Veillardffa7b7e2003-12-05 16:10:21 +00001589 * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001590 *
Daniel Veillardffa7b7e2003-12-05 16:10:21 +00001591 * Compile a pattern.
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001592 *
1593 * Returns the compiled for of the pattern or NULL in case of error
1594 */
1595xmlPatternPtr
Daniel Veillard427174f2003-12-10 10:42:59 +00001596xmlPatterncompile(const xmlChar *pattern, xmlDict *dict,
1597 int flags ATTRIBUTE_UNUSED,
Daniel Veillardffa7b7e2003-12-05 16:10:21 +00001598 const xmlChar **namespaces) {
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001599 xmlPatternPtr ret = NULL, cur;
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001600 xmlPatParserContextPtr ctxt = NULL;
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001601 const xmlChar *or, *start;
1602 xmlChar *tmp = NULL;
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001603
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001604 if (pattern == NULL)
1605 return(NULL);
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001606
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001607 start = pattern;
Daniel Veillard2b2e02d2005-02-05 23:20:22 +00001608 or = start;
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001609 while (*or != 0) {
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001610 tmp = NULL;
1611 while ((*or != 0) && (*or != '|')) or++;
1612 if (*or == 0)
1613 ctxt = xmlNewPatParserContext(start, dict, namespaces);
1614 else {
1615 tmp = xmlStrndup(start, or - start);
1616 if (tmp != NULL) {
1617 ctxt = xmlNewPatParserContext(tmp, dict, namespaces);
1618 }
1619 or++;
1620 }
1621 if (ctxt == NULL) goto error;
1622 cur = xmlNewPattern();
1623 if (cur == NULL) goto error;
1624 if (ret == NULL)
1625 ret = cur;
1626 else {
1627 cur->next = ret->next;
1628 ret->next = cur;
1629 }
1630 ctxt->comp = cur;
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001631
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001632 xmlCompilePathPattern(ctxt);
Daniel Veillard56de87e2005-02-16 00:22:29 +00001633 if (ctxt->error != 0)
1634 goto error;
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001635 xmlFreePatParserContext(ctxt);
1636
1637
1638 xmlStreamCompile(cur);
1639 if (xmlReversePattern(cur) < 0)
1640 goto error;
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001641 if (tmp != NULL) {
1642 xmlFree(tmp);
1643 tmp = NULL;
1644 }
Daniel Veillard2b2e02d2005-02-05 23:20:22 +00001645 start = or;
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001646 }
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001647 return(ret);
1648error:
1649 if (ctxt != NULL) xmlFreePatParserContext(ctxt);
1650 if (ret != NULL) xmlFreePattern(ret);
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001651 if (tmp != NULL) xmlFree(tmp);
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001652 return(NULL);
1653}
1654
1655/**
1656 * xmlPatternMatch:
1657 * @comp: the precompiled pattern
1658 * @node: a node
1659 *
1660 * Test wether the node matches the pattern
1661 *
1662 * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
1663 */
1664int
1665xmlPatternMatch(xmlPatternPtr comp, xmlNodePtr node)
1666{
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001667 int ret = 0;
1668
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001669 if ((comp == NULL) || (node == NULL))
1670 return(-1);
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001671
1672 while (comp != NULL) {
1673 ret = xmlPatMatch(comp, node);
1674 if (ret != 0)
1675 return(ret);
1676 comp = comp->next;
1677 }
1678 return(ret);
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001679}
1680
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001681/**
1682 * xmlPatternGetStreamCtxt:
1683 * @comp: the precompiled pattern
1684 *
1685 * Get a streaming context for that pattern
1686 * Use xmlFreeStreamCtxt to free the context.
1687 *
1688 * Returns a pointer to the context or NULL in case of failure
1689 */
1690xmlStreamCtxtPtr
1691xmlPatternGetStreamCtxt(xmlPatternPtr comp)
1692{
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001693 xmlStreamCtxtPtr ret = NULL, cur;
1694
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001695 if ((comp == NULL) || (comp->stream == NULL))
1696 return(NULL);
Daniel Veillardf1f08cf2005-02-05 16:35:04 +00001697
1698 while (comp != NULL) {
1699 if (comp->stream == NULL)
1700 goto failed;
1701 cur = xmlNewStreamCtxt(comp->stream);
1702 if (cur == NULL)
1703 goto failed;
1704 if (ret == NULL)
1705 ret = cur;
1706 else {
1707 cur->next = ret->next;
1708 ret->next = cur;
1709 }
1710 comp = comp->next;
1711 }
1712 return(ret);
1713failed:
1714 xmlFreeStreamCtxt(ret);
1715 return(NULL);
Daniel Veillard2fc6df92005-01-30 18:42:55 +00001716}
1717
Daniel Veillard56de87e2005-02-16 00:22:29 +00001718/**
1719 * xmlPatternStreamable:
1720 * @comp: the precompiled pattern
1721 *
1722 * Check if the pattern is streamable i.e. xmlPatternGetStreamCtxt()
1723 * should work.
1724 *
1725 * Returns 1 if streamable, 0 if not and -1 in case of error.
1726 */
1727int
1728xmlPatternStreamable(xmlPatternPtr comp) {
1729 if (comp == NULL)
1730 return(-1);
1731 while (comp != NULL) {
1732 if (comp->stream == NULL)
1733 return(0);
1734 comp = comp->next;
1735 }
1736 return(1);
1737}
1738
1739/**
1740 * xmlPatternMaxDepth:
1741 * @comp: the precompiled pattern
1742 *
1743 * Check the maximum depth reachable by a pattern
1744 *
1745 * Returns -2 if no limit (using //), otherwise the depth,
1746 * and -1 in case of error
1747 */
1748int
1749xmlPatternMaxDepth(xmlPatternPtr comp) {
1750 int ret = 0, i;
1751 if (comp == NULL)
1752 return(-1);
1753 while (comp != NULL) {
1754 if (comp->stream == NULL)
1755 return(-1);
1756 for (i = 0;i < comp->stream->nbStep;i++)
1757 if (comp->stream->steps[i].flags & XML_STREAM_STEP_DESC)
1758 return(-2);
1759 if (comp->stream->nbStep > ret)
1760 ret = comp->stream->nbStep;
1761 comp = comp->next;
1762 }
1763 return(ret);
1764
1765}
1766
1767/**
1768 * xmlPatternFromRoot:
1769 * @comp: the precompiled pattern
1770 *
1771 * Check if the pattern must be looked at from the root.
1772 *
1773 * Returns 1 if true, 0 if false and -1 in case of error
1774 */
1775int
1776xmlPatternFromRoot(xmlPatternPtr comp) {
1777 if (comp == NULL)
1778 return(-1);
1779 while (comp != NULL) {
1780 if (comp->stream == NULL)
1781 return(-1);
1782 if (comp->flags & PAT_FROM_ROOT)
1783 return(1);
1784 comp = comp->next;
1785 }
1786 return(0);
1787
1788}
Daniel Veillardb3de70c2003-12-02 22:32:15 +00001789#endif /* LIBXML_PATTERN_ENABLED */