Annotation of embedaddon/libxml2/pattern.c, revision 1.1
1.1 ! misho 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>