File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / pattern.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:58 2012 UTC (12 years, 5 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_7_8, HEAD
libxml2

    1: /*
    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: 
   14: /*
   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 .
   22:  * - get rid of the "compile" starting with lowercase
   23:  * - DONE (2006-05-16): get rid of the Strdup/Strndup in case of dictionary
   24:  */
   25: 
   26: #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: 
   38: #ifdef LIBXML_PATTERN_ENABLED
   39: 
   40: /* #define DEBUG_STREAMING */
   41: 
   42: #define ERROR(a, b, c, d)
   43: #define ERROR5(a, b, c, d, e)
   44: 
   45: #define XML_STREAM_STEP_DESC	1
   46: #define XML_STREAM_STEP_FINAL	2
   47: #define XML_STREAM_STEP_ROOT	4
   48: #define XML_STREAM_STEP_ATTR	8
   49: #define XML_STREAM_STEP_NODE	16
   50: #define XML_STREAM_STEP_IN_SET	32
   51: 
   52: /*
   53: * NOTE: Those private flags (XML_STREAM_xxx) are used
   54: *   in _xmlStreamCtxt->flag. They extend the public
   55: *   xmlPatternFlags, so be carefull not to interfere with the
   56: *   reserved values for xmlPatternFlags. 
   57: */
   58: #define XML_STREAM_FINAL_IS_ANY_NODE 1<<14
   59: #define XML_STREAM_FROM_ROOT 1<<15
   60: #define XML_STREAM_DESC 1<<16
   61: 
   62: /*
   63: * XML_STREAM_ANY_NODE is used for comparison against
   64: * xmlElementType enums, to indicate a node of any type.
   65: */
   66: #define XML_STREAM_ANY_NODE 100
   67: 
   68: #define XML_PATTERN_NOTPATTERN  (XML_PATTERN_XPATH | \
   69: 				 XML_PATTERN_XSSEL | \
   70: 				 XML_PATTERN_XSFIELD)
   71: 
   72: #define XML_STREAM_XS_IDC(c) ((c)->flags & \
   73:     (XML_PATTERN_XSSEL | XML_PATTERN_XSFIELD))
   74: 
   75: #define XML_STREAM_XS_IDC_SEL(c) ((c)->flags & XML_PATTERN_XSSEL)
   76: 
   77: #define XML_STREAM_XS_IDC_FIELD(c) ((c)->flags & XML_PATTERN_XSFIELD)
   78: 
   79: #define XML_PAT_COPY_NSNAME(c, r, nsname) \
   80:     if ((c)->comp->dict) \
   81: 	r = (xmlChar *) xmlDictLookup((c)->comp->dict, BAD_CAST nsname, -1); \
   82:     else r = xmlStrdup(BAD_CAST nsname);
   83: 
   84: #define XML_PAT_FREE_STRING(c, r) if ((c)->comp->dict == NULL) xmlFree(r);
   85: 
   86: typedef struct _xmlStreamStep xmlStreamStep;
   87: typedef xmlStreamStep *xmlStreamStepPtr;
   88: struct _xmlStreamStep {
   89:     int flags;			/* properties of that step */
   90:     const xmlChar *name;	/* first string value if NULL accept all */
   91:     const xmlChar *ns;		/* second string value */
   92:     int nodeType;		/* type of node */
   93: };
   94: 
   95: typedef struct _xmlStreamComp xmlStreamComp;
   96: typedef xmlStreamComp *xmlStreamCompPtr;
   97: struct _xmlStreamComp {
   98:     xmlDict *dict;		/* the dictionary if any */
   99:     int nbStep;			/* number of steps in the automata */
  100:     int maxStep;		/* allocated number of steps */
  101:     xmlStreamStepPtr steps;	/* the array of steps */
  102:     int flags;
  103: };
  104: 
  105: struct _xmlStreamCtxt {
  106:     struct _xmlStreamCtxt *next;/* link to next sub pattern if | */
  107:     xmlStreamCompPtr comp;	/* the compiled stream */
  108:     int nbState;		/* number of states in the automata */
  109:     int maxState;		/* allocated number of states */
  110:     int level;			/* how deep are we ? */
  111:     int *states;		/* the array of step indexes */
  112:     int flags;			/* validation options */
  113:     int blockLevel;
  114: };
  115: 
  116: static void xmlFreeStreamComp(xmlStreamCompPtr comp);
  117: 
  118: /*
  119:  * Types are private:
  120:  */
  121: 
  122: typedef enum {
  123:     XML_OP_END=0,
  124:     XML_OP_ROOT,
  125:     XML_OP_ELEM,
  126:     XML_OP_CHILD,
  127:     XML_OP_ATTR,
  128:     XML_OP_PARENT,
  129:     XML_OP_ANCESTOR,
  130:     XML_OP_NS,
  131:     XML_OP_ALL
  132: } xmlPatOp;
  133: 
  134: 
  135: typedef struct _xmlStepState xmlStepState;
  136: typedef xmlStepState *xmlStepStatePtr;
  137: struct _xmlStepState {
  138:     int step;
  139:     xmlNodePtr node;
  140: };
  141: 
  142: typedef struct _xmlStepStates xmlStepStates;
  143: typedef xmlStepStates *xmlStepStatesPtr;
  144: struct _xmlStepStates {
  145:     int nbstates;
  146:     int maxstates;
  147:     xmlStepStatePtr states;
  148: };
  149: 
  150: typedef struct _xmlStepOp xmlStepOp;
  151: typedef xmlStepOp *xmlStepOpPtr;
  152: struct _xmlStepOp {
  153:     xmlPatOp op;
  154:     const xmlChar *value;
  155:     const xmlChar *value2; /* The namespace name */
  156: };
  157: 
  158: #define PAT_FROM_ROOT	(1<<8)
  159: #define PAT_FROM_CUR	(1<<9)
  160: 
  161: struct _xmlPattern {
  162:     void *data;    		/* the associated template */
  163:     xmlDictPtr dict;		/* the optional dictionary */
  164:     struct _xmlPattern *next;	/* next pattern if | is used */
  165:     const xmlChar *pattern;	/* the pattern */
  166:     int flags;			/* flags */
  167:     int nbStep;
  168:     int maxStep;
  169:     xmlStepOpPtr steps;        /* ops for computation */
  170:     xmlStreamCompPtr stream;	/* the streaming data if any */
  171: };
  172: 
  173: typedef struct _xmlPatParserContext xmlPatParserContext;
  174: typedef xmlPatParserContext *xmlPatParserContextPtr;
  175: struct _xmlPatParserContext {
  176:     const xmlChar *cur;			/* the current char being parsed */
  177:     const xmlChar *base;		/* the full expression */
  178:     int	           error;		/* error code */
  179:     xmlDictPtr     dict;		/* the dictionary if any */
  180:     xmlPatternPtr  comp;		/* the result */
  181:     xmlNodePtr     elem;		/* the current node if any */    
  182:     const xmlChar **namespaces;		/* the namespaces definitions */
  183:     int   nb_namespaces;		/* the number of namespaces */
  184: };
  185: 
  186: /************************************************************************
  187:  * 									*
  188:  * 			Type functions 					*
  189:  * 									*
  190:  ************************************************************************/
  191: 
  192: /**
  193:  * xmlNewPattern:
  194:  *
  195:  * Create a new XSLT Pattern
  196:  *
  197:  * Returns the newly allocated xmlPatternPtr or NULL in case of error
  198:  */
  199: static xmlPatternPtr
  200: xmlNewPattern(void) {
  201:     xmlPatternPtr cur;
  202: 
  203:     cur = (xmlPatternPtr) xmlMalloc(sizeof(xmlPattern));
  204:     if (cur == NULL) {
  205: 	ERROR(NULL, NULL, NULL,
  206: 		"xmlNewPattern : malloc failed\n");
  207: 	return(NULL);
  208:     }
  209:     memset(cur, 0, sizeof(xmlPattern));
  210:     cur->maxStep = 10;
  211:     cur->steps = (xmlStepOpPtr) xmlMalloc(cur->maxStep * sizeof(xmlStepOp));
  212:     if (cur->steps == NULL) {
  213:         xmlFree(cur);
  214: 	ERROR(NULL, NULL, NULL,
  215: 		"xmlNewPattern : malloc failed\n");
  216: 	return(NULL);
  217:     }
  218:     return(cur);
  219: }
  220: 
  221: /**
  222:  * xmlFreePattern:
  223:  * @comp:  an XSLT comp
  224:  *
  225:  * Free up the memory allocated by @comp
  226:  */
  227: void
  228: xmlFreePattern(xmlPatternPtr comp) {
  229:     xmlStepOpPtr op;
  230:     int i;
  231: 
  232:     if (comp == NULL)
  233: 	return;
  234:     if (comp->next != NULL)
  235:         xmlFreePattern(comp->next);
  236:     if (comp->stream != NULL)
  237:         xmlFreeStreamComp(comp->stream);
  238:     if (comp->pattern != NULL)
  239: 	xmlFree((xmlChar *)comp->pattern);
  240:     if (comp->steps != NULL) {
  241:         if (comp->dict == NULL) {
  242: 	    for (i = 0;i < comp->nbStep;i++) {
  243: 		op = &comp->steps[i];
  244: 		if (op->value != NULL)
  245: 		    xmlFree((xmlChar *) op->value);
  246: 		if (op->value2 != NULL)
  247: 		    xmlFree((xmlChar *) op->value2);
  248: 	    }
  249: 	}
  250: 	xmlFree(comp->steps);
  251:     }
  252:     if (comp->dict != NULL)
  253:         xmlDictFree(comp->dict);
  254: 
  255:     memset(comp, -1, sizeof(xmlPattern));
  256:     xmlFree(comp);
  257: }
  258: 
  259: /**
  260:  * xmlFreePatternList:
  261:  * @comp:  an XSLT comp list
  262:  *
  263:  * Free up the memory allocated by all the elements of @comp
  264:  */
  265: void
  266: xmlFreePatternList(xmlPatternPtr comp) {
  267:     xmlPatternPtr cur;
  268: 
  269:     while (comp != NULL) {
  270: 	cur = comp;
  271: 	comp = comp->next;
  272: 	cur->next = NULL;
  273: 	xmlFreePattern(cur);
  274:     }
  275: }
  276: 
  277: /**
  278:  * xmlNewPatParserContext:
  279:  * @pattern:  the pattern context
  280:  * @dict:  the inherited dictionary or NULL
  281:  * @namespaces: the prefix definitions, array of [URI, prefix] terminated
  282:  *              with [NULL, NULL] or NULL if no namespace is used
  283:  *
  284:  * Create a new XML pattern parser context
  285:  *
  286:  * Returns the newly allocated xmlPatParserContextPtr or NULL in case of error
  287:  */
  288: static xmlPatParserContextPtr
  289: xmlNewPatParserContext(const xmlChar *pattern, xmlDictPtr dict,
  290:                        const xmlChar **namespaces) {
  291:     xmlPatParserContextPtr cur;
  292: 
  293:     if (pattern == NULL)
  294:         return(NULL);
  295: 
  296:     cur = (xmlPatParserContextPtr) xmlMalloc(sizeof(xmlPatParserContext));
  297:     if (cur == NULL) {
  298: 	ERROR(NULL, NULL, NULL,
  299: 		"xmlNewPatParserContext : malloc failed\n");
  300: 	return(NULL);
  301:     }
  302:     memset(cur, 0, sizeof(xmlPatParserContext));
  303:     cur->dict = dict;
  304:     cur->cur = pattern;
  305:     cur->base = pattern;
  306:     if (namespaces != NULL) {
  307:         int i;
  308: 	for (i = 0;namespaces[2 * i] != NULL;i++);
  309:         cur->nb_namespaces = i;
  310:     } else {
  311:         cur->nb_namespaces = 0;
  312:     }
  313:     cur->namespaces = namespaces;
  314:     return(cur);
  315: }
  316: 
  317: /**
  318:  * xmlFreePatParserContext:
  319:  * @ctxt:  an XSLT parser context
  320:  *
  321:  * Free up the memory allocated by @ctxt
  322:  */
  323: static void
  324: xmlFreePatParserContext(xmlPatParserContextPtr ctxt) {
  325:     if (ctxt == NULL)
  326: 	return;    
  327:     memset(ctxt, -1, sizeof(xmlPatParserContext));
  328:     xmlFree(ctxt);
  329: }
  330: 
  331: /**
  332:  * xmlPatternAdd:
  333:  * @comp:  the compiled match expression
  334:  * @op:  an op
  335:  * @value:  the first value
  336:  * @value2:  the second value
  337:  *
  338:  * Add a step to an XSLT Compiled Match
  339:  *
  340:  * Returns -1 in case of failure, 0 otherwise.
  341:  */
  342: static int
  343: xmlPatternAdd(xmlPatParserContextPtr ctxt ATTRIBUTE_UNUSED,
  344:                 xmlPatternPtr comp,
  345:                 xmlPatOp op, xmlChar * value, xmlChar * value2)
  346: {
  347:     if (comp->nbStep >= comp->maxStep) {
  348:         xmlStepOpPtr temp;
  349: 	temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
  350: 	                                 sizeof(xmlStepOp));
  351:         if (temp == NULL) {
  352: 	    ERROR(ctxt, NULL, NULL,
  353: 			     "xmlPatternAdd: realloc failed\n");
  354: 	    return (-1);
  355: 	}
  356: 	comp->steps = temp;
  357: 	comp->maxStep *= 2;
  358:     }
  359:     comp->steps[comp->nbStep].op = op;
  360:     comp->steps[comp->nbStep].value = value;
  361:     comp->steps[comp->nbStep].value2 = value2;
  362:     comp->nbStep++;
  363:     return (0);
  364: }
  365: 
  366: #if 0
  367: /**
  368:  * xsltSwapTopPattern:
  369:  * @comp:  the compiled match expression
  370:  *
  371:  * reverse the two top steps.
  372:  */
  373: static void
  374: xsltSwapTopPattern(xmlPatternPtr comp) {
  375:     int i;
  376:     int j = comp->nbStep - 1;
  377: 
  378:     if (j > 0) {
  379: 	register const xmlChar *tmp;
  380: 	register xmlPatOp op;
  381: 	i = j - 1;
  382: 	tmp = comp->steps[i].value;
  383: 	comp->steps[i].value = comp->steps[j].value;
  384: 	comp->steps[j].value = tmp;
  385: 	tmp = comp->steps[i].value2;
  386: 	comp->steps[i].value2 = comp->steps[j].value2;
  387: 	comp->steps[j].value2 = tmp;
  388: 	op = comp->steps[i].op;
  389: 	comp->steps[i].op = comp->steps[j].op;
  390: 	comp->steps[j].op = op;
  391:     }
  392: }
  393: #endif
  394: 
  395: /**
  396:  * xmlReversePattern:
  397:  * @comp:  the compiled match expression
  398:  *
  399:  * reverse all the stack of expressions
  400:  *
  401:  * returns 0 in case of success and -1 in case of error.
  402:  */
  403: static int
  404: xmlReversePattern(xmlPatternPtr comp) {
  405:     int i, j;
  406: 
  407:     /*
  408:      * remove the leading // for //a or .//a
  409:      */
  410:     if ((comp->nbStep > 0) && (comp->steps[0].op == XML_OP_ANCESTOR)) {
  411:         for (i = 0, j = 1;j < comp->nbStep;i++,j++) {
  412: 	    comp->steps[i].value = comp->steps[j].value;
  413: 	    comp->steps[i].value2 = comp->steps[j].value2;
  414: 	    comp->steps[i].op = comp->steps[j].op;
  415: 	}
  416: 	comp->nbStep--;
  417:     }
  418:     if (comp->nbStep >= comp->maxStep) {
  419:         xmlStepOpPtr temp;
  420: 	temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
  421: 	                                 sizeof(xmlStepOp));
  422:         if (temp == NULL) {
  423: 	    ERROR(ctxt, NULL, NULL,
  424: 			     "xmlReversePattern: realloc failed\n");
  425: 	    return (-1);
  426: 	}
  427: 	comp->steps = temp;
  428: 	comp->maxStep *= 2;
  429:     }
  430:     i = 0;
  431:     j = comp->nbStep - 1;
  432:     while (j > i) {
  433: 	register const xmlChar *tmp;
  434: 	register xmlPatOp op;
  435: 	tmp = comp->steps[i].value;
  436: 	comp->steps[i].value = comp->steps[j].value;
  437: 	comp->steps[j].value = tmp;
  438: 	tmp = comp->steps[i].value2;
  439: 	comp->steps[i].value2 = comp->steps[j].value2;
  440: 	comp->steps[j].value2 = tmp;
  441: 	op = comp->steps[i].op;
  442: 	comp->steps[i].op = comp->steps[j].op;
  443: 	comp->steps[j].op = op;
  444: 	j--;
  445: 	i++;
  446:     }
  447:     comp->steps[comp->nbStep].value = NULL;
  448:     comp->steps[comp->nbStep].value2 = NULL;
  449:     comp->steps[comp->nbStep++].op = XML_OP_END;
  450:     return(0);
  451: }
  452: 
  453: /************************************************************************
  454:  * 									*
  455:  * 		The interpreter for the precompiled patterns		*
  456:  * 									*
  457:  ************************************************************************/
  458: 
  459: static int
  460: xmlPatPushState(xmlStepStates *states, int step, xmlNodePtr node) {
  461:     if ((states->states == NULL) || (states->maxstates <= 0)) {
  462:         states->maxstates = 4;
  463: 	states->nbstates = 0;
  464: 	states->states = xmlMalloc(4 * sizeof(xmlStepState));
  465:     }
  466:     else if (states->maxstates <= states->nbstates) {
  467:         xmlStepState *tmp;
  468: 
  469: 	tmp = (xmlStepStatePtr) xmlRealloc(states->states,
  470: 			       2 * states->maxstates * sizeof(xmlStepState));
  471: 	if (tmp == NULL)
  472: 	    return(-1);
  473: 	states->states = tmp;
  474: 	states->maxstates *= 2;
  475:     }
  476:     states->states[states->nbstates].step = step;
  477:     states->states[states->nbstates++].node = node;
  478: #if 0
  479:     fprintf(stderr, "Push: %d, %s\n", step, node->name);
  480: #endif
  481:     return(0);
  482: }
  483: 
  484: /**
  485:  * xmlPatMatch:
  486:  * @comp: the precompiled pattern
  487:  * @node: a node
  488:  *
  489:  * Test whether the node matches the pattern
  490:  *
  491:  * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
  492:  */
  493: static int
  494: xmlPatMatch(xmlPatternPtr comp, xmlNodePtr node) {
  495:     int i;
  496:     xmlStepOpPtr step;
  497:     xmlStepStates states = {0, 0, NULL}; /* // may require backtrack */
  498: 
  499:     if ((comp == NULL) || (node == NULL)) return(-1);
  500:     i = 0;
  501: restart:
  502:     for (;i < comp->nbStep;i++) {
  503: 	step = &comp->steps[i];
  504: 	switch (step->op) {
  505:             case XML_OP_END:
  506: 		goto found;
  507:             case XML_OP_ROOT:
  508: 		if (node->type == XML_NAMESPACE_DECL)
  509: 		    goto rollback;
  510: 		node = node->parent;
  511: 		if ((node->type == XML_DOCUMENT_NODE) ||
  512: #ifdef LIBXML_DOCB_ENABLED
  513: 		    (node->type == XML_DOCB_DOCUMENT_NODE) ||
  514: #endif
  515: 		    (node->type == XML_HTML_DOCUMENT_NODE))
  516: 		    continue;
  517: 		goto rollback;
  518:             case XML_OP_ELEM:
  519: 		if (node->type != XML_ELEMENT_NODE)
  520: 		    goto rollback;
  521: 		if (step->value == NULL)
  522: 		    continue;
  523: 		if (step->value[0] != node->name[0])
  524: 		    goto rollback;
  525: 		if (!xmlStrEqual(step->value, node->name))
  526: 		    goto rollback;
  527: 
  528: 		/* Namespace test */
  529: 		if (node->ns == NULL) {
  530: 		    if (step->value2 != NULL)
  531: 			goto rollback;
  532: 		} else if (node->ns->href != NULL) {
  533: 		    if (step->value2 == NULL)
  534: 			goto rollback;
  535: 		    if (!xmlStrEqual(step->value2, node->ns->href))
  536: 			goto rollback;
  537: 		}
  538: 		continue;
  539:             case XML_OP_CHILD: {
  540: 		xmlNodePtr lst;
  541: 
  542: 		if ((node->type != XML_ELEMENT_NODE) &&
  543: 		    (node->type != XML_DOCUMENT_NODE) &&
  544: #ifdef LIBXML_DOCB_ENABLED
  545: 		    (node->type != XML_DOCB_DOCUMENT_NODE) &&
  546: #endif
  547: 		    (node->type != XML_HTML_DOCUMENT_NODE))
  548: 		    goto rollback;
  549: 
  550: 		lst = node->children;
  551: 
  552: 		if (step->value != NULL) {
  553: 		    while (lst != NULL) {
  554: 			if ((lst->type == XML_ELEMENT_NODE) &&
  555: 			    (step->value[0] == lst->name[0]) &&
  556: 			    (xmlStrEqual(step->value, lst->name)))
  557: 			    break;
  558: 			lst = lst->next;
  559: 		    }
  560: 		    if (lst != NULL)
  561: 			continue;
  562: 		}
  563: 		goto rollback;
  564: 	    }
  565:             case XML_OP_ATTR:
  566: 		if (node->type != XML_ATTRIBUTE_NODE)
  567: 		    goto rollback;
  568: 		if (step->value != NULL) {
  569: 		    if (step->value[0] != node->name[0])
  570: 			goto rollback;
  571: 		    if (!xmlStrEqual(step->value, node->name))
  572: 			goto rollback;
  573: 		}
  574: 		/* Namespace test */
  575: 		if (node->ns == NULL) {
  576: 		    if (step->value2 != NULL)
  577: 			goto rollback;
  578: 		} else if (step->value2 != NULL) {
  579: 		    if (!xmlStrEqual(step->value2, node->ns->href))
  580: 			goto rollback;
  581: 		}
  582: 		continue;
  583:             case XML_OP_PARENT:
  584: 		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))
  590: 		    goto rollback;
  591: 		node = node->parent;
  592: 		if (node == NULL)
  593: 		    goto rollback;
  594: 		if (step->value == NULL)
  595: 		    continue;
  596: 		if (step->value[0] != node->name[0])
  597: 		    goto rollback;
  598: 		if (!xmlStrEqual(step->value, node->name))
  599: 		    goto rollback;
  600: 		/* Namespace test */
  601: 		if (node->ns == NULL) {
  602: 		    if (step->value2 != NULL)
  603: 			goto rollback;
  604: 		} else if (node->ns->href != NULL) {
  605: 		    if (step->value2 == NULL)
  606: 			goto rollback;
  607: 		    if (!xmlStrEqual(step->value2, node->ns->href))
  608: 			goto rollback;
  609: 		}
  610: 		continue;
  611:             case XML_OP_ANCESTOR:
  612: 		/* TODO: implement coalescing of ANCESTOR/NODE ops */
  613: 		if (step->value == NULL) {
  614: 		    i++;
  615: 		    step = &comp->steps[i];
  616: 		    if (step->op == XML_OP_ROOT)
  617: 			goto found;
  618: 		    if (step->op != XML_OP_ELEM)
  619: 			goto rollback;
  620: 		    if (step->value == NULL)
  621: 			return(-1);
  622: 		}
  623: 		if (node == NULL)
  624: 		    goto rollback;
  625: 		if ((node->type == XML_DOCUMENT_NODE) ||
  626: 		    (node->type == XML_HTML_DOCUMENT_NODE) ||
  627: #ifdef LIBXML_DOCB_ENABLED
  628: 		    (node->type == XML_DOCB_DOCUMENT_NODE) ||
  629: #endif
  630: 		    (node->type == XML_NAMESPACE_DECL))
  631: 		    goto rollback;
  632: 		node = node->parent;
  633: 		while (node != NULL) {
  634: 		    if ((node->type == XML_ELEMENT_NODE) &&
  635: 			(step->value[0] == node->name[0]) &&
  636: 			(xmlStrEqual(step->value, node->name))) {
  637: 			/* Namespace test */
  638: 			if (node->ns == NULL) {
  639: 			    if (step->value2 == NULL)
  640: 				break;
  641: 			} else if (node->ns->href != NULL) {
  642: 			    if ((step->value2 != NULL) &&
  643: 			        (xmlStrEqual(step->value2, node->ns->href)))
  644: 				break;
  645: 			}
  646: 		    }
  647: 		    node = node->parent;
  648: 		}
  649: 		if (node == NULL)
  650: 		    goto rollback;
  651: 		/*
  652: 		 * prepare a potential rollback from here
  653: 		 * for ancestors of that node.
  654: 		 */
  655: 		if (step->op == XML_OP_ANCESTOR)
  656: 		    xmlPatPushState(&states, i, node);
  657: 		else
  658: 		    xmlPatPushState(&states, i - 1, node);
  659: 		continue;
  660:             case XML_OP_NS:
  661: 		if (node->type != XML_ELEMENT_NODE)
  662: 		    goto rollback;
  663: 		if (node->ns == NULL) {
  664: 		    if (step->value != NULL)
  665: 			goto rollback;
  666: 		} else if (node->ns->href != NULL) {
  667: 		    if (step->value == NULL)
  668: 			goto rollback;
  669: 		    if (!xmlStrEqual(step->value, node->ns->href))
  670: 			goto rollback;
  671: 		}
  672: 		break;
  673:             case XML_OP_ALL:
  674: 		if (node->type != XML_ELEMENT_NODE)
  675: 		    goto rollback;
  676: 		break;
  677: 	}
  678:     }
  679: found:
  680:     if (states.states != NULL) {
  681:         /* Free the rollback states */
  682: 	xmlFree(states.states);
  683:     }
  684:     return(1);
  685: rollback:
  686:     /* got an error try to rollback */
  687:     if (states.states == NULL)
  688: 	return(0);
  689:     if (states.nbstates <= 0) {
  690: 	xmlFree(states.states);
  691: 	return(0);
  692:     }
  693:     states.nbstates--;
  694:     i = states.states[states.nbstates].step;
  695:     node = states.states[states.nbstates].node;
  696: #if 0
  697:     fprintf(stderr, "Pop: %d, %s\n", i, node->name);
  698: #endif
  699:     goto restart;
  700: }
  701: 
  702: /************************************************************************
  703:  *									*
  704:  *			Dedicated parser for templates			*
  705:  *									*
  706:  ************************************************************************/
  707: 
  708: #define TODO 								\
  709:     xmlGenericError(xmlGenericErrorContext,				\
  710: 	    "Unimplemented block at %s:%d\n",				\
  711:             __FILE__, __LINE__);
  712: #define CUR (*ctxt->cur)
  713: #define SKIP(val) ctxt->cur += (val)
  714: #define NXT(val) ctxt->cur[(val)]
  715: #define PEEKPREV(val) ctxt->cur[-(val)]
  716: #define CUR_PTR ctxt->cur
  717: 
  718: #define SKIP_BLANKS 							\
  719:     while (IS_BLANK_CH(CUR)) NEXT
  720: 
  721: #define CURRENT (*ctxt->cur)
  722: #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
  723: 
  724: 
  725: #define PUSH(op, val, val2) 						\
  726:     if (xmlPatternAdd(ctxt, ctxt->comp, (op), (val), (val2))) goto error;
  727: 
  728: #define XSLT_ERROR(X)							\
  729:     { xsltError(ctxt, __FILE__, __LINE__, X);				\
  730:       ctxt->error = (X); return; }
  731: 
  732: #define XSLT_ERROR0(X)							\
  733:     { xsltError(ctxt, __FILE__, __LINE__, X);				\
  734:       ctxt->error = (X); return(0); }
  735: 
  736: #if 0
  737: /**
  738:  * xmlPatScanLiteral:
  739:  * @ctxt:  the XPath Parser context
  740:  *
  741:  * Parse an XPath Litteral:
  742:  *
  743:  * [29] Literal ::= '"' [^"]* '"'
  744:  *                | "'" [^']* "'"
  745:  *
  746:  * Returns the Literal parsed or NULL
  747:  */
  748: 
  749: static xmlChar *
  750: xmlPatScanLiteral(xmlPatParserContextPtr ctxt) {
  751:     const xmlChar *q, *cur;
  752:     xmlChar *ret = NULL;
  753:     int val, len;
  754: 
  755:     SKIP_BLANKS;
  756:     if (CUR == '"') {
  757:         NEXT;
  758: 	cur = q = CUR_PTR;
  759: 	val = xmlStringCurrentChar(NULL, cur, &len);
  760: 	while ((IS_CHAR(val)) && (val != '"')) {
  761: 	    cur += len;
  762: 	    val = xmlStringCurrentChar(NULL, cur, &len);
  763: 	}
  764: 	if (!IS_CHAR(val)) {
  765: 	    ctxt->error = 1;
  766: 	    return(NULL);
  767: 	} else {
  768: 	    if (ctxt->dict)
  769: 		ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
  770: 	    else
  771: 		ret = xmlStrndup(q, cur - q);	    
  772:         }
  773: 	cur += len;
  774: 	CUR_PTR = cur;
  775:     } else if (CUR == '\'') {
  776:         NEXT;
  777: 	cur = q = CUR_PTR;
  778: 	val = xmlStringCurrentChar(NULL, cur, &len);
  779: 	while ((IS_CHAR(val)) && (val != '\'')) {
  780: 	    cur += len;
  781: 	    val = xmlStringCurrentChar(NULL, cur, &len);
  782: 	}
  783: 	if (!IS_CHAR(val)) {
  784: 	    ctxt->error = 1;
  785: 	    return(NULL);
  786: 	} else {
  787: 	    if (ctxt->dict)
  788: 		ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
  789: 	    else
  790: 		ret = xmlStrndup(q, cur - q);	    
  791:         }
  792: 	cur += len;
  793: 	CUR_PTR = cur;
  794:     } else {
  795: 	/* XP_ERROR(XPATH_START_LITERAL_ERROR); */
  796: 	ctxt->error = 1;
  797: 	return(NULL);
  798:     }
  799:     return(ret);
  800: }
  801: #endif
  802: 
  803: /**
  804:  * xmlPatScanName:
  805:  * @ctxt:  the XPath Parser context
  806:  *
  807:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | 
  808:  *                  CombiningChar | Extender
  809:  *
  810:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
  811:  *
  812:  * [6] Names ::= Name (S Name)*
  813:  *
  814:  * Returns the Name parsed or NULL
  815:  */
  816: 
  817: static xmlChar *
  818: xmlPatScanName(xmlPatParserContextPtr ctxt) {
  819:     const xmlChar *q, *cur;
  820:     xmlChar *ret = NULL;
  821:     int val, len;
  822: 
  823:     SKIP_BLANKS;
  824: 
  825:     cur = q = CUR_PTR;
  826:     val = xmlStringCurrentChar(NULL, cur, &len);
  827:     if (!IS_LETTER(val) && (val != '_') && (val != ':'))
  828: 	return(NULL);
  829: 
  830:     while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
  831:            (val == '.') || (val == '-') ||
  832: 	   (val == '_') || 
  833: 	   (IS_COMBINING(val)) ||
  834: 	   (IS_EXTENDER(val))) {
  835: 	cur += len;
  836: 	val = xmlStringCurrentChar(NULL, cur, &len);
  837:     }
  838:     if (ctxt->dict)
  839: 	ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
  840:     else
  841: 	ret = xmlStrndup(q, cur - q);    
  842:     CUR_PTR = cur;
  843:     return(ret);
  844: }
  845: 
  846: /**
  847:  * xmlPatScanNCName:
  848:  * @ctxt:  the XPath Parser context
  849:  *
  850:  * Parses a non qualified name
  851:  *
  852:  * Returns the Name parsed or NULL
  853:  */
  854: 
  855: static xmlChar *
  856: xmlPatScanNCName(xmlPatParserContextPtr ctxt) {
  857:     const xmlChar *q, *cur;
  858:     xmlChar *ret = NULL;
  859:     int val, len;
  860: 
  861:     SKIP_BLANKS;
  862: 
  863:     cur = q = CUR_PTR;
  864:     val = xmlStringCurrentChar(NULL, cur, &len);
  865:     if (!IS_LETTER(val) && (val != '_'))
  866: 	return(NULL);
  867: 
  868:     while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
  869:            (val == '.') || (val == '-') ||
  870: 	   (val == '_') ||
  871: 	   (IS_COMBINING(val)) ||
  872: 	   (IS_EXTENDER(val))) {
  873: 	cur += len;
  874: 	val = xmlStringCurrentChar(NULL, cur, &len);
  875:     }
  876:     if (ctxt->dict)
  877: 	ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
  878:     else
  879: 	ret = xmlStrndup(q, cur - q);
  880:     CUR_PTR = cur;
  881:     return(ret);
  882: }
  883: 
  884: #if 0
  885: /**
  886:  * xmlPatScanQName:
  887:  * @ctxt:  the XPath Parser context
  888:  * @prefix:  the place to store the prefix
  889:  *
  890:  * Parse a qualified name
  891:  *
  892:  * Returns the Name parsed or NULL
  893:  */
  894: 
  895: static xmlChar *
  896: xmlPatScanQName(xmlPatParserContextPtr ctxt, xmlChar **prefix) {
  897:     xmlChar *ret = NULL;
  898: 
  899:     *prefix = NULL;
  900:     ret = xmlPatScanNCName(ctxt);
  901:     if (CUR == ':') {
  902:         *prefix = ret;
  903: 	NEXT;
  904: 	ret = xmlPatScanNCName(ctxt);
  905:     }
  906:     return(ret);
  907: }
  908: #endif
  909: 
  910: /**
  911:  * xmlCompileAttributeTest:
  912:  * @ctxt:  the compilation context
  913:  *
  914:  * Compile an attribute test.
  915:  */
  916: static void
  917: xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) {
  918:     xmlChar *token = NULL;
  919:     xmlChar *name = NULL;
  920:     xmlChar *URL = NULL;
  921:     
  922:     SKIP_BLANKS;
  923:     name = xmlPatScanNCName(ctxt);
  924:     if (name == NULL) {
  925: 	if (CUR == '*') {
  926: 	    PUSH(XML_OP_ATTR, NULL, NULL);
  927: 	    NEXT;
  928: 	} else {
  929: 	    ERROR(NULL, NULL, NULL,
  930: 		"xmlCompileAttributeTest : Name expected\n");
  931: 	    ctxt->error = 1;
  932: 	}
  933: 	return;
  934:     }
  935:     if (CUR == ':') {
  936: 	int i;
  937: 	xmlChar *prefix = name;
  938: 	
  939: 	NEXT;
  940: 
  941: 	if (IS_BLANK_CH(CUR)) {	    
  942: 	    ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
  943: 	    XML_PAT_FREE_STRING(ctxt, prefix);
  944: 	    ctxt->error = 1;
  945: 	    goto error;
  946: 	}
  947: 	/*
  948: 	* This is a namespace match
  949: 	*/
  950: 	token = xmlPatScanName(ctxt);
  951: 	if ((prefix[0] == 'x') &&
  952: 	    (prefix[1] == 'm') &&
  953: 	    (prefix[2] == 'l') &&
  954: 	    (prefix[3] == 0))
  955: 	{
  956: 	    XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE);	    
  957: 	} else {
  958: 	    for (i = 0;i < ctxt->nb_namespaces;i++) {
  959: 		if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
  960: 		    XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])		    
  961: 		    break;
  962: 		}
  963: 	    }
  964: 	    if (i >= ctxt->nb_namespaces) {
  965: 		ERROR5(NULL, NULL, NULL,
  966: 		    "xmlCompileAttributeTest : no namespace bound to prefix %s\n",
  967: 		    prefix);
  968: 		ctxt->error = 1;	    
  969: 		goto error;
  970: 	    }
  971: 	}
  972: 	XML_PAT_FREE_STRING(ctxt, prefix);
  973: 	if (token == NULL) {
  974: 	    if (CUR == '*') {
  975: 		NEXT;
  976: 		PUSH(XML_OP_ATTR, NULL, URL);
  977: 	    } else {
  978: 		ERROR(NULL, NULL, NULL,
  979: 		    "xmlCompileAttributeTest : Name expected\n");
  980: 		ctxt->error = 1;
  981: 		goto error;
  982: 	    }	    
  983: 	} else {
  984: 	    PUSH(XML_OP_ATTR, token, URL);
  985: 	}
  986:     } else {
  987: 	PUSH(XML_OP_ATTR, name, NULL);
  988:     }
  989:     return;
  990: error:
  991:     if (URL != NULL)
  992: 	XML_PAT_FREE_STRING(ctxt, URL)	
  993:     if (token != NULL)
  994: 	XML_PAT_FREE_STRING(ctxt, token);
  995: }
  996: 
  997: /**
  998:  * xmlCompileStepPattern:
  999:  * @ctxt:  the compilation context
 1000:  *
 1001:  * Compile the Step Pattern and generates a precompiled
 1002:  * form suitable for fast matching.
 1003:  *
 1004:  * [3]    Step    ::=    '.' | NameTest
 1005:  * [4]    NameTest    ::=    QName | '*' | NCName ':' '*' 
 1006:  */
 1007: 
 1008: static void
 1009: xmlCompileStepPattern(xmlPatParserContextPtr ctxt) {
 1010:     xmlChar *token = NULL;
 1011:     xmlChar *name = NULL;
 1012:     xmlChar *URL = NULL;
 1013:     int hasBlanks = 0;
 1014: 
 1015:     SKIP_BLANKS;
 1016:     if (CUR == '.') {
 1017: 	/*
 1018: 	* Context node.
 1019: 	*/
 1020: 	NEXT;
 1021: 	PUSH(XML_OP_ELEM, NULL, NULL);
 1022: 	return;
 1023:     }
 1024:     if (CUR == '@') {
 1025: 	/*
 1026: 	* Attribute test.
 1027: 	*/
 1028: 	if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) {
 1029: 	    ERROR5(NULL, NULL, NULL,
 1030: 		"Unexpected attribute axis in '%s'.\n", ctxt->base);
 1031: 	    ctxt->error = 1;
 1032: 	    return;
 1033: 	}
 1034: 	NEXT;
 1035: 	xmlCompileAttributeTest(ctxt);
 1036: 	if (ctxt->error != 0) 
 1037: 	    goto error;
 1038: 	return;
 1039:     }
 1040:     name = xmlPatScanNCName(ctxt);
 1041:     if (name == NULL) {
 1042: 	if (CUR == '*') {
 1043: 	    NEXT;
 1044: 	    PUSH(XML_OP_ALL, NULL, NULL);
 1045: 	    return;
 1046: 	} else {
 1047: 	    ERROR(NULL, NULL, NULL,
 1048: 		    "xmlCompileStepPattern : Name expected\n");
 1049: 	    ctxt->error = 1;
 1050: 	    return;
 1051: 	}
 1052:     }
 1053:     if (IS_BLANK_CH(CUR)) {
 1054: 	hasBlanks = 1;
 1055: 	SKIP_BLANKS;
 1056:     }
 1057:     if (CUR == ':') {
 1058: 	NEXT;
 1059: 	if (CUR != ':') {
 1060: 	    xmlChar *prefix = name;
 1061: 	    int i;	    
 1062: 
 1063: 	    if (hasBlanks || IS_BLANK_CH(CUR)) {
 1064: 		ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
 1065: 		ctxt->error = 1;
 1066: 		goto error;
 1067: 	    }
 1068: 	    /*
 1069: 	     * This is a namespace match
 1070: 	     */
 1071: 	    token = xmlPatScanName(ctxt);
 1072: 	    if ((prefix[0] == 'x') &&
 1073: 		(prefix[1] == 'm') &&
 1074: 		(prefix[2] == 'l') &&
 1075: 		(prefix[3] == 0))
 1076: 	    {
 1077: 		XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE)
 1078: 	    } else {
 1079: 		for (i = 0;i < ctxt->nb_namespaces;i++) {
 1080: 		    if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
 1081: 			XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])
 1082: 			break;
 1083: 		    }
 1084: 		}
 1085: 		if (i >= ctxt->nb_namespaces) {
 1086: 		    ERROR5(NULL, NULL, NULL,
 1087: 			"xmlCompileStepPattern : no namespace bound to prefix %s\n",
 1088: 			prefix);
 1089: 		    ctxt->error = 1;
 1090: 		    goto error;
 1091: 		}
 1092: 	    }
 1093: 	    XML_PAT_FREE_STRING(ctxt, prefix);
 1094: 	    name = NULL;
 1095: 	    if (token == NULL) {
 1096: 		if (CUR == '*') {
 1097: 		    NEXT;
 1098: 		    PUSH(XML_OP_NS, URL, NULL);
 1099: 		} else {
 1100: 		    ERROR(NULL, NULL, NULL,
 1101: 			    "xmlCompileStepPattern : Name expected\n");
 1102: 		    ctxt->error = 1;
 1103: 		    goto error;
 1104: 		}
 1105: 	    } else {
 1106: 		PUSH(XML_OP_ELEM, token, URL);
 1107: 	    }
 1108: 	} else {
 1109: 	    NEXT;
 1110: 	    if (xmlStrEqual(name, (const xmlChar *) "child")) {		
 1111: 		XML_PAT_FREE_STRING(ctxt, name);
 1112: 		name = xmlPatScanName(ctxt);
 1113: 		if (name == NULL) {
 1114: 		    if (CUR == '*') {
 1115: 			NEXT;
 1116: 			PUSH(XML_OP_ALL, NULL, NULL);
 1117: 			return;
 1118: 		    } else {
 1119: 			ERROR(NULL, NULL, NULL,
 1120: 			    "xmlCompileStepPattern : QName expected\n");
 1121: 			ctxt->error = 1;
 1122: 			goto error;
 1123: 		    }
 1124: 		}
 1125: 		if (CUR == ':') {
 1126: 		    xmlChar *prefix = name;
 1127: 		    int i;
 1128: 		    
 1129: 		    NEXT;
 1130: 		    if (IS_BLANK_CH(CUR)) {
 1131: 			ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
 1132: 			ctxt->error = 1;
 1133: 			goto error;
 1134: 		    }
 1135: 		    /*
 1136: 		    * This is a namespace match
 1137: 		    */
 1138: 		    token = xmlPatScanName(ctxt);
 1139: 		    if ((prefix[0] == 'x') &&
 1140: 			(prefix[1] == 'm') &&
 1141: 			(prefix[2] == 'l') &&
 1142: 			(prefix[3] == 0))
 1143: 		    {
 1144: 			XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE)			
 1145: 		    } else {
 1146: 			for (i = 0;i < ctxt->nb_namespaces;i++) {
 1147: 			    if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
 1148: 				XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])				
 1149: 				break;
 1150: 			    }
 1151: 			}
 1152: 			if (i >= ctxt->nb_namespaces) {
 1153: 			    ERROR5(NULL, NULL, NULL,
 1154: 				"xmlCompileStepPattern : no namespace bound "
 1155: 				"to prefix %s\n", prefix);
 1156: 			    ctxt->error = 1;
 1157: 			    goto error;
 1158: 			}
 1159: 		    }
 1160: 		    XML_PAT_FREE_STRING(ctxt, prefix);
 1161: 		    name = NULL;
 1162: 		    if (token == NULL) {
 1163: 			if (CUR == '*') {
 1164: 			    NEXT;
 1165: 			    PUSH(XML_OP_NS, URL, NULL);
 1166: 			} else {
 1167: 			    ERROR(NULL, NULL, NULL,
 1168: 				"xmlCompileStepPattern : Name expected\n");
 1169: 			    ctxt->error = 1;
 1170: 			    goto error;
 1171: 			}
 1172: 		    } else {
 1173: 			PUSH(XML_OP_CHILD, token, URL);
 1174: 		    }
 1175: 		} else
 1176: 		    PUSH(XML_OP_CHILD, name, NULL);
 1177: 		return;
 1178: 	    } else if (xmlStrEqual(name, (const xmlChar *) "attribute")) {
 1179: 		XML_PAT_FREE_STRING(ctxt, name)
 1180: 		name = NULL;
 1181: 		if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) {
 1182: 		    ERROR5(NULL, NULL, NULL,
 1183: 			"Unexpected attribute axis in '%s'.\n", ctxt->base);
 1184: 		    ctxt->error = 1;
 1185: 		    goto error;
 1186: 		}
 1187: 		xmlCompileAttributeTest(ctxt);
 1188: 		if (ctxt->error != 0)
 1189: 		    goto error;
 1190: 		return;
 1191: 	    } else {
 1192: 		ERROR5(NULL, NULL, NULL,
 1193: 		    "The 'element' or 'attribute' axis is expected.\n", NULL);
 1194: 		ctxt->error = 1;
 1195: 		goto error;
 1196: 	    }	    
 1197: 	}
 1198:     } else if (CUR == '*') {
 1199:         if (name != NULL) {
 1200: 	    ctxt->error = 1;
 1201: 	    goto error;
 1202: 	}
 1203: 	NEXT;
 1204: 	PUSH(XML_OP_ALL, token, NULL);
 1205:     } else {
 1206: 	PUSH(XML_OP_ELEM, name, NULL);
 1207:     }
 1208:     return;
 1209: error:
 1210:     if (URL != NULL)
 1211: 	XML_PAT_FREE_STRING(ctxt, URL)	
 1212:     if (token != NULL)
 1213: 	XML_PAT_FREE_STRING(ctxt, token)
 1214:     if (name != NULL)
 1215: 	XML_PAT_FREE_STRING(ctxt, name)
 1216: }
 1217: 
 1218: /**
 1219:  * xmlCompilePathPattern:
 1220:  * @ctxt:  the compilation context
 1221:  *
 1222:  * Compile the Path Pattern and generates a precompiled
 1223:  * form suitable for fast matching.
 1224:  *
 1225:  * [5]    Path    ::=    ('.//')? ( Step '/' )* ( Step | '@' NameTest ) 
 1226:  */
 1227: static void
 1228: xmlCompilePathPattern(xmlPatParserContextPtr ctxt) {
 1229:     SKIP_BLANKS;
 1230:     if (CUR == '/') {
 1231:         ctxt->comp->flags |= PAT_FROM_ROOT;
 1232:     } else if ((CUR == '.') || (ctxt->comp->flags & XML_PATTERN_NOTPATTERN)) {
 1233:         ctxt->comp->flags |= PAT_FROM_CUR;
 1234:     }
 1235: 	
 1236:     if ((CUR == '/') && (NXT(1) == '/')) {
 1237: 	PUSH(XML_OP_ANCESTOR, NULL, NULL);
 1238: 	NEXT;
 1239: 	NEXT;
 1240:     } else if ((CUR == '.') && (NXT(1) == '/') && (NXT(2) == '/')) {
 1241: 	PUSH(XML_OP_ANCESTOR, NULL, NULL);
 1242: 	NEXT;
 1243: 	NEXT;
 1244: 	NEXT;
 1245: 	/* Check for incompleteness. */
 1246: 	SKIP_BLANKS;
 1247: 	if (CUR == 0) {
 1248: 	    ERROR5(NULL, NULL, NULL,
 1249: 	       "Incomplete expression '%s'.\n", ctxt->base);
 1250: 	    ctxt->error = 1;
 1251: 	    goto error;
 1252: 	}
 1253:     }
 1254:     if (CUR == '@') {
 1255: 	NEXT;
 1256: 	xmlCompileAttributeTest(ctxt);
 1257: 	SKIP_BLANKS;
 1258: 	/* TODO: check for incompleteness */
 1259: 	if (CUR != 0) {
 1260: 	    xmlCompileStepPattern(ctxt);
 1261: 	    if (ctxt->error != 0)
 1262: 		goto error;
 1263: 	}
 1264:     } else {
 1265:         if (CUR == '/') {
 1266: 	    PUSH(XML_OP_ROOT, NULL, NULL);
 1267: 	    NEXT;
 1268: 	    /* Check for incompleteness. */
 1269: 	    SKIP_BLANKS;
 1270: 	    if (CUR == 0) {
 1271: 		ERROR5(NULL, NULL, NULL,
 1272: 		    "Incomplete expression '%s'.\n", ctxt->base);
 1273: 		ctxt->error = 1;
 1274: 		goto error;
 1275: 	    }
 1276: 	}
 1277: 	xmlCompileStepPattern(ctxt);
 1278: 	if (ctxt->error != 0)
 1279: 	    goto error;
 1280: 	SKIP_BLANKS;
 1281: 	while (CUR == '/') {
 1282: 	    if (NXT(1) == '/') {
 1283: 	        PUSH(XML_OP_ANCESTOR, NULL, NULL);
 1284: 		NEXT;
 1285: 		NEXT;
 1286: 		SKIP_BLANKS;
 1287: 		xmlCompileStepPattern(ctxt);
 1288: 		if (ctxt->error != 0)
 1289: 		    goto error;
 1290: 	    } else {
 1291: 	        PUSH(XML_OP_PARENT, NULL, NULL);
 1292: 		NEXT;
 1293: 		SKIP_BLANKS;
 1294: 		if (CUR == 0) {
 1295: 		    ERROR5(NULL, NULL, NULL,
 1296: 		    "Incomplete expression '%s'.\n", ctxt->base);
 1297: 		    ctxt->error = 1;
 1298: 		    goto error;		    
 1299: 		}
 1300: 		xmlCompileStepPattern(ctxt);
 1301: 		if (ctxt->error != 0)
 1302: 		    goto error;
 1303: 	    }
 1304: 	}
 1305:     }
 1306:     if (CUR != 0) {
 1307: 	ERROR5(NULL, NULL, NULL,
 1308: 	       "Failed to compile pattern %s\n", ctxt->base);
 1309: 	ctxt->error = 1;
 1310:     }
 1311: error:
 1312:     return;
 1313: }
 1314: 
 1315: /**
 1316:  * xmlCompileIDCXPathPath:
 1317:  * @ctxt:  the compilation context
 1318:  *
 1319:  * Compile the Path Pattern and generates a precompiled
 1320:  * form suitable for fast matching.
 1321:  *
 1322:  * [5]    Path    ::=    ('.//')? ( Step '/' )* ( Step | '@' NameTest ) 
 1323:  */
 1324: static void
 1325: xmlCompileIDCXPathPath(xmlPatParserContextPtr ctxt) {
 1326:     SKIP_BLANKS;
 1327:     if (CUR == '/') {
 1328: 	ERROR5(NULL, NULL, NULL,
 1329: 	    "Unexpected selection of the document root in '%s'.\n",
 1330: 	    ctxt->base);
 1331: 	goto error;
 1332:     }
 1333:     ctxt->comp->flags |= PAT_FROM_CUR;
 1334: 
 1335:     if (CUR == '.') {
 1336: 	/* "." - "self::node()" */
 1337: 	NEXT;
 1338: 	SKIP_BLANKS;
 1339: 	if (CUR == 0) {
 1340: 	    /*
 1341: 	    * Selection of the context node.
 1342: 	    */
 1343: 	    PUSH(XML_OP_ELEM, NULL, NULL);
 1344: 	    return;
 1345: 	}
 1346: 	if (CUR != '/') {
 1347: 	    /* TODO: A more meaningful error message. */
 1348: 	    ERROR5(NULL, NULL, NULL,
 1349: 	    "Unexpected token after '.' in '%s'.\n", ctxt->base);
 1350: 	    goto error;
 1351: 	}
 1352: 	/* "./" - "self::node()/" */
 1353: 	NEXT;
 1354: 	SKIP_BLANKS;
 1355: 	if (CUR == '/') {
 1356: 	    if (IS_BLANK_CH(PEEKPREV(1))) {
 1357: 		/*
 1358: 		* Disallow "./ /"
 1359: 		*/
 1360: 		ERROR5(NULL, NULL, NULL,
 1361: 		    "Unexpected '/' token in '%s'.\n", ctxt->base);
 1362: 		goto error;
 1363: 	    }
 1364: 	    /* ".//" - "self:node()/descendant-or-self::node()/" */
 1365: 	    PUSH(XML_OP_ANCESTOR, NULL, NULL);
 1366: 	    NEXT;
 1367: 	    SKIP_BLANKS;
 1368: 	}
 1369: 	if (CUR == 0)
 1370: 	    goto error_unfinished;
 1371:     }
 1372:     /*
 1373:     * Process steps.
 1374:     */
 1375:     do {
 1376: 	xmlCompileStepPattern(ctxt);
 1377: 	if (ctxt->error != 0) 
 1378: 	    goto error;
 1379: 	SKIP_BLANKS;
 1380: 	if (CUR != '/')
 1381: 	    break;
 1382: 	PUSH(XML_OP_PARENT, NULL, NULL);
 1383: 	NEXT;
 1384: 	SKIP_BLANKS;
 1385: 	if (CUR == '/') {
 1386: 	    /*
 1387: 	    * Disallow subsequent '//'.
 1388: 	    */
 1389: 	    ERROR5(NULL, NULL, NULL,
 1390: 		"Unexpected subsequent '//' in '%s'.\n",
 1391: 		ctxt->base);
 1392: 	    goto error;
 1393: 	}
 1394: 	if (CUR == 0)
 1395: 	    goto error_unfinished;
 1396: 	
 1397:     } while (CUR != 0);
 1398: 
 1399:     if (CUR != 0) {
 1400: 	ERROR5(NULL, NULL, NULL,
 1401: 	    "Failed to compile expression '%s'.\n", ctxt->base);
 1402: 	ctxt->error = 1;
 1403:     }
 1404:     return;
 1405: error:
 1406:     ctxt->error = 1;
 1407:     return;
 1408: 
 1409: error_unfinished:
 1410:     ctxt->error = 1;
 1411:     ERROR5(NULL, NULL, NULL,
 1412: 	"Unfinished expression '%s'.\n", ctxt->base);    
 1413:     return;
 1414: }
 1415: 
 1416: /************************************************************************
 1417:  *									*
 1418:  *			The streaming code				*
 1419:  *									*
 1420:  ************************************************************************/
 1421: 
 1422: #ifdef DEBUG_STREAMING
 1423: static void
 1424: xmlDebugStreamComp(xmlStreamCompPtr stream) {
 1425:     int i;
 1426: 
 1427:     if (stream == NULL) {
 1428:         printf("Stream: NULL\n");
 1429: 	return;
 1430:     }
 1431:     printf("Stream: %d steps\n", stream->nbStep);
 1432:     for (i = 0;i < stream->nbStep;i++) {
 1433: 	if (stream->steps[i].ns != NULL) {
 1434: 	    printf("{%s}", stream->steps[i].ns);
 1435: 	}
 1436:         if (stream->steps[i].name == NULL) {
 1437: 	    printf("* ");
 1438: 	} else {
 1439: 	    printf("%s ", stream->steps[i].name);
 1440: 	}
 1441: 	if (stream->steps[i].flags & XML_STREAM_STEP_ROOT)
 1442: 	    printf("root ");
 1443: 	if (stream->steps[i].flags & XML_STREAM_STEP_DESC)
 1444: 	    printf("// ");
 1445: 	if (stream->steps[i].flags & XML_STREAM_STEP_FINAL)
 1446: 	    printf("final ");
 1447: 	printf("\n");
 1448:     }
 1449: }
 1450: static void
 1451: xmlDebugStreamCtxt(xmlStreamCtxtPtr ctxt, int match) {
 1452:     int i;
 1453: 
 1454:     if (ctxt == NULL) {
 1455:         printf("Stream: NULL\n");
 1456: 	return;
 1457:     }
 1458:     printf("Stream: level %d, %d states: ", ctxt->level, ctxt->nbState);
 1459:     if (match)
 1460:         printf("matches\n");
 1461:     else
 1462:         printf("\n");
 1463:     for (i = 0;i < ctxt->nbState;i++) {
 1464:         if (ctxt->states[2 * i] < 0)
 1465: 	    printf(" %d: free\n", i);
 1466: 	else {
 1467: 	    printf(" %d: step %d, level %d", i, ctxt->states[2 * i],
 1468: 	           ctxt->states[(2 * i) + 1]);
 1469:             if (ctxt->comp->steps[ctxt->states[2 * i]].flags &
 1470: 	        XML_STREAM_STEP_DESC)
 1471: 	        printf(" //\n");
 1472: 	    else
 1473: 	        printf("\n");
 1474: 	}
 1475:     }
 1476: }
 1477: #endif
 1478: /**
 1479:  * xmlNewStreamComp:
 1480:  * @size: the number of expected steps
 1481:  *
 1482:  * build a new compiled pattern for streaming
 1483:  *
 1484:  * Returns the new structure or NULL in case of error.
 1485:  */
 1486: static xmlStreamCompPtr
 1487: xmlNewStreamComp(int size) {
 1488:     xmlStreamCompPtr cur;
 1489: 
 1490:     if (size < 4)
 1491:         size  = 4;
 1492: 
 1493:     cur = (xmlStreamCompPtr) xmlMalloc(sizeof(xmlStreamComp));
 1494:     if (cur == NULL) {
 1495: 	ERROR(NULL, NULL, NULL,
 1496: 		"xmlNewStreamComp: malloc failed\n");
 1497: 	return(NULL);
 1498:     }
 1499:     memset(cur, 0, sizeof(xmlStreamComp));
 1500:     cur->steps = (xmlStreamStepPtr) xmlMalloc(size * sizeof(xmlStreamStep));
 1501:     if (cur->steps == NULL) {
 1502: 	xmlFree(cur);
 1503: 	ERROR(NULL, NULL, NULL,
 1504: 	      "xmlNewStreamComp: malloc failed\n");
 1505: 	return(NULL);
 1506:     }
 1507:     cur->nbStep = 0;
 1508:     cur->maxStep = size;
 1509:     return(cur);
 1510: }
 1511: 
 1512: /**
 1513:  * xmlFreeStreamComp:
 1514:  * @comp: the compiled pattern for streaming
 1515:  *
 1516:  * Free the compiled pattern for streaming
 1517:  */
 1518: static void
 1519: xmlFreeStreamComp(xmlStreamCompPtr comp) {
 1520:     if (comp != NULL) {
 1521:         if (comp->steps != NULL)
 1522: 	    xmlFree(comp->steps);
 1523: 	if (comp->dict != NULL)
 1524: 	    xmlDictFree(comp->dict);
 1525:         xmlFree(comp);
 1526:     }
 1527: }
 1528: 
 1529: /**
 1530:  * xmlStreamCompAddStep:
 1531:  * @comp: the compiled pattern for streaming
 1532:  * @name: the first string, the name, or NULL for *
 1533:  * @ns: the second step, the namespace name
 1534:  * @flags: the flags for that step
 1535:  *
 1536:  * Add a new step to the compiled pattern
 1537:  *
 1538:  * Returns -1 in case of error or the step index if successful
 1539:  */
 1540: static int
 1541: xmlStreamCompAddStep(xmlStreamCompPtr comp, const xmlChar *name,
 1542:                      const xmlChar *ns, int nodeType, int flags) {
 1543:     xmlStreamStepPtr cur;
 1544: 
 1545:     if (comp->nbStep >= comp->maxStep) {
 1546: 	cur = (xmlStreamStepPtr) xmlRealloc(comp->steps,
 1547: 				 comp->maxStep * 2 * sizeof(xmlStreamStep));
 1548: 	if (cur == NULL) {
 1549: 	    ERROR(NULL, NULL, NULL,
 1550: 		  "xmlNewStreamComp: malloc failed\n");
 1551: 	    return(-1);
 1552: 	}
 1553: 	comp->steps = cur;
 1554:         comp->maxStep *= 2;
 1555:     }
 1556:     cur = &comp->steps[comp->nbStep++];
 1557:     cur->flags = flags;
 1558:     cur->name = name;
 1559:     cur->ns = ns;
 1560:     cur->nodeType = nodeType;
 1561:     return(comp->nbStep - 1);
 1562: }
 1563: 
 1564: /**
 1565:  * xmlStreamCompile:
 1566:  * @comp: the precompiled pattern
 1567:  * 
 1568:  * Tries to stream compile a pattern
 1569:  *
 1570:  * Returns -1 in case of failure and 0 in case of success.
 1571:  */
 1572: static int
 1573: xmlStreamCompile(xmlPatternPtr comp) {
 1574:     xmlStreamCompPtr stream;
 1575:     int i, s = 0, root = 0, flags = 0, prevs = -1;
 1576:     xmlStepOp step;
 1577: 
 1578:     if ((comp == NULL) || (comp->steps == NULL))
 1579:         return(-1);
 1580:     /*
 1581:      * special case for .
 1582:      */
 1583:     if ((comp->nbStep == 1) &&
 1584:         (comp->steps[0].op == XML_OP_ELEM) &&
 1585: 	(comp->steps[0].value == NULL) &&
 1586: 	(comp->steps[0].value2 == NULL)) {
 1587: 	stream = xmlNewStreamComp(0);
 1588: 	if (stream == NULL)
 1589: 	    return(-1);
 1590: 	/* Note that the stream will have no steps in this case. */
 1591: 	stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE;
 1592: 	comp->stream = stream;
 1593: 	return(0);
 1594:     }
 1595: 
 1596:     stream = xmlNewStreamComp((comp->nbStep / 2) + 1);
 1597:     if (stream == NULL)
 1598:         return(-1);
 1599:     if (comp->dict != NULL) {
 1600:         stream->dict = comp->dict;
 1601: 	xmlDictReference(stream->dict);
 1602:     }
 1603: 
 1604:     i = 0;        
 1605:     if (comp->flags & PAT_FROM_ROOT)
 1606: 	stream->flags |= XML_STREAM_FROM_ROOT;
 1607: 
 1608:     for (;i < comp->nbStep;i++) {
 1609: 	step = comp->steps[i];
 1610:         switch (step.op) {
 1611: 	    case XML_OP_END:
 1612: 	        break;
 1613: 	    case XML_OP_ROOT:
 1614: 	        if (i != 0)
 1615: 		    goto error;
 1616: 		root = 1;
 1617: 		break;
 1618: 	    case XML_OP_NS:
 1619: 		s = xmlStreamCompAddStep(stream, NULL, step.value,
 1620: 		    XML_ELEMENT_NODE, flags);		
 1621: 		if (s < 0)
 1622: 		    goto error;
 1623: 		prevs = s;
 1624: 		flags = 0;		
 1625: 		break;	    
 1626: 	    case XML_OP_ATTR:
 1627: 		flags |= XML_STREAM_STEP_ATTR;
 1628: 		prevs = -1;
 1629: 		s = xmlStreamCompAddStep(stream,
 1630: 		    step.value, step.value2, XML_ATTRIBUTE_NODE, flags);
 1631: 		flags = 0;
 1632: 		if (s < 0)
 1633: 		    goto error;
 1634: 		break;
 1635: 	    case XML_OP_ELEM:		
 1636: 	        if ((step.value == NULL) && (step.value2 == NULL)) {
 1637: 		    /*
 1638: 		    * We have a "." or "self::node()" here.
 1639: 		    * Eliminate redundant self::node() tests like in "/./."
 1640: 		    * or "//./"
 1641: 		    * The only case we won't eliminate is "//.", i.e. if
 1642: 		    * self::node() is the last node test and we had
 1643: 		    * continuation somewhere beforehand.
 1644: 		    */
 1645: 		    if ((comp->nbStep == i + 1) &&
 1646: 			(flags & XML_STREAM_STEP_DESC)) {
 1647: 			/*
 1648: 			* Mark the special case where the expression resolves
 1649: 			* to any type of node.
 1650: 			*/
 1651: 			if (comp->nbStep == i + 1) {
 1652: 			    stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE;
 1653: 			}
 1654: 			flags |= XML_STREAM_STEP_NODE;			
 1655: 			s = xmlStreamCompAddStep(stream, NULL, NULL,
 1656: 			    XML_STREAM_ANY_NODE, flags);
 1657: 			if (s < 0)
 1658: 			    goto error;
 1659: 			flags = 0;
 1660: 			/*
 1661: 			* If there was a previous step, mark it to be added to
 1662: 			* the result node-set; this is needed since only
 1663: 			* the last step will be marked as "final" and only
 1664: 			* "final" nodes are added to the resulting set.
 1665: 			*/
 1666: 			if (prevs != -1) {
 1667: 			    stream->steps[prevs].flags |= XML_STREAM_STEP_IN_SET;
 1668: 			    prevs = -1;
 1669: 			}
 1670: 			break;	
 1671: 
 1672: 		    } else {
 1673: 			/* Just skip this one. */
 1674: 			continue;
 1675: 		    }
 1676: 		}
 1677: 		/* An element node. */		
 1678: 	        s = xmlStreamCompAddStep(stream, step.value, step.value2,
 1679: 		    XML_ELEMENT_NODE, flags);		
 1680: 		if (s < 0)
 1681: 		    goto error;
 1682: 		prevs = s;
 1683: 		flags = 0;		
 1684: 		break;		
 1685: 	    case XML_OP_CHILD:
 1686: 		/* An element node child. */
 1687: 	        s = xmlStreamCompAddStep(stream, step.value, step.value2,
 1688: 		    XML_ELEMENT_NODE, flags);		
 1689: 		if (s < 0)
 1690: 		    goto error;
 1691: 		prevs = s;
 1692: 		flags = 0;
 1693: 		break;	    
 1694: 	    case XML_OP_ALL:
 1695: 	        s = xmlStreamCompAddStep(stream, NULL, NULL,
 1696: 		    XML_ELEMENT_NODE, flags);		
 1697: 		if (s < 0)
 1698: 		    goto error;
 1699: 		prevs = s;
 1700: 		flags = 0;
 1701: 		break;
 1702: 	    case XML_OP_PARENT:	
 1703: 	        break;
 1704: 	    case XML_OP_ANCESTOR:
 1705: 		/* Skip redundant continuations. */
 1706: 		if (flags & XML_STREAM_STEP_DESC)
 1707: 		    break;
 1708: 	        flags |= XML_STREAM_STEP_DESC;
 1709: 		/*
 1710: 		* Mark the expression as having "//".
 1711: 		*/
 1712: 		if ((stream->flags & XML_STREAM_DESC) == 0)
 1713: 		    stream->flags |= XML_STREAM_DESC;
 1714: 		break;
 1715: 	}
 1716:     }    
 1717:     if ((! root) && (comp->flags & XML_PATTERN_NOTPATTERN) == 0) {
 1718: 	/*
 1719: 	* If this should behave like a real pattern, we will mark
 1720: 	* the first step as having "//", to be reentrant on every
 1721: 	* tree level.
 1722: 	*/
 1723: 	if ((stream->flags & XML_STREAM_DESC) == 0)
 1724: 	    stream->flags |= XML_STREAM_DESC;
 1725: 
 1726: 	if (stream->nbStep > 0) {
 1727: 	    if ((stream->steps[0].flags & XML_STREAM_STEP_DESC) == 0)
 1728: 		stream->steps[0].flags |= XML_STREAM_STEP_DESC;	    
 1729: 	}
 1730:     }
 1731:     if (stream->nbStep <= s)
 1732: 	goto error;
 1733:     stream->steps[s].flags |= XML_STREAM_STEP_FINAL;
 1734:     if (root)
 1735: 	stream->steps[0].flags |= XML_STREAM_STEP_ROOT;
 1736: #ifdef DEBUG_STREAMING
 1737:     xmlDebugStreamComp(stream);
 1738: #endif
 1739:     comp->stream = stream;
 1740:     return(0);
 1741: error:
 1742:     xmlFreeStreamComp(stream);
 1743:     return(0);
 1744: }
 1745: 
 1746: /**
 1747:  * xmlNewStreamCtxt:
 1748:  * @size: the number of expected states
 1749:  *
 1750:  * build a new stream context
 1751:  *
 1752:  * Returns the new structure or NULL in case of error.
 1753:  */
 1754: static xmlStreamCtxtPtr
 1755: xmlNewStreamCtxt(xmlStreamCompPtr stream) {
 1756:     xmlStreamCtxtPtr cur;
 1757: 
 1758:     cur = (xmlStreamCtxtPtr) xmlMalloc(sizeof(xmlStreamCtxt));
 1759:     if (cur == NULL) {
 1760: 	ERROR(NULL, NULL, NULL,
 1761: 		"xmlNewStreamCtxt: malloc failed\n");
 1762: 	return(NULL);
 1763:     }
 1764:     memset(cur, 0, sizeof(xmlStreamCtxt));
 1765:     cur->states = (int *) xmlMalloc(4 * 2 * sizeof(int));
 1766:     if (cur->states == NULL) {
 1767: 	xmlFree(cur);
 1768: 	ERROR(NULL, NULL, NULL,
 1769: 	      "xmlNewStreamCtxt: malloc failed\n");
 1770: 	return(NULL);
 1771:     }
 1772:     cur->nbState = 0;
 1773:     cur->maxState = 4;
 1774:     cur->level = 0;
 1775:     cur->comp = stream;
 1776:     cur->blockLevel = -1;
 1777:     return(cur);
 1778: }
 1779: 
 1780: /**
 1781:  * xmlFreeStreamCtxt:
 1782:  * @stream: the stream context
 1783:  *
 1784:  * Free the stream context
 1785:  */
 1786: void
 1787: xmlFreeStreamCtxt(xmlStreamCtxtPtr stream) {
 1788:     xmlStreamCtxtPtr next;
 1789: 
 1790:     while (stream != NULL) {
 1791:         next = stream->next;
 1792:         if (stream->states != NULL)
 1793: 	    xmlFree(stream->states);
 1794:         xmlFree(stream);
 1795: 	stream = next;
 1796:     }
 1797: }
 1798: 
 1799: /**
 1800:  * xmlStreamCtxtAddState:
 1801:  * @comp: the stream context
 1802:  * @idx: the step index for that streaming state
 1803:  *
 1804:  * Add a new state to the stream context
 1805:  *
 1806:  * Returns -1 in case of error or the state index if successful
 1807:  */
 1808: static int
 1809: xmlStreamCtxtAddState(xmlStreamCtxtPtr comp, int idx, int level) {
 1810:     int i;
 1811:     for (i = 0;i < comp->nbState;i++) {
 1812:         if (comp->states[2 * i] < 0) {
 1813: 	    comp->states[2 * i] = idx;
 1814: 	    comp->states[2 * i + 1] = level;
 1815: 	    return(i);
 1816: 	}
 1817:     }
 1818:     if (comp->nbState >= comp->maxState) {
 1819:         int *cur;
 1820: 
 1821: 	cur = (int *) xmlRealloc(comp->states,
 1822: 				 comp->maxState * 4 * sizeof(int));
 1823: 	if (cur == NULL) {
 1824: 	    ERROR(NULL, NULL, NULL,
 1825: 		  "xmlNewStreamCtxt: malloc failed\n");
 1826: 	    return(-1);
 1827: 	}
 1828: 	comp->states = cur;
 1829:         comp->maxState *= 2;
 1830:     }
 1831:     comp->states[2 * comp->nbState] = idx;
 1832:     comp->states[2 * comp->nbState++ + 1] = level;
 1833:     return(comp->nbState - 1);
 1834: }
 1835: 
 1836: /**
 1837:  * xmlStreamPushInternal:
 1838:  * @stream: the stream context
 1839:  * @name: the current name
 1840:  * @ns: the namespace name
 1841:  * @nodeType: the type of the node
 1842:  *
 1843:  * Push new data onto the stream. NOTE: if the call xmlPatterncompile()
 1844:  * indicated a dictionary, then strings for name and ns will be expected
 1845:  * to come from the dictionary.
 1846:  * Both @name and @ns being NULL means the / i.e. the root of the document.
 1847:  * This can also act as a reset.
 1848:  *
 1849:  * Returns: -1 in case of error, 1 if the current state in the stream is a
 1850:  *    match and 0 otherwise.
 1851:  */
 1852: static int
 1853: xmlStreamPushInternal(xmlStreamCtxtPtr stream,
 1854: 		      const xmlChar *name, const xmlChar *ns,
 1855: 		      int nodeType) {
 1856:     int ret = 0, err = 0, final = 0, tmp, i, m, match, stepNr, desc;
 1857:     xmlStreamCompPtr comp;
 1858:     xmlStreamStep step;
 1859: #ifdef DEBUG_STREAMING
 1860:     xmlStreamCtxtPtr orig = stream;
 1861: #endif
 1862: 
 1863:     if ((stream == NULL) || (stream->nbState < 0))
 1864:         return(-1);
 1865: 
 1866:     while (stream != NULL) {
 1867: 	comp = stream->comp;
 1868: 
 1869: 	if ((nodeType == XML_ELEMENT_NODE) &&
 1870: 	    (name == NULL) && (ns == NULL)) {
 1871: 	    /* We have a document node here (or a reset). */
 1872: 	    stream->nbState = 0;
 1873: 	    stream->level = 0;
 1874: 	    stream->blockLevel = -1;
 1875: 	    if (comp->flags & XML_STREAM_FROM_ROOT) {
 1876: 		if (comp->nbStep == 0) {
 1877: 		    /* TODO: We have a "/." here? */
 1878: 		    ret = 1;
 1879: 		} else {
 1880: 		    if ((comp->nbStep == 1) &&
 1881: 			(comp->steps[0].nodeType == XML_STREAM_ANY_NODE) &&
 1882: 			(comp->steps[0].flags & XML_STREAM_STEP_DESC))
 1883: 		    {
 1884: 			/*
 1885: 			* In the case of "//." the document node will match
 1886: 			* as well.
 1887: 			*/
 1888: 			ret = 1;
 1889: 		    } else if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) {
 1890: 			/* TODO: Do we need this ? */
 1891: 			tmp = xmlStreamCtxtAddState(stream, 0, 0);
 1892: 			if (tmp < 0)
 1893: 			    err++;
 1894: 		    }
 1895: 		}
 1896: 	    }
 1897: 	    stream = stream->next;
 1898: 	    continue; /* while */
 1899: 	}
 1900: 
 1901: 	/*
 1902: 	* Fast check for ".".
 1903: 	*/
 1904: 	if (comp->nbStep == 0) {
 1905: 	    /*
 1906: 	     * / and . are handled at the XPath node set creation
 1907: 	     * level by checking min depth
 1908: 	     */
 1909: 	    if (stream->flags & XML_PATTERN_XPATH) {
 1910: 		stream = stream->next;
 1911: 		continue; /* while */
 1912: 	    }
 1913: 	    /*
 1914: 	    * For non-pattern like evaluation like XML Schema IDCs
 1915: 	    * or traditional XPath expressions, this will match if
 1916: 	    * we are at the first level only, otherwise on every level.
 1917: 	    */
 1918: 	    if ((nodeType != XML_ATTRIBUTE_NODE) &&
 1919: 		(((stream->flags & XML_PATTERN_NOTPATTERN) == 0) ||
 1920: 		(stream->level == 0))) {
 1921: 		    ret = 1;		
 1922: 	    }
 1923: 	    stream->level++;
 1924: 	    goto stream_next;
 1925: 	}
 1926: 	if (stream->blockLevel != -1) {
 1927: 	    /*
 1928: 	    * Skip blocked expressions.
 1929: 	    */
 1930:     	    stream->level++;
 1931: 	    goto stream_next;
 1932: 	}
 1933: 
 1934: 	if ((nodeType != XML_ELEMENT_NODE) &&
 1935: 	    (nodeType != XML_ATTRIBUTE_NODE) &&
 1936: 	    ((comp->flags & XML_STREAM_FINAL_IS_ANY_NODE) == 0)) {
 1937: 	    /*
 1938: 	    * No need to process nodes of other types if we don't
 1939: 	    * resolve to those types.
 1940: 	    * TODO: Do we need to block the context here?
 1941: 	    */
 1942: 	    stream->level++;
 1943: 	    goto stream_next;
 1944: 	}
 1945: 
 1946: 	/*
 1947: 	 * Check evolution of existing states
 1948: 	 */
 1949: 	i = 0;
 1950: 	m = stream->nbState;
 1951: 	while (i < m) {
 1952: 	    if ((comp->flags & XML_STREAM_DESC) == 0) {
 1953: 		/*
 1954: 		* If there is no "//", then only the last
 1955: 		* added state is of interest.
 1956: 		*/
 1957: 		stepNr = stream->states[2 * (stream->nbState -1)];
 1958: 		/*
 1959: 		* TODO: Security check, should not happen, remove it.
 1960: 		*/
 1961: 		if (stream->states[(2 * (stream->nbState -1)) + 1] <
 1962: 		    stream->level) {
 1963: 		    return (-1);
 1964: 		}
 1965: 		desc = 0;
 1966: 		/* loop-stopper */
 1967: 		i = m;
 1968: 	    } else {
 1969: 		/*
 1970: 		* If there are "//", then we need to process every "//"
 1971: 		* occuring in the states, plus any other state for this
 1972: 		* level.
 1973: 		*/		
 1974: 		stepNr = stream->states[2 * i];
 1975: 
 1976: 		/* TODO: should not happen anymore: dead states */
 1977: 		if (stepNr < 0)
 1978: 		    goto next_state;
 1979: 
 1980: 		tmp = stream->states[(2 * i) + 1];
 1981: 
 1982: 		/* skip new states just added */
 1983: 		if (tmp > stream->level)
 1984: 		    goto next_state;
 1985: 
 1986: 		/* skip states at ancestor levels, except if "//" */
 1987: 		desc = comp->steps[stepNr].flags & XML_STREAM_STEP_DESC;
 1988: 		if ((tmp < stream->level) && (!desc))
 1989: 		    goto next_state;
 1990: 	    }
 1991: 	    /* 
 1992: 	    * Check for correct node-type.
 1993: 	    */
 1994: 	    step = comp->steps[stepNr];
 1995: 	    if (step.nodeType != nodeType) {
 1996: 		if (step.nodeType == XML_ATTRIBUTE_NODE) {
 1997: 		    /*
 1998: 		    * Block this expression for deeper evaluation.
 1999: 		    */
 2000: 		    if ((comp->flags & XML_STREAM_DESC) == 0)
 2001: 			stream->blockLevel = stream->level +1;
 2002: 		    goto next_state;
 2003: 		} else if (step.nodeType != XML_STREAM_ANY_NODE)
 2004: 		    goto next_state;
 2005: 	    }	    
 2006: 	    /*
 2007: 	    * Compare local/namespace-name.
 2008: 	    */
 2009: 	    match = 0;
 2010: 	    if (step.nodeType == XML_STREAM_ANY_NODE) {
 2011: 		match = 1;
 2012: 	    } else if (step.name == NULL) {
 2013: 		if (step.ns == NULL) {
 2014: 		    /*
 2015: 		    * This lets through all elements/attributes.
 2016: 		    */
 2017: 		    match = 1;
 2018: 		} else if (ns != NULL)
 2019: 		    match = xmlStrEqual(step.ns, ns);
 2020: 	    } else if (((step.ns != NULL) == (ns != NULL)) &&
 2021: 		(name != NULL) &&
 2022: 		(step.name[0] == name[0]) &&
 2023: 		xmlStrEqual(step.name, name) &&
 2024: 		((step.ns == ns) || xmlStrEqual(step.ns, ns)))
 2025: 	    {
 2026: 		match = 1;	    
 2027: 	    }	 
 2028: #if 0 
 2029: /*
 2030: * TODO: Pointer comparison won't work, since not guaranteed that the given
 2031: *  values are in the same dict; especially if it's the namespace name,
 2032: *  normally coming from ns->href. We need a namespace dict mechanism !
 2033: */
 2034: 	    } else if (comp->dict) {
 2035: 		if (step.name == NULL) {
 2036: 		    if (step.ns == NULL)
 2037: 			match = 1;
 2038: 		    else
 2039: 			match = (step.ns == ns);
 2040: 		} else {
 2041: 		    match = ((step.name == name) && (step.ns == ns));
 2042: 		}
 2043: #endif /* if 0 ------------------------------------------------------- */	    
 2044: 	    if (match) {		
 2045: 		final = step.flags & XML_STREAM_STEP_FINAL;
 2046: 		if (desc) {
 2047: 		    if (final) {
 2048: 			ret = 1;
 2049: 		    } else {
 2050: 			/* descending match create a new state */
 2051: 			xmlStreamCtxtAddState(stream, stepNr + 1,
 2052: 			                      stream->level + 1);
 2053: 		    }
 2054: 		} else {
 2055: 		    if (final) {
 2056: 			ret = 1;
 2057: 		    } else {
 2058: 			xmlStreamCtxtAddState(stream, stepNr + 1,
 2059: 			                      stream->level + 1);
 2060: 		    }
 2061: 		}
 2062: 		if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) {
 2063: 		    /*
 2064: 		    * Check if we have a special case like "foo/bar//.", where
 2065: 		    * "foo" is selected as well.
 2066: 		    */
 2067: 		    ret = 1;
 2068: 		}
 2069: 	    }	    
 2070: 	    if (((comp->flags & XML_STREAM_DESC) == 0) &&
 2071: 		((! match) || final))  {
 2072: 		/*
 2073: 		* Mark this expression as blocked for any evaluation at
 2074: 		* deeper levels. Note that this includes "/foo"
 2075: 		* expressions if the *pattern* behaviour is used.
 2076: 		*/
 2077: 		stream->blockLevel = stream->level +1;
 2078: 	    }
 2079: next_state:
 2080: 	    i++;
 2081: 	}
 2082: 
 2083: 	stream->level++;
 2084: 
 2085: 	/*
 2086: 	* Re/enter the expression.
 2087: 	* Don't reenter if it's an absolute expression like "/foo",
 2088: 	*   except "//foo".
 2089: 	*/
 2090: 	step = comp->steps[0];
 2091: 	if (step.flags & XML_STREAM_STEP_ROOT)
 2092: 	    goto stream_next;
 2093: 
 2094: 	desc = step.flags & XML_STREAM_STEP_DESC;
 2095: 	if (stream->flags & XML_PATTERN_NOTPATTERN) {
 2096: 	    /*
 2097: 	    * Re/enter the expression if it is a "descendant" one,
 2098: 	    * or if we are at the 1st level of evaluation.
 2099: 	    */
 2100: 	    
 2101: 	    if (stream->level == 1) {
 2102: 		if (XML_STREAM_XS_IDC(stream)) {
 2103: 		    /*
 2104: 		    * XS-IDC: The missing "self::node()" will always
 2105: 		    * match the first given node.
 2106: 		    */
 2107: 		    goto stream_next;
 2108: 		} else
 2109: 		    goto compare;
 2110: 	    }	    
 2111: 	    /*
 2112: 	    * A "//" is always reentrant.
 2113: 	    */
 2114: 	    if (desc)
 2115: 		goto compare;
 2116: 
 2117: 	    /*
 2118: 	    * XS-IDC: Process the 2nd level, since the missing
 2119: 	    * "self::node()" is responsible for the 2nd level being
 2120: 	    * the real start level.	    
 2121: 	    */	    
 2122: 	    if ((stream->level == 2) && XML_STREAM_XS_IDC(stream))
 2123: 		goto compare;
 2124: 
 2125: 	    goto stream_next;
 2126: 	}
 2127: 	
 2128: compare:
 2129: 	/*
 2130: 	* Check expected node-type.
 2131: 	*/
 2132: 	if (step.nodeType != nodeType) {
 2133: 	    if (nodeType == XML_ATTRIBUTE_NODE)
 2134: 		goto stream_next;
 2135: 	    else if (step.nodeType != XML_STREAM_ANY_NODE)
 2136: 		goto stream_next;	     
 2137: 	}
 2138: 	/*
 2139: 	* Compare local/namespace-name.
 2140: 	*/
 2141: 	match = 0;
 2142: 	if (step.nodeType == XML_STREAM_ANY_NODE) {
 2143: 	    match = 1;
 2144: 	} else if (step.name == NULL) {
 2145: 	    if (step.ns == NULL) {
 2146: 		/*
 2147: 		* This lets through all elements/attributes.
 2148: 		*/
 2149: 		match = 1;
 2150: 	    } else if (ns != NULL)
 2151: 		match = xmlStrEqual(step.ns, ns);
 2152: 	} else if (((step.ns != NULL) == (ns != NULL)) &&
 2153: 	    (name != NULL) &&
 2154: 	    (step.name[0] == name[0]) &&
 2155: 	    xmlStrEqual(step.name, name) &&
 2156: 	    ((step.ns == ns) || xmlStrEqual(step.ns, ns)))
 2157: 	{
 2158: 	    match = 1;	    
 2159: 	}	    
 2160: 	final = step.flags & XML_STREAM_STEP_FINAL;
 2161: 	if (match) {	    
 2162: 	    if (final)
 2163: 		ret = 1;
 2164: 	    else
 2165: 		xmlStreamCtxtAddState(stream, 1, stream->level);
 2166: 	    if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) {
 2167: 		/*
 2168: 		* Check if we have a special case like "foo//.", where
 2169: 		* "foo" is selected as well.
 2170: 		*/
 2171: 		ret = 1;
 2172: 	    }
 2173: 	}
 2174: 	if (((comp->flags & XML_STREAM_DESC) == 0) &&
 2175: 	    ((! match) || final))  {
 2176: 	    /*
 2177: 	    * Mark this expression as blocked for any evaluation at
 2178: 	    * deeper levels.
 2179: 	    */
 2180: 	    stream->blockLevel = stream->level;
 2181: 	}
 2182: 
 2183: stream_next:
 2184:         stream = stream->next;
 2185:     } /* while stream != NULL */
 2186:  
 2187:     if (err > 0)
 2188:         ret = -1;
 2189: #ifdef DEBUG_STREAMING
 2190:     xmlDebugStreamCtxt(orig, ret);
 2191: #endif
 2192:     return(ret);
 2193: }
 2194: 
 2195: /**
 2196:  * xmlStreamPush:
 2197:  * @stream: the stream context
 2198:  * @name: the current name
 2199:  * @ns: the namespace name
 2200:  *
 2201:  * Push new data onto the stream. NOTE: if the call xmlPatterncompile()
 2202:  * indicated a dictionary, then strings for name and ns will be expected
 2203:  * to come from the dictionary.
 2204:  * Both @name and @ns being NULL means the / i.e. the root of the document.
 2205:  * This can also act as a reset.
 2206:  * Otherwise the function will act as if it has been given an element-node.
 2207:  *
 2208:  * Returns: -1 in case of error, 1 if the current state in the stream is a
 2209:  *    match and 0 otherwise.
 2210:  */
 2211: int
 2212: xmlStreamPush(xmlStreamCtxtPtr stream,
 2213:               const xmlChar *name, const xmlChar *ns) {
 2214:     return (xmlStreamPushInternal(stream, name, ns, (int) XML_ELEMENT_NODE));
 2215: }
 2216: 
 2217: /**
 2218:  * xmlStreamPushNode:
 2219:  * @stream: the stream context
 2220:  * @name: the current name
 2221:  * @ns: the namespace name
 2222:  * @nodeType: the type of the node being pushed
 2223:  *
 2224:  * Push new data onto the stream. NOTE: if the call xmlPatterncompile()
 2225:  * indicated a dictionary, then strings for name and ns will be expected
 2226:  * to come from the dictionary.
 2227:  * Both @name and @ns being NULL means the / i.e. the root of the document.
 2228:  * This can also act as a reset.
 2229:  * Different from xmlStreamPush() this function can be fed with nodes of type:
 2230:  * element-, attribute-, text-, cdata-section-, comment- and
 2231:  * processing-instruction-node.
 2232:  *
 2233:  * Returns: -1 in case of error, 1 if the current state in the stream is a
 2234:  *    match and 0 otherwise.
 2235:  */
 2236: int
 2237: xmlStreamPushNode(xmlStreamCtxtPtr stream,
 2238: 		  const xmlChar *name, const xmlChar *ns,
 2239: 		  int nodeType)
 2240: {
 2241:     return (xmlStreamPushInternal(stream, name, ns,
 2242: 	nodeType));
 2243: }
 2244: 
 2245: /**
 2246: * xmlStreamPushAttr:
 2247: * @stream: the stream context
 2248: * @name: the current name
 2249: * @ns: the namespace name
 2250: *
 2251: * Push new attribute data onto the stream. NOTE: if the call xmlPatterncompile()
 2252: * indicated a dictionary, then strings for name and ns will be expected
 2253: * to come from the dictionary.
 2254: * Both @name and @ns being NULL means the / i.e. the root of the document.
 2255: * This can also act as a reset.
 2256: * Otherwise the function will act as if it has been given an attribute-node.
 2257: *
 2258: * Returns: -1 in case of error, 1 if the current state in the stream is a
 2259: *    match and 0 otherwise.
 2260: */
 2261: int
 2262: xmlStreamPushAttr(xmlStreamCtxtPtr stream,
 2263: 		  const xmlChar *name, const xmlChar *ns) {
 2264:     return (xmlStreamPushInternal(stream, name, ns, (int) XML_ATTRIBUTE_NODE));
 2265: }
 2266: 
 2267: /**
 2268:  * xmlStreamPop:
 2269:  * @stream: the stream context
 2270:  *
 2271:  * push one level from the stream.
 2272:  *
 2273:  * Returns: -1 in case of error, 0 otherwise.
 2274:  */
 2275: int
 2276: xmlStreamPop(xmlStreamCtxtPtr stream) {
 2277:     int i, lev;
 2278:     
 2279:     if (stream == NULL)
 2280:         return(-1);
 2281:     while (stream != NULL) {
 2282: 	/*
 2283: 	* Reset block-level.
 2284: 	*/
 2285: 	if (stream->blockLevel == stream->level)
 2286: 	    stream->blockLevel = -1;
 2287: 
 2288: 	/*
 2289: 	 *  stream->level can be zero when XML_FINAL_IS_ANY_NODE is set
 2290: 	 *  (see the thread at
 2291: 	 *  http://mail.gnome.org/archives/xslt/2008-July/msg00027.html)
 2292: 	 */
 2293: 	if (stream->level)
 2294: 	    stream->level--;
 2295: 	/*
 2296: 	 * Check evolution of existing states
 2297: 	 */	
 2298: 	for (i = stream->nbState -1; i >= 0; i--) {
 2299: 	    /* discard obsoleted states */
 2300: 	    lev = stream->states[(2 * i) + 1];
 2301: 	    if (lev > stream->level)
 2302: 		stream->nbState--;
 2303: 	    if (lev <= stream->level)
 2304: 		break;
 2305: 	}
 2306: 	stream = stream->next;
 2307:     }
 2308:     return(0);
 2309: }
 2310: 
 2311: /**
 2312:  * xmlStreamWantsAnyNode:
 2313:  * @streamCtxt: the stream context
 2314:  *
 2315:  * Query if the streaming pattern additionally needs to be fed with
 2316:  * text-, cdata-section-, comment- and processing-instruction-nodes.
 2317:  * If the result is 0 then only element-nodes and attribute-nodes
 2318:  * need to be pushed.
 2319:  *
 2320:  * Returns: 1 in case of need of nodes of the above described types,
 2321:  *          0 otherwise. -1 on API errors.
 2322:  */
 2323: int
 2324: xmlStreamWantsAnyNode(xmlStreamCtxtPtr streamCtxt)
 2325: {    
 2326:     if (streamCtxt == NULL)
 2327: 	return(-1);
 2328:     while (streamCtxt != NULL) {
 2329: 	if (streamCtxt->comp->flags & XML_STREAM_FINAL_IS_ANY_NODE)	
 2330: 	    return(1);
 2331: 	streamCtxt = streamCtxt->next;
 2332:     }
 2333:     return(0);
 2334: }
 2335: 
 2336: /************************************************************************
 2337:  *									*
 2338:  *			The public interfaces				*
 2339:  *									*
 2340:  ************************************************************************/
 2341: 
 2342: /**
 2343:  * xmlPatterncompile:
 2344:  * @pattern: the pattern to compile
 2345:  * @dict: an optional dictionary for interned strings
 2346:  * @flags: compilation flags, see xmlPatternFlags
 2347:  * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
 2348:  *
 2349:  * Compile a pattern.
 2350:  *
 2351:  * Returns the compiled form of the pattern or NULL in case of error
 2352:  */
 2353: xmlPatternPtr
 2354: xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags,
 2355:                   const xmlChar **namespaces) {
 2356:     xmlPatternPtr ret = NULL, cur;
 2357:     xmlPatParserContextPtr ctxt = NULL;
 2358:     const xmlChar *or, *start;
 2359:     xmlChar *tmp = NULL;
 2360:     int type = 0;
 2361:     int streamable = 1;
 2362: 
 2363:     if (pattern == NULL)
 2364:         return(NULL);
 2365: 
 2366:     start = pattern;
 2367:     or = start;
 2368:     while (*or != 0) {
 2369: 	tmp = NULL;
 2370: 	while ((*or != 0) && (*or != '|')) or++;
 2371:         if (*or == 0)
 2372: 	    ctxt = xmlNewPatParserContext(start, dict, namespaces);
 2373: 	else {
 2374: 	    tmp = xmlStrndup(start, or - start);
 2375: 	    if (tmp != NULL) {
 2376: 		ctxt = xmlNewPatParserContext(tmp, dict, namespaces);
 2377: 	    }
 2378: 	    or++;
 2379: 	}
 2380: 	if (ctxt == NULL) goto error;	
 2381: 	cur = xmlNewPattern();
 2382: 	if (cur == NULL) goto error;
 2383: 	/*
 2384: 	* Assign string dict.
 2385: 	*/
 2386: 	if (dict) {	    
 2387: 	    cur->dict = dict;
 2388: 	    xmlDictReference(dict);
 2389: 	}
 2390: 	if (ret == NULL)
 2391: 	    ret = cur;
 2392: 	else {
 2393: 	    cur->next = ret->next;
 2394: 	    ret->next = cur;
 2395: 	}
 2396: 	cur->flags = flags;
 2397: 	ctxt->comp = cur;
 2398: 
 2399: 	if (XML_STREAM_XS_IDC(cur))
 2400: 	    xmlCompileIDCXPathPath(ctxt);
 2401: 	else
 2402: 	    xmlCompilePathPattern(ctxt);
 2403: 	if (ctxt->error != 0)
 2404: 	    goto error;
 2405: 	xmlFreePatParserContext(ctxt);
 2406: 	ctxt = NULL;
 2407: 
 2408: 
 2409:         if (streamable) {
 2410: 	    if (type == 0) {
 2411: 	        type = cur->flags & (PAT_FROM_ROOT | PAT_FROM_CUR);
 2412: 	    } else if (type == PAT_FROM_ROOT) {
 2413: 	        if (cur->flags & PAT_FROM_CUR)
 2414: 		    streamable = 0;
 2415: 	    } else if (type == PAT_FROM_CUR) {
 2416: 	        if (cur->flags & PAT_FROM_ROOT)
 2417: 		    streamable = 0;
 2418: 	    }
 2419: 	}
 2420: 	if (streamable)
 2421: 	    xmlStreamCompile(cur);
 2422: 	if (xmlReversePattern(cur) < 0)
 2423: 	    goto error;
 2424: 	if (tmp != NULL) {
 2425: 	    xmlFree(tmp);
 2426: 	    tmp = NULL;
 2427: 	}
 2428: 	start = or;
 2429:     }
 2430:     if (streamable == 0) {
 2431:         cur = ret;
 2432: 	while (cur != NULL) {
 2433: 	    if (cur->stream != NULL) {
 2434: 		xmlFreeStreamComp(cur->stream);
 2435: 		cur->stream = NULL;
 2436: 	    }
 2437: 	    cur = cur->next;
 2438: 	}
 2439:     }
 2440: 
 2441:     return(ret);
 2442: error:
 2443:     if (ctxt != NULL) xmlFreePatParserContext(ctxt);
 2444:     if (ret != NULL) xmlFreePattern(ret);
 2445:     if (tmp != NULL) xmlFree(tmp);
 2446:     return(NULL);
 2447: }
 2448: 
 2449: /**
 2450:  * xmlPatternMatch:
 2451:  * @comp: the precompiled pattern
 2452:  * @node: a node
 2453:  *
 2454:  * Test whether the node matches the pattern
 2455:  *
 2456:  * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
 2457:  */
 2458: int
 2459: xmlPatternMatch(xmlPatternPtr comp, xmlNodePtr node)
 2460: {
 2461:     int ret = 0;
 2462: 
 2463:     if ((comp == NULL) || (node == NULL))
 2464:         return(-1);
 2465: 
 2466:     while (comp != NULL) {
 2467:         ret = xmlPatMatch(comp, node);
 2468: 	if (ret != 0)
 2469: 	    return(ret);
 2470: 	comp = comp->next;
 2471:     }
 2472:     return(ret);
 2473: }
 2474: 
 2475: /**
 2476:  * xmlPatternGetStreamCtxt:
 2477:  * @comp: the precompiled pattern
 2478:  *
 2479:  * Get a streaming context for that pattern
 2480:  * Use xmlFreeStreamCtxt to free the context.
 2481:  *
 2482:  * Returns a pointer to the context or NULL in case of failure
 2483:  */
 2484: xmlStreamCtxtPtr
 2485: xmlPatternGetStreamCtxt(xmlPatternPtr comp)
 2486: {
 2487:     xmlStreamCtxtPtr ret = NULL, cur;
 2488: 
 2489:     if ((comp == NULL) || (comp->stream == NULL))
 2490:         return(NULL);
 2491: 
 2492:     while (comp != NULL) {
 2493:         if (comp->stream == NULL)
 2494: 	    goto failed;
 2495: 	cur = xmlNewStreamCtxt(comp->stream);
 2496: 	if (cur == NULL)
 2497: 	    goto failed;
 2498: 	if (ret == NULL)
 2499: 	    ret = cur;
 2500: 	else {
 2501: 	    cur->next = ret->next;
 2502: 	    ret->next = cur;
 2503: 	}
 2504: 	cur->flags = comp->flags;
 2505: 	comp = comp->next;
 2506:     }
 2507:     return(ret);
 2508: failed:
 2509:     xmlFreeStreamCtxt(ret);
 2510:     return(NULL);
 2511: }
 2512: 
 2513: /**
 2514:  * xmlPatternStreamable:
 2515:  * @comp: the precompiled pattern
 2516:  *
 2517:  * Check if the pattern is streamable i.e. xmlPatternGetStreamCtxt()
 2518:  * should work.
 2519:  *
 2520:  * Returns 1 if streamable, 0 if not and -1 in case of error.
 2521:  */
 2522: int
 2523: xmlPatternStreamable(xmlPatternPtr comp) {
 2524:     if (comp == NULL)
 2525:         return(-1);
 2526:     while (comp != NULL) {
 2527:         if (comp->stream == NULL)
 2528: 	    return(0);
 2529: 	comp = comp->next;
 2530:     }
 2531:     return(1);
 2532: }
 2533: 
 2534: /**
 2535:  * xmlPatternMaxDepth:
 2536:  * @comp: the precompiled pattern
 2537:  *
 2538:  * Check the maximum depth reachable by a pattern
 2539:  *
 2540:  * Returns -2 if no limit (using //), otherwise the depth,
 2541:  *         and -1 in case of error
 2542:  */
 2543: int
 2544: xmlPatternMaxDepth(xmlPatternPtr comp) {
 2545:     int ret = 0, i;
 2546:     if (comp == NULL)
 2547:         return(-1);
 2548:     while (comp != NULL) {
 2549:         if (comp->stream == NULL)
 2550: 	    return(-1);
 2551: 	for (i = 0;i < comp->stream->nbStep;i++)
 2552: 	    if (comp->stream->steps[i].flags & XML_STREAM_STEP_DESC)
 2553: 	        return(-2);
 2554: 	if (comp->stream->nbStep > ret)
 2555: 	    ret = comp->stream->nbStep;
 2556: 	comp = comp->next;
 2557:     }
 2558:     return(ret);
 2559: }
 2560: 
 2561: /**
 2562:  * xmlPatternMinDepth:
 2563:  * @comp: the precompiled pattern
 2564:  *
 2565:  * Check the minimum depth reachable by a pattern, 0 mean the / or . are
 2566:  * part of the set.
 2567:  *
 2568:  * Returns -1 in case of error otherwise the depth,
 2569:  *         
 2570:  */
 2571: int
 2572: xmlPatternMinDepth(xmlPatternPtr comp) {
 2573:     int ret = 12345678;
 2574:     if (comp == NULL)
 2575:         return(-1);
 2576:     while (comp != NULL) {
 2577:         if (comp->stream == NULL)
 2578: 	    return(-1);
 2579: 	if (comp->stream->nbStep < ret)
 2580: 	    ret = comp->stream->nbStep;
 2581: 	if (ret == 0)
 2582: 	    return(0);
 2583: 	comp = comp->next;
 2584:     }
 2585:     return(ret);
 2586: }
 2587: 
 2588: /**
 2589:  * xmlPatternFromRoot:
 2590:  * @comp: the precompiled pattern
 2591:  *
 2592:  * Check if the pattern must be looked at from the root.
 2593:  *
 2594:  * Returns 1 if true, 0 if false and -1 in case of error
 2595:  */
 2596: int
 2597: xmlPatternFromRoot(xmlPatternPtr comp) {
 2598:     if (comp == NULL)
 2599:         return(-1);
 2600:     while (comp != NULL) {
 2601:         if (comp->stream == NULL)
 2602: 	    return(-1);
 2603: 	if (comp->flags & PAT_FROM_ROOT)
 2604: 	    return(1);
 2605: 	comp = comp->next;
 2606:     }
 2607:     return(0);
 2608: 
 2609: }
 2610: 
 2611: #define bottom_pattern
 2612: #include "elfgcchack.h"
 2613: #endif /* LIBXML_PATTERN_ENABLED */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>