Annotation of embedaddon/libxml2/pattern.c, revision 1.1.1.3

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

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