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

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

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