1/*----------------------------------------------------------------------------
2|   Copyright (c) 1999-2001 Jochen Loewer (loewerj@hotmail.com)
3|-----------------------------------------------------------------------------
4|
5|   $Id: domxpath.c,v 1.96 2007/08/23 16:33:36 rolf Exp $
6|
7|
8|   A XPath implementation (lexer/parser/evaluator) for tDOM,
9|   the DOM implementation for Tcl.
10|   Based on November 16 1999 Recommendation of the W3C
11|   (http://www.w3.org/TR/1999/REC-xslt-19991116)
12|
13|
14|   The contents of this file are subject to the Mozilla Public License
15|   Version 1.1 (the "License"); you may not use this file except in
16|   compliance with the License. You may obtain a copy of the License at
17|   http://www.mozilla.org/MPL/
18|
19|   Software distributed under the License is distributed on an "AS IS"
20|   basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
21|   License for the specific language governing rights and limitations
22|   under the License.
23|
24|   The Original Code is tDOM.
25|
26|   The Initial Developer of the Original Code is Jochen Loewer
27|   Portions created by Jochen Loewer are Copyright (C) 1999 - 2001
28|   Jochen Loewer. All Rights Reserved.
29|
30|   Portions created by Zoran Vasiljevic are Copyright (C) 2000-2002
31|   Zoran Vasiljevic. All Rights Reserved.
32|
33|   Portions created by Rolf Ade are Copyright (C) 1999-2007
34|   Rolf Ade. All Rights Reserved.
35|
36|   Contributor(s):
37|       April00  Rolf Ade   Add support for following/preceding/
38|                           precedingSibling axis plus several
39|                           bug fixes
40|
41|       Aug00    Rolf Ade   Rewrite of comparisons plus several
42|                           bug fixes/reports
43|
44|       Aug01    Rolf Ade   id(), unparsed-entity(), lang(), fixes
45|
46|        2002    Rolf Ade   Namespace aware nodetests and NS wildcard
47|                           expr, namespace aware variables, keys and
48|                           function, made lexer utf-8 aware, node sets
49|                           could now include nodes of different types,
50|                           better IEEE 754 rules support, code
51|                           restructured, serveral optimizations and bug
52|                           fixes.
53|
54|   written by Jochen Loewer
55|   July, 1999
56|
57\---------------------------------------------------------------------------*/
58
59
60
61/*----------------------------------------------------------------------------
62|   Includes
63|
64\---------------------------------------------------------------------------*/
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68#include <float.h>
69#include <math.h>
70#include <limits.h>
71#include <ctype.h>
72#include <dom.h>
73#include <domxpath.h>
74#include <domxslt.h>
75
76
77/*----------------------------------------------------------------------------
78|   Macros
79|
80\---------------------------------------------------------------------------*/
81#define JDBG(x)
82#define DBG(x)
83#define DDBG(x)
84#define TRACE(x)         DDBG(fprintf(stderr,(x)))
85#define TRACE1(x,a)      DDBG(fprintf(stderr,(x),(a)))
86#define TRACE2(x,a,b)    DDBG(fprintf(stderr,(x),(a),(b)))
87#define TRACE3(x,a,b,c)  DDBG(fprintf(stderr,(x),(a),(b),(c)))
88
89#define INITIAL_SIZE     100
90
91#define ADD_TOKEN(t)  if ((l+1)>=allocated) {                                \
92                       tokens=(XPathTokens)REALLOC((char*)tokens, 2*allocated\
93                                                      *sizeof(XPathToken));  \
94                          allocated = allocated * 2;                         \
95                      }                                                      \
96                      tokens[l].token     = (t);                             \
97                      tokens[l++].pos     = i;                               \
98                      tokens[l].token     = EOS;                             \
99                      tokens[l].strvalue  = NULL;                            \
100                      tokens[l].intvalue  = 0;                               \
101                      tokens[l].realvalue = 0.0;
102
103
104#define DeclProduction(name) static ast name (int *l,XPathTokens tokens,char **errMsg)
105
106#define Production(name)  static ast name (int *l,XPathTokens tokens,char **errMsg) \
107                          { char *__func = #name;                                   \
108                            ast a = NULL;                                           \
109                            TRACE2("\nProduction "#name": start l=%d next:%s\n",    \
110                                                *l,token2str[tokens[*l].token]);
111
112#define EndProduction       TRACE3("EndProd %s: start l=%d next:%s\n",    \
113                                __func, *l,token2str[tokens[*l].token]);  \
114                            DDBG(printAst(0,a);)                          \
115                            return a;                                     \
116                          }
117
118#define LA                tokens[*l].token
119#define LA2               tokens[*l+1].token
120#define LA3               tokens[*l+2].token
121/* #define Recurse(p)        rc=p(l,tokens,errMsg);if(rc==NULL)return rc;*/
122#define Recurse(p)        p(l,tokens,errMsg)
123
124#define Consume(tk)       if (tokens[*l].token == tk) {      \
125                              TRACE2("Production %s:   %s consumed\n", \
126                                 __func, token2str[tokens[*l].token]); \
127                              (*l)++;                         \
128                          } else {                            \
129                              if (*errMsg==NULL) {ErrExpected(#tk);} \
130                              else return a; \
131                          }
132#define STRVAL            tokens[(*l)-1].strvalue
133#define INTVAL            tokens[(*l)-1].intvalue
134#define REALVAL           tokens[(*l)-1].realvalue
135#define NEWCONS           ((ast)MALLOC(sizeof(astElem)))
136
137#define IS_STR(c,s)       (c==*(tokens[(*l)-1].strvalue))&&(strcmp(tokens[(*l)-1].strvalue,s)==0)
138#define IS_FUNC(c,s)      ((*(step->strvalue)==(c)) && (strcmp((s),step->strvalue)==0))
139
140
141#define ErrExpected(msg)  *errMsg = (char*)MALLOC(255);        \
142                          **errMsg = '\0';                     \
143                          strcpy(*errMsg, __func);             \
144                          strcat(*errMsg, ": Expected " #msg); \
145                          return a;
146
147#define CHECK_RC          if (rc) return rc
148#define checkRsAddNode(rs,node)    if (useFastAdd) rsAddNodeFast( rs,node); \
149                                   else rsAddNode (rs,node);
150
151/*----------------------------------------------------------------------------
152|   Types for Lexer
153|
154\---------------------------------------------------------------------------*/
155typedef enum {
156    LPAR, RPAR, LBRACKET, RBRACKET, DOT, DOTDOT, ATTRIBUTEPREFIX,
157    ATTRIBUTE, COMMA,  COLONCOLON, LITERAL, NSPREFIX, NSWC,
158    INTNUMBER, REALNUMBER, SLASH, SLASHSLASH,
159    PIPE, PLUS, MINUS, EQUAL, NOTEQ, LT, LTE, GT, GTE,
160    AND, OR, MOD, DIV, MULTIPLY, FUNCTION, VARIABLE,
161    FQVARIABLE, WCARDNAME, COMMENT, TEXT, PINSTR, NODE, AXISNAME,
162    EOS
163} Token;
164
165static char *token2str[] = {
166    "LPAR", "RPAR", "LBRACKET", "RBRACKET", "DOT", "DOTDOT", "ATTRIBUTEPREFIX",
167    "ATTRIBUTE", "COMMA", "COLONCOLON", "LITERAL", "NSPREFIX", "NSWC",
168    "INTNUMBER", "REALNUMBER", "SLASH", "SLASHSLASH",
169    "PIPE", "PLUS", "MINUS", "EQUAL", "NOTEQ", "LT", "LTE", "GT", "GTE",
170    "AND", "OR", "MOD", "DIV", "MULTIPLY", "FUNCTION", "VARIABLE",
171    "FQVARIABLE", "WCARDNAME", "COMMENT", "TEXT", "PI", "NODE", "AXISNAME",
172    "EOS"
173};
174
175
176typedef struct {
177
178    Token  token;
179    char  *strvalue;
180    int    intvalue;
181    double realvalue;
182    int    pos;
183
184} XPathToken;
185
186typedef XPathToken *XPathTokens;
187
188
189/*----------------------------------------------------------------------------
190|   Types for abstract syntax trees
191|
192\---------------------------------------------------------------------------*/
193static char *astType2str[] = {
194    "Int", "Real", "Mult", "Div", "Mod", "UnaryMinus", "IsNSElement",
195    "IsNode", "IsComment", "IsText", "IsPI", "IsSpecificPI", "IsElement",
196    "IsFQElement", "GetVar", "GetFQVar", "Literal", "ExecFunction", "Pred",
197    "EvalSteps", "SelectRoot", "CombineSets", "Add", "Substract", "Less",
198    "LessOrEq", "Greater", "GreaterOrEq", "Equal", "NotEqual", "And", "Or",
199    "IsNSAttr", "IsAttr", "AxisAncestor", "AxisAncestorOrSelf",
200    "AxisAttribute", "AxisChild",
201    "AxisDescendant", "AxisDescendantOrSelf", "AxisFollowing",
202    "AxisFollowingSibling", "AxisNamespace", "AxisParent",
203    "AxisPreceding", "AxisPrecedingSilbing", "AxisSelf",
204    "GetContextNode", "GetParentNode", "AxisDescendantOrSelfLit",
205    "AxisDescendantLit", "SlashSlash",
206
207    "CombinePath", "IsRoot", "ToParent", "ToAncestors", "FillNodeList",
208    "FillWithCurrentNode",
209    "ExecIdKey"
210};
211
212/*----------------------------------------------------------------------------
213|   functionTag
214|
215\---------------------------------------------------------------------------*/
216typedef enum {
217
218    f_unknown = 1,
219    f_boolean, f_ceiling, f_concat, f_contains, f_count, f_false, f_floor,
220    f_generateId, f_id, f_lang, f_last, f_localName, f_name, f_namespaceUri,
221    f_normalizeSpace, f_not, f_number, f_position, f_round, f_startsWith,
222    f_string, f_stringLength, f_substring, f_substringAfter,
223    f_substringBefore, f_sum, f_translate, f_true, f_unparsedEntityUri,
224    f_fqfunction
225
226} functionTag;
227
228/*----------------------------------------------------------------------------
229|   Prototypes / Forwards
230|
231\---------------------------------------------------------------------------*/
232DeclProduction(OrExpr);
233DeclProduction(Predicate);
234DeclProduction(RelativeLocationPath);
235DeclProduction(AbsoluteLocationPath);
236
237char *xpathFuncString (xpathResultSet  *rs );
238static int xpathEvalStep (ast step, domNode *ctxNode, domNode *exprContext,
239                          int position, xpathResultSet *nodeList,
240                          xpathCBs *cbs, xpathResultSet *result,
241                          int *docOrder, char **errMsg);
242
243static int xpathEvalPredicate (ast steps, domNode *exprContext,
244                               xpathResultSet *result,
245                               xpathResultSet *stepResult,
246                               xpathCBs *cbs, int *docOrder, char **errMsg);
247
248/*----------------------------------------------------------------------------
249|   xpath result set functions
250|
251\---------------------------------------------------------------------------*/
252
253void xpathRSFree ( xpathResultSet *rs ) {
254
255    if (rs->type == xNodeSetResult) {
256        if (!rs->intvalue) {
257            if (rs->nodes) FREE((char*)rs->nodes);
258        }
259        rs->nr_nodes  = 0;
260    } else
261    if (rs->type == StringResult) {
262        if (rs->string) FREE((char*)rs->string);
263    }
264    rs->type = EmptyResult;
265}
266
267void rsPrint ( xpathResultSet *rs ) {
268    int i = 0,l;  char tmp[80];
269    switch (rs->type) {
270        case EmptyResult:
271             fprintf(stderr, "empty result \n");
272             break;
273
274        case BoolResult:
275             fprintf(stderr, "boolean result: %d \n", rs->intvalue);
276             break;
277
278        case IntResult:
279             fprintf(stderr, "int result: %d \n", rs->intvalue);
280             break;
281
282        case RealResult:
283             fprintf(stderr, "real result: %f \n", rs->realvalue);
284             break;
285
286        case StringResult:
287             fprintf(stderr, "string result: -%*s-\n", rs->string_len,
288                                                       rs->string);
289             break;
290
291        case xNodeSetResult:
292             if (!i) fprintf(stderr,"nodeSet result (len %d):\n",rs->nr_nodes);
293             for (i=0; i<rs->nr_nodes; i++) {
294                 if (rs->nodes[i]->nodeType == ELEMENT_NODE) {
295                     fprintf(stderr, "%2d domNode%p %s ",
296                             i, rs->nodes[i], rs->nodes[i]->nodeName);
297                     if (rs->nodes[i]->firstChild &&
298                         rs->nodes[i]->firstChild->nodeType == TEXT_NODE)
299                     {
300                         l = ((domTextNode*)rs->nodes[i]->firstChild)->valueLength;
301                         if (l > 25) l = 25;
302                         memcpy(tmp, ((domTextNode*)rs->nodes[i]->firstChild)->nodeValue, l);
303                         tmp[l] = '\0';
304                         fprintf(stderr, "'%s'", tmp);
305                     }
306                     fprintf(stderr, "\n");
307                 } else
308                 if (rs->nodes[i]->nodeType == TEXT_NODE) {
309                     l = ((domTextNode*)rs->nodes[i])->valueLength;
310                     if (l > 60) l = 60;
311                     memcpy(tmp, ((domTextNode*)rs->nodes[i])->nodeValue, l);
312                     tmp[l] = '\0';
313                     fprintf(stderr, "%2d domNode%p text:'%s' \n",
314                             i, rs->nodes[i], tmp);
315                 } else
316                 if (rs->nodes[i]->nodeType == COMMENT_NODE) {
317                     l = ((domTextNode*)rs->nodes[i])->valueLength;
318                     memcpy (tmp, "<!--", 4);
319                     if (l > 60) l = 60;
320                     memcpy(&tmp[4], ((domTextNode*)rs->nodes[i])->nodeValue, l);
321                     memcpy(&tmp[4+l], "-->", 3);
322                     tmp[7+l] = '\0';
323                     fprintf(stderr, "%2d domNode%p text:'%s' \n",
324                             i, rs->nodes[i], tmp);
325                 } else
326                 if (rs->nodes[i]->nodeType == ATTRIBUTE_NODE) {
327                     fprintf(stderr, "%2d Attr %s='%*s'\n", i,
328                             ((domAttrNode*)rs->nodes[i])->nodeName,
329                             ((domAttrNode*)rs->nodes[i])->valueLength,
330                             ((domAttrNode*)rs->nodes[i])->nodeValue);
331                 }
332             }
333             break;
334         case NaNResult: fprintf (stderr, "NaN result\n"); break;
335         case InfResult: fprintf (stderr, "Inf result\n"); break;
336         case NInfResult: fprintf (stderr, "-Inf result\n"); break;
337
338         default:
339             fprintf (stderr, "unknown result type: '%d'!!!\n", rs->type);
340             break;
341
342    }
343}
344void rsSetReal ( xpathResultSet *rs, double d) {
345
346    rs->type = RealResult;
347    rs->realvalue = d;
348}
349void rsSetNaN ( xpathResultSet *rs ) {
350    rs->type = NaNResult;
351}
352void rsSetInf ( xpathResultSet *rs ) {
353    rs->type = InfResult;
354}
355void rsSetNInf ( xpathResultSet *rs ) {
356    rs->type = NInfResult;
357}
358void rsSetInt ( xpathResultSet *rs, int i) {
359
360    rs->type = IntResult;
361    rs->intvalue = i;
362}
363void rsSetBool ( xpathResultSet *rs, int i) {
364
365    rs->type = BoolResult;
366    rs->intvalue = (i ? 1 : 0);
367}
368void rsSetString ( xpathResultSet *rs, const char *s) {
369
370    rs->type = StringResult;
371    if (s) {
372        rs->string     = tdomstrdup(s);
373        rs->string_len = strlen(s);
374    } else {
375        rs->string     = tdomstrdup("");
376        rs->string_len = 0;
377    }
378    rs->nr_nodes = 0;
379}
380
381void rsAddNode ( xpathResultSet *rs, domNode *node) {
382
383    if ((rs->type != EmptyResult) && (rs->type != xNodeSetResult)) {
384        domPanic("Can not add node to non NodeSetResult xpathResultSet!");
385    }
386    if (rs->type == EmptyResult) {
387
388        rs->type      = xNodeSetResult;
389        rs->nodes     = (domNode**)MALLOC(INITIAL_SIZE * sizeof(domNode*));
390        rs->allocated = INITIAL_SIZE;
391        rs->nr_nodes  = 1;
392        rs->nodes[0]  = node;
393
394    } else {
395        int insertIndex;
396        int i;
397
398        if (rs->intvalue) {
399            /* we must do a copy-on-write */
400            domNode **nodes;
401            nodes = (domNode**)MALLOC(rs->allocated * sizeof(domNode*));
402            memcpy (nodes, rs->nodes, sizeof(domNode*) * rs->nr_nodes);
403            rs->nodes = nodes;
404            rs->intvalue = 0;
405        }
406
407        insertIndex = rs->nr_nodes;
408        for (i = rs->nr_nodes - 1; i >= 0; i--) {
409            if (node == rs->nodes[i]) return;
410            if (!domPrecedes (node, rs->nodes[i])) {
411                break;
412            }
413            insertIndex--;
414        }
415
416        if ((rs->nr_nodes+1) >= rs->allocated) {
417            rs->nodes = (domNode**)REALLOC((void*)rs->nodes,
418                                         2 * rs->allocated * sizeof(domNode*));
419            rs->allocated = rs->allocated * 2;
420        }
421        if (insertIndex == rs->nr_nodes) {
422            rs->nodes[rs->nr_nodes++] = node;
423        } else {
424            for (i = rs->nr_nodes - 1; i >= insertIndex; i--) {
425                rs->nodes[i+1] = rs->nodes[i];
426            }
427            rs->nodes[insertIndex] = node;
428            rs->nr_nodes++;
429        }
430    }
431}
432
433void rsAddNodeFast ( xpathResultSet *rs, domNode *node) {
434
435    if ((rs->type != EmptyResult) && (rs->type != xNodeSetResult)) {
436        domPanic("Can not add node to non NodeSetResult xpathResultSet!");
437    }
438    if (rs->type == EmptyResult) {
439
440        rs->type      = xNodeSetResult;
441        rs->nodes     = (domNode**)MALLOC(INITIAL_SIZE * sizeof(domNode*));
442        rs->allocated = INITIAL_SIZE;
443        rs->nr_nodes  = 1;
444        rs->nodes[0]  = node;
445
446    } else {
447        if ((rs->nr_nodes+1) >= rs->allocated) {
448            rs->nodes = (domNode**)REALLOC((void*)rs->nodes,
449                                         2 * rs->allocated * sizeof(domNode*));
450            rs->allocated = rs->allocated * 2;
451        }
452        rs->nodes[rs->nr_nodes++] = node;
453    }
454}
455
456void rsCopy ( xpathResultSet *to, xpathResultSet *from ) {
457
458    int i;
459
460    to->type       = from->type;
461    to->intvalue   = from->intvalue;
462    if (from->type == RealResult) {
463        to->realvalue  = from->realvalue;
464    } else
465    if (from->type == StringResult) {
466        to->string     = tdomstrdup(from->string);
467        to->string_len = from->string_len;
468    } else
469    if (from->type == xNodeSetResult) {
470        to->nr_nodes = from->nr_nodes;
471        to->nodes = (domNode**)MALLOC(from->nr_nodes * sizeof(domNode*));
472        for (i=0; i<from->nr_nodes; i++)
473            to->nodes[i] = from->nodes[i];
474        to->intvalue = 0;
475    }
476}
477
478
479/*----------------------------------------------------------------------------
480|   AST construct functions
481|
482\---------------------------------------------------------------------------*/
483static ast New( astType type ) {
484    ast t = NEWCONS;
485    t->type = type;
486    t->next = t->child = NULL;
487    t->strvalue  = NULL;
488    t->intvalue  = 0;
489    t->realvalue = 0.0;
490    return t;
491}
492static ast New1( astType type, ast a) {
493    ast t = NEWCONS;
494    t->type = type;
495    t->next = NULL;
496    t->child = a;
497    t->strvalue  = NULL;
498    t->intvalue  = 0;
499    t->realvalue = 0.0;
500    return t;
501}
502static ast New1WithEvalSteps( astType type, ast a) {
503    ast t = NEWCONS;
504    t->type = type;
505    t->next = NULL;
506    if (a && a->next) {
507        t->child =  New1(EvalSteps,a);
508    } else {
509        t->child =  a;
510    }
511    t->strvalue  = NULL;
512    t->intvalue  = 0;
513    t->realvalue = 0.0;
514    return t;
515}
516static ast New2( astType type, ast a, ast b ) {
517    ast t = NEWCONS;
518
519    t->type      = type;
520    t->next      = NULL;
521    t->strvalue  = NULL;
522    t->intvalue  = 0;
523    t->realvalue = 0.0;
524
525    if (a && a->next) {
526        t->child =  New1(EvalSteps,a);
527    } else {
528        t->child =  a;
529    }
530    if (b && b->next) {
531        t->child->next = New1(EvalSteps, b);
532    } else {
533        t->child->next = b;
534    }
535    return t;
536}
537
538static ast NewInt( int i ) {
539    ast t = NEWCONS;
540
541    t->type      = Int;
542    t->strvalue  = NULL;
543    t->intvalue  = i;
544    t->realvalue = 0.0;
545
546    t->next = t->child = NULL;
547    return t;
548}
549static ast NewReal( double r ) {
550    ast t = NEWCONS;
551
552    t->type      = Real;
553    t->strvalue  = NULL;
554    t->intvalue  = 0;
555    t->realvalue = r;
556
557    t->next = t->child = NULL;
558    return t;
559}
560static ast NewStr( astType type, char *str ) {
561    ast t = NEWCONS;
562
563    t->type      = type;
564    t->strvalue  = tdomstrdup(str);
565    t->intvalue  = 0;
566    t->realvalue = 0.0;
567
568    t->next = t->child = NULL;
569    return t;
570}
571static ast Append( ast m, ast n ) {
572    if (!n) return NULL;
573    if (!m) return NULL;
574
575    while (m->next != NULL) m = m->next;
576    m->next = n;
577    return m;
578}
579static ast AddChild( ast m, ast child ) {
580    if (!child) return NULL;
581    if (!m)     return NULL;
582
583    if (m->child == NULL) {
584        m->child = child;
585    } else {
586        ast c = m->child;
587        while (c->next != NULL) c = c->next;
588        c->next = child;
589    }
590    return m;
591}
592static ast AddChildWithEvalSteps( ast m, ast child ) {
593    if (!child) return NULL;
594    if (!m)     return NULL;
595
596    if (child->next) {
597        child =  New1(EvalSteps, child);
598    }
599
600    if (m->child == NULL) {
601        m->child = child;
602    } else {
603        ast c = m->child;
604        while (c->next != NULL) c = c->next;
605        c->next = child;
606    }
607    /*child->next = NULL;*/
608    return m;
609}
610static void freeAst (ast t)
611{
612    ast tmp;
613
614    while (t) {
615        tmp = t->next;
616        if (t->strvalue) FREE(t->strvalue);
617        if (t->child) freeAst (t->child);
618        FREE((char*)t);
619        t = tmp;
620    }
621}
622void printAst (int depth, ast t)
623{
624    int i;
625
626    while (t) {
627        for (i=0; i<depth; i++) fprintf(stderr, "   ");
628        fprintf(stderr, "%s ", astType2str[t->type]);
629        switch (t->type) {
630
631            case Int :        fprintf(stderr, "%d", t->intvalue);   break;
632            case Real:        fprintf(stderr, "%f", t->realvalue);  break;
633            case IsElement:
634            case IsFQElement:
635            case IsNSAttr:
636            case IsAttr:
637            case ExecFunction:
638            case Literal:
639            case GetFQVar:
640            case GetVar:      fprintf(stderr, "'%s'", t->strvalue); break;
641
642            default: break;
643        }
644        fprintf(stderr, "\n");
645        if (t->child) printAst (depth+1, t->child);
646        t = t->next;
647    }
648}
649
650
651
652
653/*----------------------------------------------------------------------------
654|   xpathFreeAst
655|
656\---------------------------------------------------------------------------*/
657void xpathFreeAst(
658    ast t
659)
660{
661    freeAst(t);
662}
663
664
665/*----------------------------------------------------------------------------
666|   xpathLexer
667|
668\---------------------------------------------------------------------------*/
669static XPathTokens xpathLexer (
670    char     *xpath,
671    domNode  *exprContext,
672    char    **prefixMappings,
673    int      *useNamespaceAxis,
674    xpathParseVarCB *varParseCB,
675    char    **errMsg
676)
677{
678    int  l, allocated;
679    int  i, k, start, offset;
680    char delim, *ps, save, tmpErr[80];
681    const char *uri;
682    XPathTokens tokens;
683    int token = EOS;
684
685
686    tokens = (XPathTokens)MALLOC(INITIAL_SIZE * sizeof(XPathToken));
687    if (tokens == NULL) {
688        *errMsg = tdomstrdup("Unable to alloc initial memory!");
689        return NULL;
690    }
691    allocated = INITIAL_SIZE;
692    l = 0;
693    tokens[l].token     = EOS;
694    tokens[l].strvalue  = NULL;
695    tokens[l].intvalue  = 0;
696    tokens[l].realvalue = 0.0;
697
698    i = 0;
699    while (xpath[i]) {
700        switch (xpath[i]) {
701
702            case ' ' :
703            case '\n':
704            case '\r':
705            case '\t': i++; continue;
706
707            case '(':  token = LPAR;     break;
708            case ')':  token = RPAR;     break;
709            case '[':  token = LBRACKET; break;
710            case ']':  token = RBRACKET; break;
711
712            case '@':  i++;
713                       while (xpath[i] && IS_XML_WHITESPACE(xpath[i])) i++;
714                       if ( isNCNameStart (&xpath[i]) ) {
715                           ps = &(xpath[i]);
716                           i += UTF8_CHAR_LEN (xpath[i]);
717                           while (xpath[i] && isNCNameChar (&xpath[i]))
718                               i += UTF8_CHAR_LEN (xpath[i]);
719                           save = xpath[i];
720                           xpath[i] = '\0';
721                           if (save == ':' && xpath[i+1] != ':') {
722                               uri = domLookupPrefixWithMappings (
723                                   exprContext, ps, prefixMappings);
724                               if (!uri) {
725                                   xpath[i] = save;
726                                   *errMsg = tdomstrdup ("Prefix doesn't"
727                                                         " resolve");
728                                   return tokens;
729                               }
730                               tokens[l].strvalue = tdomstrdup (uri);
731                               xpath[i] = save;
732                               token = ATTRIBUTEPREFIX;
733                               ADD_TOKEN (token);
734                               if (xpath[i+1] == '*') {
735                                   token = ATTRIBUTE;
736                                   tokens[l].strvalue = tdomstrdup("*");
737                                   i++;
738                               } else {
739                                   ps = &(xpath[++i]);
740                                   if (!(isNCNameStart (&xpath[i]))) {
741                                       *errMsg =
742                                           tdomstrdup ("Illegal attribute"
743                                                       " name");
744                                       return tokens;
745                                   }
746                                   i += UTF8_CHAR_LEN (xpath[i]);
747                                   while (xpath[i] && isNCNameChar (&xpath[i]))
748                                       i += UTF8_CHAR_LEN (xpath[i]);
749                                   save = xpath[i];
750                                   xpath[i] = '\0';
751                                   token = ATTRIBUTE;
752                                   tokens[l].strvalue = tdomstrdup(ps);
753                                   xpath[i--] = save;
754                               }
755                           } else {
756                               tokens[l].strvalue = tdomstrdup(ps);
757                               xpath[i] = save;
758                               token = ATTRIBUTE;
759                               i--;
760                           }
761                       } else if (xpath[i]=='*') {
762                           tokens[l].strvalue = tdomstrdup("*");
763                           token = ATTRIBUTE;
764                       } else {
765                           *errMsg = tdomstrdup("Expected attribute name");
766                           return tokens;
767                       }; break;
768
769            case ',':  token = COMMA; break;
770
771            case ':':  if (xpath[i+1] == ':') {
772                           token = COLONCOLON;
773                           i++;
774                       } else {
775                           *errMsg = tdomstrdup("Unexpected token ':'");
776                           return tokens;
777                       }; break;
778
779            case '"' :
780            case '\'': delim = xpath[i]; start = ++i;
781                       while (xpath[i] && (xpath[i] != delim)) i++;
782                       if (!xpath[i]) {
783                           *errMsg = tdomstrdup("Undetermined string");
784                           return tokens;
785                       }
786                       xpath[i] = '\0'; /* terminate string */
787                       tokens[l].strvalue = tdomstrdup(&xpath[start]);
788                       token = LITERAL;
789                       xpath[i] = delim;
790                       break;
791
792            case '/':  if (xpath[i+1] == '/') {
793                           token = SLASHSLASH;
794                           i++;
795                       } else {
796                           token = SLASH;
797                       };
798                       break;
799
800            case '|':  token = PIPE;     break;
801            case '+':  token = PLUS;     break;
802            case '-':  token = MINUS;    break;
803            case '=':  token = EQUAL;    break;
804            case '!':  if (xpath[i+1] == '=') {
805                           token = NOTEQ;
806                           i++;
807                       } else {
808                           *errMsg = tdomstrdup("Unexpected token '!'");
809                           return tokens;
810                       }; break;
811
812            case '<':  if (xpath[i+1] == '=') {
813                           token = LTE;
814                           i++;
815                       } else {
816                           token = LT;
817                       };break;
818
819            case '>':  if (xpath[i+1] == '=') {
820                           token = GTE;
821                           i++;
822                       } else {
823                           token = GT;
824                       }; break;
825
826
827            case '*':  if ((l>0)
828                          && (tokens[l-1].token != COLONCOLON)
829                          && (tokens[l-1].token != LPAR)
830                          && (tokens[l-1].token != LBRACKET)
831                          && (tokens[l-1].token != COMMA)
832                          && (tokens[l-1].token != SLASH)
833                          && (tokens[l-1].token != SLASHSLASH)
834                        ) {
835                           token = MULTIPLY;
836                       } else {
837                           token = WCARDNAME;
838                           tokens[l].strvalue = tdomstrdup("*");
839                       }; break;
840
841            case '$':  if (varParseCB) {
842                           ps = (varParseCB->parseVarCB) (
843                                    varParseCB->parseVarClientData, &xpath[i],
844                                    &offset, errMsg
845                                  );
846                           if (ps) {
847                               token = LITERAL;
848                               tokens[l].strvalue = tdomstrdup (ps);
849                               i += offset - 1;
850                           } else {
851                               return tokens;
852                           }
853                       } else {
854                           i++;
855                           if ( isNCNameStart (&xpath[i])) {
856                               ps = &(xpath[i]);
857                               i += UTF8_CHAR_LEN (xpath[i]);
858                               while (xpath[i] && isNCNameChar(&xpath[i]))
859                                   i +=  UTF8_CHAR_LEN(xpath[i]);
860                               if (xpath[i] == ':' && xpath[i+1] != ':') {
861                                   token = FQVARIABLE;
862                                   save = xpath[i];
863                                   xpath[i] = '\0';
864                                   uri = domLookupPrefixWithMappings (
865                                       exprContext, ps, prefixMappings);
866                                   if (!uri) {
867                                       xpath[i] = save;
868                                       *errMsg = tdomstrdup ("Prefix doesn't"
869                                                             " resolve");
870                                       return tokens;
871                                   }
872                                   tokens[l].strvalue = tdomstrdup (uri);
873                                   xpath[i] = save;
874                                   ADD_TOKEN (token);
875                                   ps = &(xpath[++i]);
876                                   if (!isNCNameStart (&xpath[i])) {
877                                       *errMsg = tdomstrdup ("Illegal variable"
878                                                             " name");
879                                       return tokens;
880                                   }
881                                   i += UTF8_CHAR_LEN (xpath[i]);
882                                   while (xpath[i] && isNCNameChar (&xpath[i]))
883                                       i += UTF8_CHAR_LEN (xpath[i]);
884                               }
885                               token = VARIABLE;
886                               save = xpath[i];
887                               xpath[i] = '\0';
888                               tokens[l].strvalue = tdomstrdup(ps);
889                               xpath[i--] = save;
890                           } else {
891                               *errMsg = tdomstrdup("Expected variable name");
892                               return tokens;
893                           }
894                       }
895                       break;
896
897            case '.':  if (xpath[i+1] == '.') {
898                           token = DOTDOT;
899                           i++;
900                           break;
901                       } else if (!isdigit((unsigned char)xpath[i+1])) {
902                           token = DOT;
903                           break;
904                       }
905                       /* DOT followed by digit, ie a REAL.
906                          Handled by default. Fall throu */
907
908            default:   if ( isNCNameStart (&xpath[i])) {
909                           ps = &(xpath[i]);
910                           i += UTF8_CHAR_LEN (xpath[i]);
911                           while (xpath[i] && isNCNameChar(&xpath[i])) {
912                               i += UTF8_CHAR_LEN(xpath[i]);
913                           }
914
915                           k = i;
916                           if (xpath[i] == ':') {
917                               if (xpath[i+1] == '*') {
918                                   save = xpath[i];
919                                   xpath[i] = '\0'; /* terminate */
920                                   token = NSWC;
921                                   uri = domLookupPrefixWithMappings (
922                                       exprContext, ps, prefixMappings);
923                                   if (!uri) {
924                                       xpath[i] = save;
925                                       *errMsg = tdomstrdup ("Prefix doesn't"
926                                                             " resolve");
927                                       return tokens;
928                                   }
929                                   tokens[l].strvalue = tdomstrdup (uri);
930                                   xpath[i] = save;
931                                   i++;
932                                   break;
933                               }
934                               if (xpath[i+1] != ':') {
935                                   save = xpath[i];
936                                   xpath[i] = '\0'; /* terminate */
937                                   token = NSPREFIX;
938                                   uri = domLookupPrefixWithMappings (
939                                       exprContext, ps, prefixMappings);
940                                   if (!uri) {
941                                       xpath[i] = save;
942                                       *errMsg = tdomstrdup ("Prefix doesn't"
943                                                             " resolve");
944                                       return tokens;
945                                   }
946                                   tokens[l].strvalue = tdomstrdup (uri);
947                                   xpath[i] = save;
948                                   ADD_TOKEN (token);
949                                   ps = &(xpath[++i]);
950                                   if (!(isNCNameStart (&xpath[i]))) {
951                                       *errMsg =
952                                           tdomstrdup ("Illegal character in"
953                                                       " localname");
954                                       return tokens;
955                                   }
956                                   i += UTF8_CHAR_LEN (xpath[i]);
957                                   while (xpath[i] && isNCNameChar (&xpath[i]))
958                                       i += UTF8_CHAR_LEN (xpath[i]);
959                                   k = i;
960                               }
961                           }
962                           /* read over white space */
963                           while ((xpath[k] == ' ')  ||
964                                  (xpath[k] == '\n') ||
965                                  (xpath[k] == '\r') ||
966                                  (xpath[k] == '\t')   )  k++;
967
968                           if (l>0 && tokens[l-1].token == NSPREFIX) {
969                               if (xpath[k]!='(') token = WCARDNAME;
970                               else               token = FUNCTION;
971                               save = xpath[i];
972                               xpath[i] = '\0';
973                               tokens[l].strvalue = tdomstrdup(ps);
974                               xpath[i--] = save;
975                               break;
976                           }
977
978                           if (xpath[k]=='(') {
979                               save = xpath[i];
980                               xpath[i] = '\0'; /* terminate */
981                               if (strcmp(ps,"text")==0) {
982                                   token = TEXT;
983                               } else if (strcmp(ps,"node")==0) {
984                                   token = NODE;
985                               } else if (strcmp(ps,"comment")==0) {
986                                   token = COMMENT;
987                               } else if (strcmp(ps,"processing-instruction")==0) {
988                                   token = PINSTR;
989                               } else {
990                                   if ((save!='(') && (strcmp(ps,"and")==0)) token = AND;
991                                   else
992                                   if ((save!='(') && (strcmp(ps,"or")==0))  token = OR;
993                                   else
994                                   if ((save!='(') && (strcmp(ps,"mod")==0)) token = MOD;
995                                   else
996                                   if ((save!='(') && (strcmp(ps,"div")==0)) token = DIV;
997                                   else {
998                                       token = FUNCTION;
999                                       tokens[l].strvalue = tdomstrdup(ps);
1000                                   }
1001                               }
1002                               xpath[i] = save;
1003                           } else if ((xpath[k]==':') && (xpath[k+1]==':')) {
1004                               token = AXISNAME;
1005                               save = xpath[i];
1006                               xpath[i] = '\0'; /* terminate */
1007                               tokens[l].strvalue = tdomstrdup(ps);
1008                               if (ps[0] == 'n'&& strcmp(ps, "namespace")==0) {
1009                                   *useNamespaceAxis = 1;
1010                               }
1011                               xpath[i] = save;
1012                           } else {
1013                               save = xpath[i];
1014                               xpath[i] = '\0';
1015                               if ((l>0)
1016                                   && (tokens[l-1].token != COLONCOLON)
1017                                   && (tokens[l-1].token != LPAR)
1018                                   && (tokens[l-1].token != LBRACKET)
1019                                   && (tokens[l-1].token != COMMA)
1020                                   && (tokens[l-1].token != SLASH)
1021                                   && (tokens[l-1].token != SLASHSLASH)
1022                                   && (tokens[l-1].token != PIPE)
1023                                   && (tokens[l-1].token != PLUS)
1024                                   && (tokens[l-1].token != MINUS)
1025                                   && (tokens[l-1].token != EQUAL)
1026                                   && (tokens[l-1].token != NOTEQ)
1027                                   && (tokens[l-1].token != LT)
1028                                   && (tokens[l-1].token != LTE)
1029                                   && (tokens[l-1].token != GT)
1030                                   && (tokens[l-1].token != GTE)
1031                                   && (tokens[l-1].token != AND)
1032                                   && (tokens[l-1].token != OR)
1033                                   && (tokens[l-1].token != MOD)
1034                                   && (tokens[l-1].token != DIV)
1035                                   && (tokens[l-1].token != MULTIPLY)
1036                               ) {
1037                                   if (strcmp(ps,"and")==0) {
1038                                       token = AND;
1039                                   } else if (strcmp(ps,"or")==0) {
1040                                       token = OR;
1041                                   } else if (strcmp(ps,"mod")==0) {
1042                                       token = MOD;
1043                                   } else if (strcmp(ps,"div")==0) {
1044                                       token = DIV;
1045                                   } else {
1046                                       token = WCARDNAME;
1047                                       tokens[l].strvalue = tdomstrdup(ps);
1048                                   }
1049                               } else {
1050                                   token = WCARDNAME;
1051                                   tokens[l].strvalue = tdomstrdup(ps);
1052                               }
1053                               xpath[i] = save;
1054                           }
1055                           i--;
1056                       } else if (isdigit((unsigned char)xpath[i])
1057                                  || (xpath[i] == '.')) {
1058                           if (xpath[i] == '.') {
1059                               token = REALNUMBER;
1060                           } else {
1061                               token = INTNUMBER;
1062                           }
1063                           ps = &(xpath[i++]);
1064                           while (xpath[i] && isdigit((unsigned char)xpath[i]))
1065                               i++;
1066                           if (xpath[i]=='.') {
1067                               if (token == REALNUMBER) {
1068                                   sprintf (tmpErr, "Unexpected character "
1069                                            "'%c' at position %d", xpath[i],
1070                                            i);
1071                                   *errMsg = tdomstrdup (tmpErr);
1072                                   return tokens;
1073                               }
1074                               token = REALNUMBER;
1075                               i++;
1076                               while (xpath[i]
1077                                      && isdigit((unsigned char)xpath[i])) i++;
1078                           }
1079                           save = xpath[i];
1080                           xpath[i] = '\0';
1081                           if (token == INTNUMBER) {
1082                               tokens[l].intvalue = atoi(ps);
1083                           }
1084                           tokens[l].realvalue = (double)atof(ps);
1085                           xpath[i--] = save;
1086                       } else {
1087                           sprintf (tmpErr, "Unexpected character '%c' at "
1088                                    "position %d", xpath[i], i);
1089                           *errMsg = tdomstrdup (tmpErr);
1090                           return tokens;
1091                       }
1092                       break;
1093
1094        } /* switch */
1095        ADD_TOKEN(token);
1096        i++;
1097    }
1098    ADD_TOKEN(EOS);
1099    return tokens;
1100
1101} /* xpathLexer */
1102
1103
1104
1105/*-----------------------------------------------------------------
1106|   NodeTest  production
1107|
1108\----------------------------------------------------------------*/
1109Production(NodeTest)
1110
1111    if (LA==NODE) {
1112        Consume(NODE);
1113        Consume(LPAR);
1114        Consume(RPAR);
1115        a = New (IsNode);
1116    } else
1117    if (LA==TEXT) {
1118        Consume(TEXT);
1119        Consume(LPAR);
1120        Consume(RPAR);
1121        a = New (IsText);
1122    } else
1123    if (LA==COMMENT) {
1124        Consume(COMMENT);
1125        Consume(LPAR);
1126        Consume(RPAR);
1127        a = New (IsComment);
1128    } else
1129    if (LA==PINSTR) {
1130        Consume(PINSTR);
1131        Consume(LPAR);
1132        if (LA==LITERAL) {
1133            Consume(LITERAL);
1134            a = NewStr (IsSpecificPI, STRVAL);
1135        } else {
1136            a = New (IsPI);
1137        }
1138        Consume(RPAR);
1139    } else
1140    if (LA==MULTIPLY) {
1141        Consume(MULTIPLY);
1142        a = NewStr (IsElement, "*");
1143    } else
1144    if (LA==NSPREFIX) {
1145        ast b;
1146        Consume (NSPREFIX);
1147        a = NewStr (IsFQElement, STRVAL);
1148        Consume (WCARDNAME);
1149        b = NewStr (IsElement, STRVAL);
1150        AddChild (a, b);
1151    } else
1152    if (LA==NSWC) {
1153        Consume (NSWC);
1154        a = NewStr (IsNSElement, STRVAL);
1155    } else {
1156        Consume(WCARDNAME);
1157        a = NewStr (IsElement, STRVAL);
1158    }
1159EndProduction
1160
1161
1162/*-----------------------------------------------------------------
1163|   AbbreviatedBasis  production
1164|
1165\----------------------------------------------------------------*/
1166Production(AbbreviatedBasis)
1167    if (LA==ATTRIBUTE) {
1168        Consume(ATTRIBUTE);
1169        a = New1( AxisAttribute, NewStr(IsAttr, STRVAL) );
1170    } else
1171    if (LA==ATTRIBUTEPREFIX) {
1172        ast b, c;
1173        Consume(ATTRIBUTEPREFIX);
1174        a = New (AxisAttribute);
1175        b = NewStr (IsNSAttr, STRVAL);
1176        AddChild (a, b);
1177        Consume(ATTRIBUTE);
1178        c = NewStr (IsAttr, STRVAL);
1179        AddChild (b, c);
1180    }
1181    else {
1182        a = New1( AxisChild, Recurse(NodeTest));
1183    }
1184EndProduction
1185
1186/*-----------------------------------------------------------------
1187|   getFunctionTag
1188|
1189\----------------------------------------------------------------*/
1190static functionTag
1191getFunctionTag (char *funcName)
1192{
1193    switch (funcName[0]) {
1194    case 'b':
1195        if (strcmp (funcName, "boolean")==0) return f_boolean;
1196        break;
1197    case 'c':
1198        if (strcmp (funcName, "ceiling")==0) return f_ceiling;
1199        else if (strcmp (funcName, "concat")==0) return f_concat;
1200        else if (strcmp (funcName, "contains")==0) return f_contains;
1201        else if (strcmp (funcName, "count")==0) return f_count;
1202        break;
1203    case 'f':
1204        if (strcmp (funcName, "false")==0) return f_false;
1205        else if (strcmp (funcName, "floor")==0) return f_floor;
1206        break;
1207    case 'g':
1208        if (strcmp (funcName, "generate-id")==0) return f_generateId;
1209        break;
1210    case 'i':
1211        if (strcmp (funcName, "id")==0) return f_id;
1212    case 'l':
1213        if (strcmp (funcName, "lang")==0) return f_lang;
1214        else if (strcmp (funcName, "last")==0) return f_last;
1215        else if (strcmp (funcName, "local-name")==0) return f_localName;
1216        break;
1217    case 'n':
1218        if (strcmp (funcName, "name")==0) return f_name;
1219        else if (strcmp (funcName, "namespace-uri")==0) return f_namespaceUri;
1220        else if (strcmp (funcName, "normalize-space")==0) return f_normalizeSpace;
1221        else if (strcmp (funcName, "not")==0) return f_not;
1222        else if (strcmp (funcName, "number")==0) return f_number;
1223        break;
1224    case 'p':
1225        if (strcmp (funcName, "position")==0) return f_position;
1226        break;
1227    case 'r':
1228        if (strcmp (funcName, "round")==0) return f_round;
1229        break;
1230    case 's':
1231        if (strcmp (funcName, "starts-with")==0) return f_startsWith;
1232        else if (strcmp (funcName, "string")==0) return f_string;
1233        else if (strcmp (funcName, "string-length")==0) return f_stringLength;
1234        else if (strcmp (funcName, "substring")==0) return f_substring;
1235        else if (strcmp (funcName, "substring-after")==0) return f_substringAfter;
1236        else if (strcmp (funcName, "substring-before")==0) return f_substringBefore;
1237        else if (strcmp (funcName, "sum")==0) return f_sum;
1238        break;
1239    case 't':
1240        if (strcmp (funcName, "translate")==0) return f_translate;
1241        else if (strcmp (funcName, "true")==0) return f_true;
1242        break;
1243    case 'u':
1244        if (strcmp (funcName, "unparsed-entity-uri")==0) return f_unparsedEntityUri;
1245        break;
1246    default:
1247        break;
1248    }
1249    return f_unknown;
1250}
1251
1252/*-----------------------------------------------------------------
1253|   FilterExpr  production
1254|
1255\----------------------------------------------------------------*/
1256Production(FilterExpr)
1257
1258    if (LA==VARIABLE) {
1259        Consume(VARIABLE);
1260        a = NewStr( GetVar, STRVAL);
1261
1262    } else if (LA==FQVARIABLE) {
1263        Consume(FQVARIABLE);
1264        a = NewStr( GetFQVar, STRVAL);
1265        Consume(VARIABLE);
1266        AddChild (a, NewStr( GetVar, STRVAL));
1267
1268    } else if (LA==LPAR) {
1269        Consume(LPAR);
1270        a = New1(EvalSteps, Recurse(OrExpr));
1271        Consume(RPAR);
1272
1273    } else if (LA==LITERAL) {
1274        Consume(LITERAL);
1275        a = NewStr( Literal, STRVAL);
1276
1277    } else if (LA==INTNUMBER) {
1278        Consume(INTNUMBER);
1279        a = NewInt( INTVAL );
1280
1281    } else if (LA==REALNUMBER) {
1282        Consume(REALNUMBER);
1283        a = NewReal( REALVAL );
1284
1285    } else if (LA==FUNCTION || LA==NSPREFIX) {
1286        if (LA==FUNCTION) {
1287            Consume(FUNCTION);
1288            a = NewStr( ExecFunction, STRVAL);
1289            a->intvalue = getFunctionTag (STRVAL);
1290        } else {
1291            Consume(NSPREFIX);
1292            a = NewStr( ExecFunction, STRVAL);
1293            a->intvalue = f_fqfunction;
1294            Consume(FUNCTION);
1295            AddChild (a, NewStr( ExecFunction, STRVAL));
1296        }
1297        Consume(LPAR);
1298        if (LA!=RPAR) {
1299            AddChildWithEvalSteps (a, Recurse(OrExpr));
1300            while(LA==COMMA) {
1301                Consume(COMMA);
1302                AddChildWithEvalSteps  (a, Recurse(OrExpr) );
1303            }
1304        }
1305        Consume(RPAR);
1306    } else {
1307        ErrExpected("$var or (expr) or literal or number or func");
1308    }
1309    while (LA==LBRACKET) {
1310        ast b;
1311        b = Recurse(Predicate);
1312        if (!b) return NULL;
1313        Append( a, New1WithEvalSteps( Pred, b));
1314    }
1315EndProduction
1316
1317
1318/*-----------------------------------------------------------------
1319|   PathExpr  production
1320|
1321\----------------------------------------------------------------*/
1322Production(PathExpr)
1323
1324    if ( (LA==VARIABLE)
1325       ||(LA==FQVARIABLE)
1326       ||(LA==LPAR)
1327       ||(LA==LITERAL)
1328       ||(LA==INTNUMBER)
1329       ||(LA==REALNUMBER)
1330       ||(LA==FUNCTION)
1331       ||(LA==NSPREFIX && LA2==FUNCTION)
1332    ) {
1333        a = Recurse(FilterExpr);
1334        if (LA==SLASH) {
1335            Consume(SLASH);
1336            Append(a, Recurse(RelativeLocationPath));
1337
1338        } else if (LA==SLASHSLASH) {
1339            ast b;
1340            Consume(SLASHSLASH);
1341            b = Recurse(RelativeLocationPath);
1342            if (b->type == AxisChild) {
1343                b->type = AxisDescendant;
1344            } else {
1345                Append(a, New( AxisDescendantOrSelf ) );
1346            }
1347            Append(a, b );
1348        }
1349
1350    } else {
1351        if ( (LA==SLASH) || (LA==SLASHSLASH)) {
1352            return Recurse(AbsoluteLocationPath);
1353        } else {
1354            return Recurse(RelativeLocationPath);
1355        }
1356    }
1357
1358EndProduction
1359
1360
1361/*-----------------------------------------------------------------
1362|   UnionExpr  production
1363|
1364\----------------------------------------------------------------*/
1365Production(UnionExpr)
1366
1367    a = Recurse(PathExpr);
1368    while (LA==PIPE) {
1369        Consume(PIPE);
1370        a = New2( CombineSets, a, Recurse(PathExpr));
1371    }
1372
1373EndProduction
1374
1375
1376/*-----------------------------------------------------------------
1377|   UnaryExpr  production
1378|
1379\----------------------------------------------------------------*/
1380Production(UnaryExpr)
1381
1382    if (LA==MINUS) {
1383        Consume(MINUS);
1384        a = Recurse(UnionExpr);
1385        if (!a) {
1386            if (*errMsg == NULL) { ErrExpected("UnionExpr"); }
1387            return NULL;
1388        }
1389        if ((a->type == Int) && (a->next == NULL)) {
1390            a->intvalue = a->intvalue * -1;
1391        } else
1392        if ((a->type == Real) && (a->next == NULL)) {
1393            a->realvalue = a->realvalue * -1;
1394        } else {
1395            a = New1( UnaryMinus, a);
1396        }
1397
1398    } else {
1399        a = Recurse(UnionExpr);
1400    }
1401EndProduction
1402
1403
1404/*-----------------------------------------------------------------
1405|   MultiplicativeExpr  production
1406|
1407\----------------------------------------------------------------*/
1408Production(MultiplicativeExpr)
1409
1410    a = Recurse(UnaryExpr);
1411    while ( (LA==MULTIPLY)
1412          ||(LA==DIV)
1413          ||(LA==MOD)
1414    ) {
1415        if (LA==MULTIPLY) {
1416            Consume(MULTIPLY);
1417            a = New2( Mult, a, Recurse(UnaryExpr));
1418        } else if (LA==DIV) {
1419            Consume(DIV);
1420            a = New2( Div, a, Recurse(UnaryExpr));
1421        } else {
1422            Consume(MOD);
1423            a = New2( Mod, a, Recurse(UnaryExpr));
1424        }
1425    }
1426EndProduction
1427
1428
1429/*-----------------------------------------------------------------
1430|   AdditiveExpr  production
1431|
1432\----------------------------------------------------------------*/
1433Production(AdditiveExpr)
1434
1435    a = Recurse(MultiplicativeExpr);
1436    while ( (LA==PLUS)
1437          ||(LA==MINUS)
1438    ) {
1439        if (LA==PLUS) {
1440            Consume(PLUS);
1441            a = New2( Add, a, Recurse(MultiplicativeExpr));
1442        } else {
1443            Consume(MINUS);
1444            a = New2( Substract, a, Recurse(MultiplicativeExpr));
1445        }
1446    }
1447EndProduction
1448
1449
1450/*-----------------------------------------------------------------
1451|   RelationalExpr  production
1452|
1453\----------------------------------------------------------------*/
1454Production(RelationalExpr)
1455
1456    a = Recurse(AdditiveExpr);
1457    while ( (LA==LT)
1458          ||(LA==LTE)
1459          ||(LA==GT)
1460          ||(LA==GTE)
1461    ) {
1462        if (LA==LT) {
1463            Consume(LT);
1464            a = New2( Less, a, Recurse(AdditiveExpr));
1465        } else if (LA==LTE) {
1466            Consume(LTE);
1467            a = New2( LessOrEq, a, Recurse(AdditiveExpr));
1468        } else if (LA==GT) {
1469            Consume(GT);
1470            a = New2( Greater, a, Recurse(AdditiveExpr));
1471        } else {
1472            Consume(GTE);
1473            a = New2( GreaterOrEq, a, Recurse(AdditiveExpr));
1474        }
1475    }
1476EndProduction
1477
1478
1479/*-----------------------------------------------------------------
1480|   EqualityExpr  production
1481|
1482\----------------------------------------------------------------*/
1483Production(EqualityExpr)
1484
1485    a = Recurse(RelationalExpr);
1486    while ( (LA==EQUAL)
1487          ||(LA==NOTEQ)
1488    ) {
1489        if (LA==EQUAL) {
1490            Consume(EQUAL);
1491            a = New2( Equal, a, Recurse(RelationalExpr));
1492        } else {
1493            Consume(NOTEQ);
1494            a = New2( NotEqual, a, Recurse(RelationalExpr));
1495        }
1496    }
1497EndProduction
1498
1499
1500/*-----------------------------------------------------------------
1501|   AndExpr  production
1502|
1503\----------------------------------------------------------------*/
1504Production(AndExpr)
1505
1506    a = Recurse(EqualityExpr);
1507    while (LA==AND) {
1508        Consume(AND);
1509        a = New2( And, a, Recurse(EqualityExpr));
1510    }
1511EndProduction
1512
1513
1514/*-----------------------------------------------------------------
1515|   OrExpr  production
1516|
1517\----------------------------------------------------------------*/
1518Production(OrExpr)
1519
1520    a = Recurse(AndExpr);
1521    while (LA==OR) {
1522        Consume(OR);
1523        a = New2( Or, a, Recurse(AndExpr));
1524    }
1525EndProduction
1526
1527
1528/*-----------------------------------------------------------------
1529|   Predicate  production
1530|
1531\----------------------------------------------------------------*/
1532Production(Predicate)
1533
1534    Consume(LBRACKET);
1535    a = Recurse(OrExpr);
1536    Consume(RBRACKET);
1537
1538EndProduction
1539
1540
1541/*-----------------------------------------------------------------
1542|   Basis  production
1543|
1544\----------------------------------------------------------------*/
1545Production(Basis)
1546
1547    if (LA==AXISNAME) {
1548        astType t;
1549        Consume(AXISNAME);
1550        if        (IS_STR('c',"child"))              { t = AxisChild;
1551        } else if (IS_STR('d',"descendant"))         { t = AxisDescendantLit;
1552        } else if (IS_STR('d',"descendant-or-self")) { t = AxisDescendantOrSelfLit;
1553        } else if (IS_STR('s',"self"))               { t = AxisSelf;
1554        } else if (IS_STR('a',"attribute"))          { t = AxisAttribute;
1555        } else if (IS_STR('a',"ancestor"))           { t = AxisAncestor;
1556        } else if (IS_STR('a',"ancestor-or-self"))   { t = AxisAncestorOrSelf;
1557        } else if (IS_STR('f',"following"))          { t = AxisFollowing;
1558        } else if (IS_STR('f',"following-sibling"))  { t = AxisFollowingSibling;
1559        } else if (IS_STR('n',"namespace"))          { t = AxisNamespace;
1560        } else if (IS_STR('p',"parent"))             { t = AxisParent;
1561        } else if (IS_STR('p',"preceding"))          { t = AxisPreceding;
1562        } else if (IS_STR('p',"preceding-sibling"))  { t = AxisPrecedingSibling;
1563        } else {
1564            ErrExpected("correct axis name");
1565        }
1566        a = New( t );
1567        Consume(COLONCOLON);
1568        AddChild( a, Recurse(NodeTest));
1569    } else {
1570        a = Recurse(AbbreviatedBasis);
1571    }
1572EndProduction
1573
1574
1575/*-----------------------------------------------------------------
1576|   Step  production
1577|
1578\----------------------------------------------------------------*/
1579static int IsStepPredOptimizable (ast a) {
1580    ast b;
1581    int left;
1582
1583    /* Must be called with a != NULL */
1584    DBG (
1585        fprintf (stderr, "IsStepPredOptimizable:\n");
1586        printAst (0,a);
1587    )
1588    switch (a->type) {
1589    case Int: return a->intvalue;
1590    case Less:
1591    case LessOrEq:
1592        b = a->child;
1593        if (!b) return 0;
1594        if (b->type != ExecFunction
1595            || b->intvalue != f_position) return 0;
1596        b = b->next;
1597        if (b->type != Int) return 0;
1598        if (a->type == Less) return b->intvalue;
1599        else                 return b->intvalue + 1;
1600    case Greater:
1601    case GreaterOrEq:
1602        b = a->child;
1603        if (!b) return 0;
1604        if (b->type != Int) return 0;
1605        left = b->intvalue;
1606        b = b->next;
1607        if (b->type != ExecFunction
1608            || b->intvalue != f_position) return 0;
1609        if (a->type == Greater) return left;
1610        else                    return left + 1;
1611    case Equal:
1612        b = a->child;
1613        if (!b) return 0;
1614        if (b->type == Int
1615            && b->next->type == ExecFunction
1616            && b->next->intvalue == f_position) return b->intvalue;
1617        if (b->type == ExecFunction
1618            && b->intvalue == f_position
1619            && b->next->type == Int) return b->next->intvalue;
1620        return 0;
1621    default: return 0;
1622    }
1623}
1624
1625Production(Step)
1626
1627    if (LA==DOT) {
1628        Consume(DOT);
1629        a = New( GetContextNode );
1630        /* a = New1( AxisSelf, New (IsNode)); */
1631
1632    } else if (LA==DOTDOT) {
1633        Consume(DOTDOT);
1634        a = New( GetParentNode );
1635        /* a = New1( AxisParent, New (IsNode)); */
1636
1637    } else {
1638        ast b;
1639        int isFirst = 1;
1640        a = Recurse(Basis);
1641        if (LA==LBRACKET && !a) {
1642            if (*errMsg == NULL) { ErrExpected("Step"); }
1643            return NULL;
1644        }
1645        while (LA==LBRACKET) {
1646            b = Recurse (Predicate);
1647            if (!b) return NULL;
1648            if (isFirst) {
1649                a->intvalue = IsStepPredOptimizable (b);
1650                DBG (fprintf (stderr, "step type %s, intvalue: %d\n", astType2str[a->type], a->intvalue);)
1651                    isFirst = 0;
1652            }
1653            Append( a, New1WithEvalSteps( Pred, b));
1654        }
1655    }
1656EndProduction
1657
1658
1659/*-----------------------------------------------------------------
1660|   RelativeLocationPath  production
1661|
1662\----------------------------------------------------------------*/
1663Production(RelativeLocationPath)
1664
1665    a = Recurse(Step);
1666    if (!a) return NULL;
1667    while ((LA==SLASH) || (LA==SLASHSLASH)) {
1668        if (LA==SLASH) {
1669            Consume(SLASH);
1670            Append(a, Recurse(Step));
1671        } else {
1672            ast b;
1673            Consume(SLASHSLASH);
1674            b = Recurse(Step);
1675            if (b->type == AxisChild) {
1676                b->type = AxisDescendant;
1677            } else {
1678                Append(a, New( AxisDescendantOrSelf ) );
1679            }
1680            Append(a, b );
1681        }
1682    }
1683EndProduction
1684
1685
1686/*-----------------------------------------------------------------
1687|   AbsoluteLocationPath  production
1688|
1689\----------------------------------------------------------------*/
1690Production(AbsoluteLocationPath)
1691
1692    if (LA==SLASH) {
1693        ast b;
1694
1695        Consume(SLASH);
1696        a = New(SelectRoot);
1697        if ( (LA==AXISNAME)
1698           ||(LA==WCARDNAME)
1699           ||(LA==NSPREFIX)
1700           ||(LA==NSWC)
1701           ||(LA==NODE)
1702           ||(LA==TEXT)
1703           ||(LA==COMMENT)
1704           ||(LA==PINSTR)
1705           ||(LA==DOT)
1706           ||(LA==DOTDOT)
1707           ||(LA==ATTRIBUTE)
1708           ||(LA==ATTRIBUTEPREFIX)
1709        ) {
1710            b =  Recurse(RelativeLocationPath);
1711            Append(a, b);
1712        }
1713
1714    } else if (LA==SLASHSLASH) {
1715        ast b;
1716
1717        Consume(SLASHSLASH);
1718        a = New(SelectRoot);
1719
1720        b = Recurse(RelativeLocationPath);
1721        if (!b) {
1722            freeAst (a);
1723            return NULL;
1724        }
1725        if (b->type == AxisChild) {
1726            b->type = AxisDescendant;
1727        } else {
1728            Append(a, New( AxisDescendantOrSelf ) );
1729        }
1730
1731        Append(a, b );
1732
1733    } else {
1734        ErrExpected("/ or //");
1735    }
1736EndProduction
1737
1738
1739/*-----------------------------------------------------------------
1740|   XSLT StepPattern  production
1741|
1742\----------------------------------------------------------------*/
1743static int usesPositionInformation ( ast a) {
1744
1745    while (a) {
1746        if (a->type == ExecFunction
1747            && (a->intvalue == f_position
1748                || a->intvalue == f_last
1749                || a->intvalue == f_unknown)) {
1750            return 1;
1751        }
1752        if (a->child) {
1753            if (usesPositionInformation (a->child)) return 1;
1754        }
1755        a = a->next;
1756    }
1757    return 0;
1758}
1759
1760/* Must be called with a != NULL */
1761static int checkStepPatternPredOptimizability ( ast a , int *max) {
1762    ast b;
1763
1764    switch (a->type) {
1765        case Literal:
1766        case AxisAncestor:
1767        case AxisAncestorOrSelf:
1768        case AxisChild:
1769        case AxisAttribute:
1770        case AxisDescendant:
1771        case AxisDescendantLit:
1772        case AxisDescendantOrSelf:
1773        case AxisDescendantOrSelfLit:
1774        case AxisFollowing:
1775        case AxisFollowingSibling:
1776        case AxisNamespace:
1777        case AxisParent:
1778        case AxisPreceding:
1779        case AxisPrecedingSibling:
1780        case AxisSelf:
1781        case IsNode:
1782        case IsComment:
1783        case IsText:
1784        case IsPI:
1785        case IsSpecificPI:
1786        case IsElement:
1787        case GetContextNode:
1788        case GetParentNode:
1789            break;
1790
1791        case And:
1792        case Or:
1793            if (usesPositionInformation(a->child)) return 0;
1794            return 1;
1795        case Less:
1796        case LessOrEq:
1797            b = a->child;
1798            if (b
1799                && b->type == ExecFunction
1800                && b->intvalue == f_position
1801                && b->next->type == Int) {
1802                if (a->type == Less) *max = b->next->intvalue;
1803                else *max = b->next->intvalue + 1;
1804                return 0;
1805            }
1806            if (usesPositionInformation(a->child)) return 0;
1807            return 1;
1808        case Greater:
1809        case GreaterOrEq:
1810            b = a->child;
1811            if (b
1812                && b->type == Int
1813                && b->next->type == ExecFunction
1814                && b->next->intvalue == f_position) {
1815                if (a->type == Greater) *max = b->intvalue;
1816                else *max = b->intvalue + 1;
1817                return 0;
1818            }
1819            if (usesPositionInformation(a->child)) return 0;
1820            return 1;
1821        case Equal:
1822            b = a->child;
1823            if (b
1824                && b->type == Int
1825                && b->next->type == ExecFunction
1826                && b->next->intvalue == f_position) {
1827                *max = b->intvalue;
1828                return 0;
1829            }
1830            if (b
1831                && b->type == ExecFunction
1832                && b->intvalue == f_position
1833                && b->next->type == Int) {
1834                *max = b->next->intvalue;
1835                return 0;
1836            }
1837            if (usesPositionInformation(a->child)) return 0;
1838            return 1;
1839        case NotEqual:
1840            if (usesPositionInformation(a->child)) return 0;
1841            return 1;
1842
1843        case Int:
1844            *max = a->intvalue;
1845            return 0;
1846
1847        case ExecFunction:
1848            return !usesPositionInformation(a);
1849
1850        default:
1851            return 0;
1852    }
1853    return 1;
1854}
1855
1856/* Must be called with a != NULL */
1857static int IsStepPatternPredOptimizable ( ast a, int *max ) {
1858    int f;
1859
1860    *max = 0;
1861    f = checkStepPatternPredOptimizability(a, max);
1862    DBG(
1863        if (f) {
1864            fprintf(stderr, "\nStepPattern Pred is optimizable:\n");
1865        } else {
1866            fprintf(stderr, "\nStepPattern Pred is not optimizable, max = %d:\n", *max);
1867        }
1868        printAst(0,a);
1869    )
1870    return f;
1871}
1872
1873
1874/*-----------------------------------------------------------------
1875|   XSLT StepPattern  production
1876|
1877\----------------------------------------------------------------*/
1878Production(StepPattern)
1879
1880    if (LA==AXISNAME) {
1881        astType t;
1882        Consume(AXISNAME);
1883        if        (IS_STR('c',"child"))      { t = AxisChild;
1884        } else if (IS_STR('a',"attribute"))  { t = AxisAttribute;
1885        } else {
1886            ErrExpected("correct axis name (child/attribute)");
1887        }
1888        Consume(COLONCOLON);
1889        a = New1( t, Recurse(NodeTest));
1890
1891    } else
1892    if (LA==ATTRIBUTE) {
1893        Consume(ATTRIBUTE);
1894        a = New1( AxisAttribute, NewStr(IsAttr, STRVAL) );
1895    } else
1896    if (LA==ATTRIBUTEPREFIX) {
1897        ast b, c;
1898        Consume(ATTRIBUTEPREFIX);
1899        a = New ( AxisAttribute);
1900        b = NewStr (IsNSAttr, STRVAL);
1901        AddChild (a, b);
1902        Consume(ATTRIBUTE);
1903        c = NewStr (IsAttr, STRVAL);
1904        AddChild (b, c);
1905    } else {
1906        a = Recurse(NodeTest);
1907    }
1908    if (!a) {
1909        if (*errMsg == NULL) { ErrExpected("StepPattern") };
1910        return NULL;
1911    }
1912    {
1913        ast b = NULL, c = NULL, aCopy = NULL;
1914        int stepIsOptimizable = 1, isFirst = 1, max, savedmax;
1915        while (LA==LBRACKET) {
1916            b = Recurse (Predicate);
1917            if (!b) return NULL;
1918            if (stepIsOptimizable) {
1919                if (!IsStepPatternPredOptimizable(b, &max))
1920                    stepIsOptimizable = 0;
1921            }
1922            if (isFirst) {
1923                savedmax = max;
1924                c = New1WithEvalSteps( Pred, b);
1925                isFirst = 0;
1926            } else {
1927                Append (c, New1WithEvalSteps( Pred, b));
1928            }
1929        }
1930        if (!isFirst) {
1931            if (stepIsOptimizable) {
1932                Append (a, New (FillWithCurrentNode));
1933            } else {
1934                /* copy the step before the Predicate */
1935                aCopy = NEWCONS;
1936                aCopy->type      = a->type;
1937                aCopy->next      = NULL;
1938                if (a->strvalue) aCopy->strvalue = tdomstrdup(a->strvalue);
1939                else             aCopy->strvalue = NULL;
1940                aCopy->intvalue  = a->intvalue;
1941                aCopy->realvalue = a->realvalue;
1942                aCopy->child     = NULL;
1943                if (a->child) {
1944                    ast aCopyChild = NEWCONS;
1945                    aCopyChild->type      = a->child->type;
1946                    aCopyChild->next      = NULL;
1947                    aCopyChild->child     = NULL;
1948                    if (a->child->strvalue) {
1949                        aCopyChild->strvalue  = tdomstrdup(a->child->strvalue);
1950                    } else {
1951                        aCopyChild->strvalue  = NULL;
1952                    }
1953                    aCopyChild->intvalue  = a->child->intvalue;
1954                    aCopyChild->realvalue = a->child->realvalue;
1955                    aCopy->child = aCopyChild;
1956                }
1957                b = New1( FillNodeList, aCopy);
1958                b->intvalue = savedmax;
1959                Append( a, b);
1960            }
1961            Append (a, c);
1962        }
1963    }
1964
1965EndProduction
1966
1967
1968/*-----------------------------------------------------------------
1969|   XSLT RelativePathPattern  production
1970|
1971\----------------------------------------------------------------*/
1972Production(RelativePathPattern)
1973
1974    a = Recurse(StepPattern);
1975    while ((LA==SLASH) || (LA==SLASHSLASH)) {
1976        ast b;
1977        if (LA==SLASH) {
1978            Consume(SLASH);
1979            b = Recurse(StepPattern);
1980            if (b) {
1981                Append(b, New(ToParent) );
1982                Append(b, a);
1983                a = b;
1984            }
1985        } else {
1986            Consume(SLASHSLASH);
1987            b = Recurse(StepPattern);
1988            if (b) {
1989                Append(b, New(ToAncestors) );
1990                Append(b, a);
1991                a = b;
1992            }
1993        }
1994    }
1995
1996EndProduction
1997
1998
1999/*-----------------------------------------------------------------
2000|   XSLT IdKeyPattern  production
2001|
2002\----------------------------------------------------------------*/
2003Production(IdKeyPattern)
2004
2005    Consume(FUNCTION);
2006    if (strcmp(STRVAL, "id" )==0) {
2007        ast b;
2008        /* id */
2009        a = NewStr( ExecIdKey, STRVAL);
2010        a->intvalue = f_id;
2011        Consume(LPAR);
2012        Consume(LITERAL);
2013        b = NewStr( Literal, STRVAL);
2014        AddChild (a, b);
2015        Consume(RPAR);
2016    } else {
2017        ast b;
2018        /* key */
2019        a = NewStr( ExecIdKey, STRVAL);
2020        Consume(LPAR);
2021        Consume(LITERAL);
2022        b = NewStr( Literal, STRVAL);
2023        AddChild (a, b);
2024        Consume(COMMA);
2025        Consume(LITERAL);
2026        b = NewStr( Literal, STRVAL);
2027        AddChild (a, b);
2028        Consume(RPAR);
2029    }
2030
2031EndProduction
2032
2033
2034/*-----------------------------------------------------------------
2035|   XSLT LocationPathPattern  production
2036|
2037\----------------------------------------------------------------*/
2038Production(LocationPathPattern)
2039
2040    if (LA==SLASH) {
2041        Consume(SLASH);
2042        if (LA==EOS || LA==PIPE) {
2043            a = New(IsRoot);
2044        } else {
2045            a = Recurse(RelativePathPattern);
2046            if (a) {
2047                Append( a, New(ToParent) );
2048                Append( a, New(IsRoot) );
2049            }
2050        }
2051    } else
2052    if ((LA==FUNCTION)
2053        && (  (strcmp(tokens[*l].strvalue, "id" )==0)
2054            ||(strcmp(tokens[*l].strvalue, "key")==0) ) )
2055    {
2056        ast b;
2057
2058        b = Recurse(IdKeyPattern);
2059        if (LA==SLASH) {
2060            Consume(SLASH);
2061            a = Recurse(RelativePathPattern);
2062            if (a) { Append( a, New(ToParent) ); }
2063        } else
2064        if (LA==SLASHSLASH) {
2065            Consume(SLASHSLASH);
2066            a = Recurse(RelativePathPattern);
2067            if (a) { Append( a, New(ToAncestors) ); }
2068        }
2069        if (!a) {
2070            a = b;
2071        } else {
2072            Append( a, b);
2073        }
2074    } else {
2075        if (LA==SLASHSLASH) {
2076            Consume(SLASHSLASH);
2077            a = Recurse(RelativePathPattern);
2078            if (a) {
2079                Append( a, New(ToAncestors) );
2080                Append( a, New(IsRoot) );
2081            }
2082        } else {
2083            a = Recurse(RelativePathPattern);
2084        }
2085    }
2086
2087EndProduction
2088
2089/*-----------------------------------------------------------------
2090|   XSLT Pattern  production
2091|
2092\----------------------------------------------------------------*/
2093Production(Pattern)
2094
2095    a = Recurse(LocationPathPattern);
2096    while (LA==PIPE) {
2097        Consume(PIPE);
2098        a = New2( CombinePath, New1(EvalSteps, a),
2099                               New1(EvalSteps, Recurse(LocationPathPattern) ) );
2100    }
2101
2102EndProduction
2103
2104
2105
2106/*----------------------------------------------------------------------------
2107|   xpathFreeTokens
2108|
2109\---------------------------------------------------------------------------*/
2110static
2111int xpathFreeTokens (
2112    XPathTokens tokens
2113)
2114{
2115    int i;
2116
2117    for (i=0; tokens[i].token != EOS; i++) {
2118        if (tokens[i].strvalue) {
2119            FREE(tokens[i].strvalue);
2120        }
2121    }
2122    FREE((char*)tokens);
2123    return 0;
2124}
2125
2126/*----------------------------------------------------------------------------
2127|   xpathParsePostProcess
2128|
2129\---------------------------------------------------------------------------*/
2130static
2131int xpathParsePostProcess (
2132    ast           t,
2133    xpathExprType type,
2134    domNode      *exprContext,
2135    char        **prefixMappings,
2136    char        **errMsg
2137    )
2138{
2139    const char *uri;
2140
2141    DBG(
2142        fprintf(stderr, "xpathParsePostProcess start:\n");
2143        printAst (0, t);
2144        )
2145    while (t) {
2146        DBG(printAst (4, t);)
2147        if (t->type == AxisNamespace) {
2148            if (t->child->type == IsElement && t->child->strvalue[0] != '*') {
2149                uri = domLookupPrefixWithMappings (exprContext,
2150                                                   t->child->strvalue,
2151                                                   prefixMappings);
2152                if (!uri) {
2153                    *errMsg = tdomstrdup ("Prefix doesn't resolve");
2154                    return 0;
2155                }
2156                FREE (t->child->strvalue);
2157                t->child->strvalue = tdomstrdup (uri);
2158            }
2159        }
2160        if (type != XPATH_EXPR) {
2161            if (type != XPATH_KEY_USE_EXPR) {
2162                /* 12.4: "It is an error to use the current function in a
2163                   pattern." */
2164                if (t->type == ExecFunction
2165                    && t->intvalue == f_unknown
2166                    && (strcmp (t->strvalue, "current")==0)) {
2167                    *errMsg = tdomstrdup(
2168                        "The 'current' function is not allowed in Pattern."
2169                        );
2170                    return 0;
2171                }
2172            }
2173            if (type == XPATH_KEY_MATCH_PATTERN
2174                || type == XPATH_KEY_USE_EXPR) {
2175                /* 12.2: "It is an error for the value of either the use
2176                   attribute or the match attribute to contain a
2177                   VariableReference, or a call to the key function." */
2178                if (t->type == ExecFunction
2179                    && t->intvalue == f_unknown
2180                    && (strcmp (t->strvalue, "key")==0)) {
2181                    *errMsg = tdomstrdup("The 'key' function is not allowed "
2182                                         "in the use and match attribute "
2183                                         "pattern of xsl:key.");
2184                    return 0;
2185                }
2186                if (t->type == GetVar || t->type == GetFQVar) {
2187                    *errMsg = tdomstrdup("Variable references are not allowed "
2188                                         "in the use and match attribute of "
2189                                         "xsl:key.");
2190                    return 0;
2191                }
2192            }
2193            if (type == XPATH_TEMPMATCH_PATTERN) {
2194                /* 5.3: "It is an error for the value of the match
2195                   attribute to contain a VariableReference." */
2196                if (t->type == GetVar || t->type == GetFQVar) {
2197                    *errMsg = tdomstrdup("Variable references are not allowed "
2198                                         "in the match attribute of "
2199                                         "xsl:template."
2200                        );
2201                    return 0;
2202                }
2203            }
2204        }
2205        if (t->child) {
2206            if (!xpathParsePostProcess (t->child, type, exprContext,
2207                                        prefixMappings, errMsg)) return 0;
2208        }
2209        t = t->next;
2210    }
2211    return 1;
2212}
2213
2214/*----------------------------------------------------------------------------
2215|   xpathParse
2216|
2217\---------------------------------------------------------------------------*/
2218int xpathParse (
2219    char            *xpath,
2220    domNode         *exprContext,
2221    xpathExprType    type,
2222    char           **prefixMappings,
2223    xpathParseVarCB *varParseCB,
2224    ast             *t,
2225    char           **errMsg
2226)
2227{
2228    XPathTokens tokens;
2229    int  i, l, len, newlen, slen;
2230    int  useNamespaceAxis = 0;
2231    char tmp[200];
2232
2233    DDBG(fprintf(stderr, "\nLex output following tokens for '%s':\n", xpath);)
2234    *errMsg = NULL;
2235    tokens = xpathLexer(xpath, exprContext, prefixMappings, &useNamespaceAxis,
2236                        varParseCB, errMsg);
2237    if (*errMsg != NULL) {
2238        if (tokens != NULL) xpathFreeTokens (tokens);
2239        return XPATH_LEX_ERR;
2240    }
2241    DDBG(
2242        for (i=0; tokens[i].token != EOS; i++) {
2243            fprintf(stderr, "%3d %-12s %5d %8.3f %5d  %s\n",
2244                            i,
2245                            token2str[tokens[i].token-LPAR],
2246                            tokens[i].intvalue,
2247                            tokens[i].realvalue,
2248                            tokens[i].pos,
2249                            tokens[i].strvalue
2250            );
2251        }
2252    )
2253    l = 0;
2254
2255    *t = NULL;
2256    if (type == XPATH_EXPR || type == XPATH_KEY_USE_EXPR) {
2257        *t = OrExpr (&l, tokens, errMsg);
2258    } else {
2259        *t = Pattern (&l, tokens, errMsg);
2260    }
2261    if ((*errMsg == NULL) && (tokens[l].token != EOS)) {
2262        *errMsg = tdomstrdup("Unexpected tokens (beyond end)!");
2263    }
2264    if (*errMsg == NULL && ((type != XPATH_EXPR) || useNamespaceAxis)) {
2265        xpathParsePostProcess (*t, type, exprContext, prefixMappings, errMsg);
2266    }
2267    if (*errMsg) {
2268        len    = strlen(*errMsg);
2269        newlen = strlen(xpath);
2270        *errMsg = (char*)REALLOC(*errMsg, len+newlen+10);
2271        memmove(*errMsg + len, " for '", 6);
2272        memmove(*errMsg + len+6, xpath, newlen);
2273        memmove(*errMsg + len+6+newlen, "' ", 3);
2274
2275        for (i=0; tokens[i].token != EOS; i++) {
2276            sprintf(tmp, "%s\n%3s%3d %-12s %5d %8.3f %5d  ",
2277                         (i==0) ? "\n\nParsed symbols:" : "",
2278                         (i==l) ? "-->" : "   ",
2279                          i,
2280                         token2str[tokens[i].token-LPAR],
2281                         tokens[i].intvalue,
2282                         tokens[i].realvalue,
2283                         tokens[i].pos
2284            );
2285            len    = strlen(*errMsg);
2286            newlen = strlen(tmp);
2287            slen = 0;
2288            if (tokens[i].strvalue) {
2289                slen = strlen(tokens[i].strvalue);
2290            }
2291
2292            *errMsg = (char*)REALLOC(*errMsg, len+newlen+slen+1);
2293            memmove(*errMsg + len, tmp, newlen);
2294            memmove(*errMsg + len + newlen, tokens[i].strvalue, slen);
2295            (*errMsg)[len + newlen + slen] = '\0';
2296        }
2297    }
2298    DBG(
2299        if (type) {
2300            fprintf(stderr, "\nPattern AST for '%s': \n", xpath);
2301            printAst (0, *t);
2302        } else {
2303            fprintf(stderr, "AST (xpathParse):\n");
2304            printAst (0, *t);
2305        }
2306    )
2307    xpathFreeTokens (tokens);
2308    if (*errMsg!=NULL) {
2309        if (*t) freeAst (*t);
2310        return XPATH_SYNTAX_ERR;
2311    }
2312    return 0;
2313
2314} /* xpathParse */
2315
2316
2317/*----------------------------------------------------------------------------
2318|   xpathNodeTest
2319|
2320\---------------------------------------------------------------------------*/
2321int xpathNodeTest (
2322    domNode        *node,
2323    ast             step
2324)
2325{
2326    const char *localName, *nodeUri;
2327
2328    if (!(step->child)) return 1;
2329    if (step->child->type == IsElement) {
2330        if (node->nodeType == ELEMENT_NODE) {
2331            if ((step->child->strvalue[0] == '*') &&
2332                (step->child->strvalue[1] == '\0') &&
2333                (node->ownerDocument->rootNode != node)) return 1;
2334            if (node->namespace) return 0;
2335            return (strcmp(node->nodeName, step->child->strvalue)==0);
2336        }
2337        return 0;
2338    } else
2339    if (step->child->type == IsAttr) {
2340        if (node->nodeType == ATTRIBUTE_NODE) {
2341            if (node->nodeFlags & IS_NS_NODE) return 0;
2342            if (  (step->child->strvalue[0] == '*')
2343                &&(step->child->strvalue[1] == '\0')
2344            ) {
2345                return 1;
2346            }
2347            return (strcmp( ((domAttrNode*)node)->nodeName,
2348                            step->child->strvalue)==0);
2349        }
2350        return 0;
2351    } else
2352    if (step->child->type == IsFQElement) {
2353        if (node->nodeType != ELEMENT_NODE || node->namespace == 0) return 0;
2354        nodeUri = domNamespaceURI (node);
2355        if (!nodeUri) return 0;
2356        if (strcmp (step->child->strvalue, nodeUri) != 0) return 0;
2357        localName = domGetLocalName (node->nodeName);
2358        if (strcmp (step->child->child->strvalue, localName)==0) return 1;
2359        return 0;
2360    } else
2361    if (step->child->type == IsNSElement) {
2362        nodeUri = domNamespaceURI (node);
2363        if (!nodeUri) return 0;
2364        if (nodeUri && (strcmp (step->child->strvalue, nodeUri)==0)) return 1;
2365        return 0;
2366    } else
2367    if (step->child->type == IsNSAttr) {
2368        if (node->nodeType != ATTRIBUTE_NODE
2369            || node->nodeFlags & IS_NS_NODE) return 0;
2370        nodeUri = domNamespaceURI (node);
2371        if (!nodeUri) return 0;
2372        if (strcmp (step->child->strvalue, nodeUri) != 0) return 0;
2373        if (strcmp (step->child->child->strvalue, "*")==0) return 1;
2374        localName = domGetLocalName (((domAttrNode *) node)->nodeName);
2375        if (strcmp (step->child->child->strvalue, localName)==0) return 1;
2376        return 0;
2377    } else
2378    if (step->child->type == IsNode) {
2379        DBG(fprintf(stderr, "nodeTest: nodeType=%d \n", node->nodeType);)
2380        return 1;
2381    } else
2382    if (step->child->type == IsText) {
2383        DBG(fprintf(stderr, "nodeTest: nodeType=%d == %d?? \n", node->nodeType, TEXT_NODE);)
2384        return (node->nodeType == TEXT_NODE);
2385    } else
2386    if (step->child->type == IsPI) {
2387        return (node->nodeType == PROCESSING_INSTRUCTION_NODE);
2388    } else
2389    if (step->child->type == IsSpecificPI) {
2390        return (strncmp (((domProcessingInstructionNode*)node)->targetValue,
2391                         step->child->strvalue,
2392                         ((domProcessingInstructionNode*)node)->targetLength)
2393            == 0);
2394    } else
2395    if (step->child->type == IsComment) {
2396        return (node->nodeType == COMMENT_NODE);
2397    }
2398    return 1;
2399}
2400
2401
2402/*----------------------------------------------------------------------------
2403|   xpathFuncBoolean
2404|
2405\---------------------------------------------------------------------------*/
2406int xpathFuncBoolean (
2407    xpathResultSet  *rs
2408)
2409{
2410    switch (rs->type) {
2411        case BoolResult:         return ( rs->intvalue         );
2412        case IntResult:          return ( rs->intvalue ? 1 : 0 );
2413        case RealResult:         return ((rs->realvalue != 0.0 ) && !IS_NAN (rs->realvalue));
2414        case StringResult:       return ( rs->string_len > 0   );
2415        case xNodeSetResult:     return ( rs->nr_nodes > 0     );
2416        case InfResult:
2417        case NInfResult:         return 1;
2418        /* NaNResult and EmptyResult are 'false' */
2419        default:                 return 0;
2420    }
2421}
2422
2423static int
2424xpathIsNumber (
2425    char *str
2426    )
2427{
2428    int dotseen = 0;
2429
2430    while (*str && IS_XML_WHITESPACE(*str)) str++;
2431    if (!*str) return 0;
2432    if (*str == '-') {
2433        str++;
2434        if (!*str) return 0;
2435    } else if (*str == '.') {
2436        dotseen = 1;
2437        str++;
2438        if (!*str) return 0;
2439    }
2440    if (!isdigit((unsigned char)*str)) return 0;
2441    while (*str) {
2442        if (isdigit((unsigned char)*str)) {
2443            str++;
2444            continue;
2445        }
2446        if (*str == '.' && !dotseen) {
2447            dotseen = 1;
2448            str++;
2449            continue;
2450        }
2451        break;
2452    }
2453    while (*str && IS_XML_WHITESPACE(*str)) str++;
2454    if (*str) return 0;
2455    else return 1;
2456}
2457
2458/*----------------------------------------------------------------------------
2459|   xpathFuncNumber
2460|
2461\---------------------------------------------------------------------------*/
2462double xpathFuncNumber (
2463    xpathResultSet  *rs,
2464    int             *NaN
2465)
2466{
2467    double d;
2468    char   tmp[80], *pc, *tailptr;
2469
2470    *NaN = 0;
2471    switch (rs->type) {
2472        case BoolResult:   return (rs->intvalue? 1.0 : 0.0);
2473        case IntResult:    return rs->intvalue;
2474        case RealResult:
2475            if (IS_NAN(rs->realvalue)) *NaN = 2;
2476            else if (IS_INF(rs->realvalue)!=0) *NaN = IS_INF(rs->realvalue);
2477            return rs->realvalue;
2478        case NaNResult:
2479            *NaN = 2;
2480            return 0.0;
2481        case InfResult:
2482            *NaN = 1;
2483#ifdef INFINITY
2484            return INFINITY;
2485#else
2486#   ifdef DBL_MAX
2487            return DBL_MAX;
2488#   else
2489            /* well, what? */
2490            return 0.0
2491#   endif
2492#endif
2493        case NInfResult:
2494            *NaN = -1;
2495#ifdef INFINITY
2496            return -INFINITY;
2497#else
2498#   ifdef DBL_MAX
2499            return -DBL_MAX;
2500#   else
2501            /* well, what? */
2502            return 0.0
2503#   endif
2504#endif
2505        case StringResult:
2506              if (!xpathIsNumber (rs->string)) {
2507                  d = strtod ("nan", &tailptr);
2508                  *NaN = 2;
2509                  return d;
2510              }
2511              strncpy(tmp, rs->string, (rs->string_len<79) ? rs->string_len : 79);
2512              tmp[(rs->string_len<79) ? rs->string_len : 79] = '\0';
2513              d = strtod (tmp, &tailptr);
2514              if (d == 0.0 && tailptr == tmp) {
2515                  d = strtod ("nan", &tailptr);
2516                  *NaN = 2;
2517              } else
2518              if (IS_NAN(d)) {
2519                  *NaN = 2;
2520              } else
2521              if (tailptr) {
2522                  while (*tailptr) {
2523                      switch (*tailptr) {
2524                      case ' ' :
2525                      case '\n':
2526                      case '\r':
2527                      case '\t': tailptr++; continue;
2528                      default: break; /*do nothing */
2529                      }
2530                      d = strtod ("nan", &tailptr);
2531                      *NaN = 2;
2532                      break;
2533                  }
2534              }
2535              return d;
2536        case xNodeSetResult:
2537              pc = xpathFuncString(rs);
2538              if (!xpathIsNumber (pc)) {
2539                  d = strtod ("nan", &tailptr);
2540                  *NaN = 2;
2541                  FREE(pc);
2542                  return d;
2543              }
2544              d = strtod (pc, &tailptr);
2545              if (d == 0.0 && tailptr == pc) {
2546                  d = strtod ("nan", &tailptr);
2547                  *NaN = 2;
2548              } else
2549              if (IS_NAN(d)) {
2550                  *NaN = 2;
2551              } else
2552              if (tailptr) {
2553                  while (*tailptr) {
2554                      switch (*tailptr) {
2555                      case ' ' :
2556                      case '\n':
2557                      case '\r':
2558                      case '\t': tailptr++; continue;
2559                      default: break; /*do nothing */
2560                      }
2561                      d = strtod ("nan", &tailptr);
2562                      *NaN = 2;
2563                      break;
2564                  }
2565              }
2566              FREE(pc);
2567              return d;
2568        default:
2569              DBG(fprintf(stderr, "funcNumber: default: 0.0\n");)
2570              d = strtod ("nan", &tailptr);
2571              *NaN = 2;
2572              return d;
2573    }
2574}
2575
2576
2577/*----------------------------------------------------------------------------
2578|   xpathGetStringValue
2579|
2580\---------------------------------------------------------------------------*/
2581char * xpathGetStringValueForElement (
2582    domNode *node,
2583    int     *len
2584)
2585{
2586    char        *pc, *t;
2587    int          l;
2588    domNode     *child;
2589
2590    if (node->nodeType == ELEMENT_NODE) {
2591        DBG(fprintf(stderr,"GetTextValue: tag='%s' \n", node->nodeName);)
2592        pc = MALLOC(1); *pc = '\0'; *len = 0;
2593        child = node->firstChild;
2594        while (child) {
2595            t = xpathGetStringValueForElement(child, &l);
2596            pc = (char*)REALLOC(pc, 1 + *len + l);
2597            memmove(pc + *len, t, l );
2598            *len += l;
2599            pc[*len] = '\0';
2600            FREE((char*)t);
2601            child = child->nextSibling;
2602        }
2603    } else
2604    if (node->nodeType == TEXT_NODE) {
2605
2606        *len = ((domTextNode*)node)->valueLength;
2607        pc   = (char*)MALLOC(1+*len);
2608        memmove(pc, ((domTextNode*)node)->nodeValue, *len);
2609        pc[*len] = '\0';
2610        DBG(fprintf(stderr,"GetTextValue: text='%s' \n", pc);)
2611    } else {
2612        pc   = tdomstrdup ("");
2613        *len = 0;
2614    }
2615    return pc;
2616}
2617
2618char * xpathGetStringValue (
2619    domNode *node,
2620    int     *len
2621)
2622{
2623    char         *pc, *t;
2624    int          l;
2625    domNode     *child;
2626    domAttrNode *attr;
2627
2628    if (node->nodeType == ELEMENT_NODE) {
2629        DBG(fprintf(stderr,"GetTextValue: tag='%s' \n", node->nodeName);)
2630        pc = MALLOC(1); *pc = '\0'; *len = 0;
2631        child = node->firstChild;
2632        while (child) {
2633            t = xpathGetStringValueForElement(child, &l);
2634            pc = (char*)REALLOC(pc, 1 + *len + l);
2635            memmove(pc + *len, t, l );
2636            *len += l;
2637            pc[*len] = '\0';
2638            FREE((char*)t);
2639            child = child->nextSibling;
2640        }
2641    } else
2642    if ((node->nodeType == TEXT_NODE) ||
2643        (node->nodeType == CDATA_SECTION_NODE) ||
2644        (node->nodeType == COMMENT_NODE)
2645    ) {
2646
2647        *len = ((domTextNode*)node)->valueLength;
2648        pc   = (char*)MALLOC(1+*len);
2649        memmove(pc, ((domTextNode*)node)->nodeValue, *len);
2650        pc[*len] = '\0';
2651        DBG(fprintf(stderr,"GetTextValue: text='%s' \n", pc);)
2652    } else
2653    if (node->nodeType == PROCESSING_INSTRUCTION_NODE) {
2654        *len = ((domProcessingInstructionNode*)node)->dataLength;
2655        pc   = (char*)MALLOC(1+*len);
2656        memmove(pc, ((domProcessingInstructionNode*)node)->dataValue, *len);
2657        pc[*len] = '\0';
2658    } else
2659    if (node->nodeType == ATTRIBUTE_NODE) {
2660        attr = (domAttrNode*)node;
2661        DBG(fprintf(stderr,"GetTextValue: attr='%s' \n", attr->nodeName);)
2662        pc = MALLOC(attr->valueLength +1);
2663        memmove(pc, attr->nodeValue, attr->valueLength);
2664        *(pc + attr->valueLength) = '\0';
2665        *len = attr->valueLength;
2666    }
2667    else {
2668        pc   = tdomstrdup ("");
2669        *len = 0;
2670    }
2671    return pc;
2672}
2673
2674/*----------------------------------------------------------------------------
2675|   xpathFuncString
2676|
2677\---------------------------------------------------------------------------*/
2678char * xpathFuncString (
2679    xpathResultSet  *rs
2680)
2681{
2682    char         tmp[80], *pc;
2683    int          len;
2684
2685    switch (rs->type) {
2686        case BoolResult:
2687            if (rs->intvalue) return (tdomstrdup("true"));
2688                         else return (tdomstrdup("false"));
2689        case IntResult:
2690            sprintf(tmp, "%d", rs->intvalue);
2691            return (tdomstrdup(tmp));
2692
2693        case RealResult:
2694            if (IS_NAN (rs->realvalue)) return tdomstrdup ("NaN");
2695            else if (IS_INF (rs->realvalue)) {
2696                if (IS_INF (rs->realvalue) == 1) return tdomstrdup ("Infinity");
2697                else                             return tdomstrdup ("-Infinity");
2698            }
2699            sprintf(tmp, "%f", rs->realvalue);
2700            /* strip trailing 0 and . */
2701            len = strlen(tmp);
2702            for (; (len > 0) && (tmp[len-1] == '0'); len--) tmp[len-1] = '\0';
2703            if ((len > 0) && (tmp[len-1] == '.'))   tmp[len-1] = '\0';
2704            return (tdomstrdup(tmp));
2705
2706        case NaNResult:
2707            return tdomstrdup ("NaN");
2708
2709        case InfResult:
2710            return tdomstrdup ("Infinity");
2711
2712        case NInfResult:
2713            return tdomstrdup ("-Infinity");
2714
2715        case StringResult:
2716            pc = MALLOC(rs->string_len +1);
2717            memmove(pc, rs->string, rs->string_len);
2718            *(pc + rs->string_len) = '\0';
2719            return pc;
2720
2721        case xNodeSetResult:
2722            if (rs->nr_nodes == 0) {
2723                pc = tdomstrdup ("");
2724            } else {
2725                pc = xpathGetStringValue (rs->nodes[0], &len);
2726            }
2727            return pc;
2728
2729        default:
2730            return (tdomstrdup (""));
2731    }
2732}
2733
2734/*----------------------------------------------------------------------------
2735|   xpathFuncStringForNode
2736|
2737\---------------------------------------------------------------------------*/
2738char * xpathFuncStringForNode (
2739    domNode *node
2740)
2741{
2742    int          len;
2743
2744    return xpathGetStringValue (node, &len);
2745}
2746
2747/*----------------------------------------------------------------------------
2748|   xpathFuncNumberForNode
2749|
2750\---------------------------------------------------------------------------*/
2751double xpathFuncNumberForNode (
2752    domNode *node,
2753    int      *NaN
2754)
2755{
2756    char        *pc;
2757    int          len, rc;
2758    double       d;
2759
2760    *NaN = 0;
2761    pc = xpathGetStringValue (node, &len);
2762    rc = sscanf (pc,"%lf", &d);
2763    if (rc != 1) *NaN = 2;
2764    FREE(pc);
2765    return d;
2766}
2767
2768
2769/*----------------------------------------------------------------------------
2770|   xpathArity
2771|
2772\---------------------------------------------------------------------------*/
2773static int xpathArity (
2774    ast step
2775)
2776{
2777    int parms = 0;
2778
2779    step = step->child;
2780    while (step) {
2781        parms++;
2782        step = step->next;
2783    }
2784    return parms;
2785}
2786
2787
2788/*----------------------------------------------------------------------------
2789|   xpathArityCheck
2790|
2791\---------------------------------------------------------------------------*/
2792static int xpathArityCheck (
2793    ast    step,
2794    int    arity,
2795    char **errMsg
2796)
2797{
2798    int parms = 0;
2799
2800    step = step->child;
2801    while (step) {
2802        parms++;
2803        step = step->next;
2804    }
2805    if (arity!=parms) {
2806        *errMsg = tdomstrdup("wrong number of parameters!");
2807        return 1;
2808    }
2809    return 0;
2810}
2811#define XPATH_ARITYCHECK(s,a,m) if (xpathArityCheck(s,a,m)) return XPATH_EVAL_ERR
2812
2813
2814
2815
2816/*----------------------------------------------------------------------------
2817|   xpathRound
2818|
2819\---------------------------------------------------------------------------*/
2820int xpathRound (double r) {
2821    if (r < 0.0) {
2822        return (int)floor (r + 0.5);
2823    } else {
2824        return (int)(r + 0.5);
2825    }
2826}
2827
2828/*----------------------------------------------------------------------------
2829|   xpathEvalFunction
2830|
2831\---------------------------------------------------------------------------*/
2832static int
2833xpathEvalFunction (
2834    ast                step,
2835    domNode           *ctxNode,
2836    domNode           *exprContext,
2837    int                position,
2838    xpathResultSet    *nodeList,
2839    xpathCBs          *cbs,
2840    xpathResultSet    *result,
2841    int               *docOrder,
2842    char             **errMsg
2843    )
2844{
2845    xpathResultSet   leftResult, rightResult, replaceResult;
2846    int              i, rc, pwhite, len,  NaN;
2847    char            *replaceStr, *pfrom, *pto, tmp[80], tmp1[80];
2848    domNode         *node;
2849    domAttrNode     *attr;
2850    double           leftReal;
2851    ast              nextStep;
2852    int              argc, savedDocOrder, from;
2853    xpathResultSets *args;
2854    xpathResultSet  *arg;
2855    Tcl_HashEntry   *entryPtr;
2856    int              left = 0, useFastAdd;
2857    double           dRight = 0.0;
2858    char            *leftStr = NULL, *rightStr = NULL;
2859    const char      *str;
2860    Tcl_DString      dStr;
2861#if TclOnly8Bits
2862    char            *fStr;
2863#else
2864    int              found, j;
2865    int              lenstr, fromlen, utfCharLen;
2866    char             utfBuf[TCL_UTF_MAX];
2867    Tcl_DString      tstr, tfrom, tto, tresult;
2868    Tcl_UniChar     *ufStr, *upfrom, unichar;
2869#endif
2870
2871    if (result->type == EmptyResult) useFastAdd = 1;
2872    else useFastAdd = 0;
2873
2874
2875    switch (step->intvalue) {
2876
2877    case f_position:
2878        XPATH_ARITYCHECK(step,0,errMsg);
2879        if (*docOrder) {
2880            rsSetInt (result, position+1);
2881        } else {
2882            rsSetInt (result, nodeList->nr_nodes - position);
2883        }
2884        break;
2885
2886    case f_last:
2887        XPATH_ARITYCHECK(step,0,errMsg);
2888        rsSetInt (result, nodeList->nr_nodes);
2889        break;
2890
2891    case f_number:
2892        xpathRSInit (&leftResult);
2893        if (xpathArity(step) == 0) {
2894            /*  no parameter, the context node is the nodeset to
2895             *  operate with
2896             */
2897            rsAddNodeFast( &leftResult, ctxNode);
2898        } else {
2899            XPATH_ARITYCHECK(step,1,errMsg);
2900            xpathRSInit (&leftResult);
2901            rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
2902                                nodeList, cbs, &leftResult, docOrder, errMsg);
2903            if (rc) {
2904                xpathRSFree( &leftResult );
2905                return rc;
2906            }
2907        }
2908        leftReal = xpathFuncNumber(&leftResult, &NaN);
2909        if (NaN) {
2910            if      (NaN == 2)  rsSetNaN (result);
2911            else if (NaN == 1)  rsSetInf (result);
2912            else                rsSetNInf (result);
2913        } else {
2914            rsSetReal (result, leftReal);
2915        }
2916        xpathRSFree( &leftResult );
2917        break;
2918
2919    case f_floor:
2920    case f_ceiling:
2921    case f_round:
2922        XPATH_ARITYCHECK(step,1,errMsg);
2923        xpathRSInit (&leftResult);
2924        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
2925                            nodeList, cbs, &leftResult, docOrder, errMsg);
2926        if (rc) {
2927            xpathRSFree( &leftResult );
2928            return rc;
2929        }
2930        leftReal = xpathFuncNumber(&leftResult, &NaN);
2931
2932        if (NaN) {
2933            if      (NaN == 2)  rsSetNaN (result);
2934            else if (NaN == 1)  rsSetInf (result);
2935            else                rsSetNInf (result);
2936        } else {
2937            if      (step->intvalue == f_floor)   leftReal = floor(leftReal);
2938            else if (step->intvalue == f_ceiling) leftReal = ceil(leftReal);
2939            else                                  leftReal =
2940                                                      xpathRound(leftReal);
2941            rsSetReal (result, leftReal);
2942        }
2943        xpathRSFree( &leftResult );
2944        break;
2945
2946    case f_boolean:
2947        XPATH_ARITYCHECK(step,1,errMsg);
2948        xpathRSInit (&leftResult);
2949        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
2950                            nodeList, cbs, &leftResult, docOrder, errMsg);
2951        if (rc) {
2952            xpathRSFree( &leftResult );
2953            return rc;
2954        }
2955        left = xpathFuncBoolean(&leftResult);
2956        rsSetBool (result, left);
2957        xpathRSFree( &leftResult );
2958        break;
2959
2960    case f_string:
2961    case f_normalizeSpace:
2962    case f_stringLength:
2963        xpathRSInit (&leftResult);
2964        if (step->child == NULL) {
2965            /*  no parameter, the context node is the nodeset to
2966             *  operate with
2967             */
2968            rsAddNodeFast( &leftResult, ctxNode);
2969
2970        } else {
2971            XPATH_ARITYCHECK(step,1,errMsg);
2972            xpathRSInit (&leftResult);
2973            rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
2974                                nodeList, cbs, &leftResult, docOrder, errMsg);
2975            if (rc) {
2976                xpathRSFree( &leftResult );
2977                return rc;
2978            }
2979            DBG(fprintf(stderr, "normalize-space: \n");
2980                rsPrint(&leftResult);
2981                )
2982        }
2983
2984        leftStr = xpathFuncString (&leftResult );
2985        xpathRSFree( &leftResult );
2986        DBG(fprintf(stderr, "leftStr='%s'\n", leftStr);)
2987        if      (step->intvalue == f_string)
2988            rsSetString (result, leftStr);
2989        else if (step->intvalue == f_stringLength) {
2990#if TclOnly8Bits
2991            rsSetInt (result, strlen(leftStr));
2992#else
2993            pto = leftStr;
2994            len = 0;
2995            while (*pto) {
2996                len++;
2997                i = UTF8_CHAR_LEN (*pto);
2998                if (!i) {
2999                    FREE (leftStr);
3000                    *errMsg = tdomstrdup("Can only handle UTF-8 chars up "
3001                                         "to 3 bytes length");
3002                    return XPATH_I18N_ERR;
3003                }
3004                pto += i;
3005            }
3006            rsSetInt (result, len);
3007#endif
3008        }
3009        else {
3010            pwhite = 1;
3011            pfrom = pto = leftStr;
3012            while (*pfrom) {
3013                switch (*pfrom) {
3014                case ' ' : case '\n': case '\r': case '\t':
3015                    if (!pwhite) {
3016                        *pto++ = ' ';
3017                        pwhite = 1;
3018                    }
3019                    break;
3020                default:
3021                    *pto++ = *pfrom;
3022                    pwhite = 0;
3023                    break;
3024                }
3025                pfrom++;
3026            }
3027            if ((pto > leftStr) && (*(pto-1) == ' ')) {
3028                pto--;  /* cut last empty space */
3029            }
3030            *pto = '\0';
3031            rsSetString (result, leftStr);
3032        }
3033        FREE(leftStr);
3034        break;
3035
3036    case f_not:
3037        XPATH_ARITYCHECK(step,1,errMsg);
3038        xpathRSInit (&leftResult);
3039        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
3040                            nodeList, cbs, &leftResult, docOrder, errMsg);
3041        if (rc) {
3042            xpathRSFree (&leftResult);
3043            return rc;
3044        }
3045        left = xpathFuncBoolean(&leftResult);
3046        xpathRSFree (&leftResult);
3047        rsSetBool (result, !left);
3048        break;
3049
3050    case f_true:
3051        XPATH_ARITYCHECK(step,0,errMsg);
3052        rsSetBool (result, 1);
3053        break;
3054
3055    case f_false:
3056        XPATH_ARITYCHECK(step,0,errMsg);
3057        rsSetBool (result, 0);
3058        break;
3059
3060    case f_id:
3061        XPATH_ARITYCHECK(step,1,errMsg);
3062        if (!ctxNode->ownerDocument->ids) {
3063            break;
3064        }
3065        xpathRSInit (&leftResult);
3066        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
3067                            nodeList, cbs, &leftResult, docOrder, errMsg);
3068        if (rc) {
3069            xpathRSFree( &leftResult );
3070            return rc;
3071        }
3072        DBG(fprintf(stderr, "id: \n");
3073            rsPrint(&leftResult);
3074            )
3075        if (leftResult.type == EmptyResult) {
3076            xpathRSFree (&leftResult);
3077            return XPATH_OK;
3078        }
3079        if (leftResult.type == xNodeSetResult) {
3080            for (i=0; i < leftResult.nr_nodes; i++) {
3081                leftStr = xpathFuncStringForNode (leftResult.nodes[i]);
3082                entryPtr = Tcl_FindHashEntry (ctxNode->ownerDocument->ids,
3083                                              leftStr);
3084                if (entryPtr) {
3085                    node = (domNode*) Tcl_GetHashValue (entryPtr);
3086                    /* Don't report nodes out of the fragment list */
3087                    if (node->parentNode != NULL ||
3088                        (node == node->ownerDocument->documentElement)) {
3089                        rsAddNode (result, node);
3090                    }
3091                }
3092                FREE(leftStr);
3093                /*xpathRSFree (&newNodeList);*/
3094            }
3095        } else {
3096            leftStr = xpathFuncString (&leftResult);
3097            from = 0;
3098            pwhite = 0;
3099            pfrom = pto = leftStr;
3100            while (*pto) {
3101                switch (*pto) {
3102                case ' ' : case '\n': case '\r': case '\t':
3103                    if (pwhite) {
3104                        pto++;
3105                        continue;
3106                    }
3107                    *pto = '\0';
3108                    entryPtr = Tcl_FindHashEntry (ctxNode->ownerDocument->ids,
3109                                                  pfrom);
3110                    if (entryPtr) {
3111                        node = (domNode*) Tcl_GetHashValue (entryPtr);
3112                        /* Don't report nodes out of the fragment list */
3113                        if (node->parentNode != NULL ||
3114                            (node == node->ownerDocument->documentElement)) {
3115                            rsAddNode (result, node);
3116                        }
3117                    }
3118                    pwhite = 1;
3119                    pto++;
3120                    continue;
3121                default:
3122                    if (pwhite) {
3123                        pfrom = pto;
3124                        pwhite = 0;
3125                    }
3126                    pto++;
3127                }
3128            }
3129            if (!pwhite) {
3130                entryPtr = Tcl_FindHashEntry (ctxNode->ownerDocument->ids,
3131                                              pfrom);
3132                if (entryPtr) {
3133                    node = (domNode*) Tcl_GetHashValue (entryPtr);
3134                    /* Don't report nodes out of the fragment list */
3135                    if (node->parentNode != NULL ||
3136                        (node == node->ownerDocument->documentElement)) {
3137                        rsAddNode (result, node);
3138                    }
3139                }
3140            }
3141            FREE(leftStr);
3142        }
3143        sortByDocOrder (result);
3144        xpathRSFree (&leftResult);
3145        break;
3146
3147    case f_sum:
3148        XPATH_ARITYCHECK(step,1,errMsg);
3149        xpathRSInit (&leftResult);
3150        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
3151                            nodeList, cbs, &leftResult, docOrder, errMsg);
3152        if (rc) {
3153            xpathRSFree( &leftResult );
3154            return rc;
3155        }
3156        if (leftResult.type != xNodeSetResult) {
3157            if (leftResult.type == EmptyResult) {
3158                rsSetInt (result, 0);
3159                return XPATH_OK;
3160            } else {
3161                xpathRSFree( &leftResult );
3162                *errMsg = tdomstrdup("sum() requires a node set!");
3163                xpathRSFree( &leftResult );
3164                return XPATH_EVAL_ERR;
3165            }
3166        }
3167
3168        xpathRSInit(&rightResult);
3169        rightResult.nr_nodes = 1;
3170        rightResult.type     = leftResult.type;
3171        leftReal = 0.0;
3172        for (i=0; i<leftResult.nr_nodes; i++) {
3173            rightResult.nodes = &(leftResult.nodes[i]);
3174            DBG(fprintf(stderr, "leftReal = %f \n", leftReal);)
3175            leftReal += xpathFuncNumber(&rightResult, &NaN);
3176            if (NaN) {
3177                rsSetNaN (result);
3178                xpathRSFree( &leftResult );
3179                return XPATH_OK;
3180            }
3181            DBG(fprintf(stderr, "leftReal = %f \n", leftReal);)
3182        }
3183        rsSetReal (result, leftReal);
3184        xpathRSFree( &leftResult );
3185        break;
3186
3187    case f_lang:
3188        XPATH_ARITYCHECK(step,1,errMsg);
3189        xpathRSInit (&leftResult);
3190        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
3191                            nodeList, cbs, &leftResult, docOrder, errMsg);
3192        if (rc) {
3193            xpathRSFree (&leftResult);
3194            return rc;
3195        }
3196        leftStr = xpathFuncString (&leftResult);
3197        if (ctxNode->nodeType != ELEMENT_NODE) {
3198            node = ctxNode->parentNode;
3199        } else {
3200            node = ctxNode;
3201        }
3202        while (node) {
3203            attr = node->firstAttr;
3204            while (attr) {
3205                if (strcmp (attr->nodeName, "xml:lang")!=0) {
3206                    attr = attr->nextSibling;
3207                    continue;
3208                }
3209                tcldom_tolower (attr->nodeValue, tmp, 80);
3210                tcldom_tolower (leftStr, tmp1, 80);
3211                if (strcmp (tmp, tmp1)==0) {
3212                    rsSetBool (result, 1);
3213                    FREE(leftStr);
3214                    xpathRSFree (&leftResult);
3215                    return XPATH_OK;
3216                } else {
3217                    pfrom = tmp;
3218                    i = 0;
3219                    while (*pfrom && i < 79) {
3220                        if (*pfrom == '-') {
3221                            *pfrom = '\0';
3222                            break;
3223                        }
3224                        pfrom++;
3225                        i++;
3226                    }
3227                    if (strcmp (tmp, tmp1)==0) {
3228                        rsSetBool (result, 1);
3229                        FREE(leftStr);
3230                        xpathRSFree (&leftResult);
3231                        return XPATH_OK;
3232                    } else {
3233                        rsSetBool (result, 0);
3234                        FREE(leftStr);
3235                        xpathRSFree (&leftResult);
3236                        return XPATH_OK;
3237                    }
3238                }
3239            }
3240            node = node->parentNode;
3241        }
3242        rsSetBool (result, 0);
3243        FREE(leftStr);
3244        xpathRSFree (&leftResult);
3245        break;
3246
3247    case f_startsWith:
3248    case f_contains:
3249    case f_substringBefore:
3250    case f_substringAfter:
3251        XPATH_ARITYCHECK(step,2,errMsg);
3252        xpathRSInit (&leftResult);
3253        xpathRSInit (&rightResult);
3254
3255        savedDocOrder = *docOrder;
3256        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
3257                            nodeList, cbs, &leftResult, docOrder, errMsg);
3258        CHECK_RC;
3259        *docOrder = savedDocOrder;
3260
3261        rc = xpathEvalStep( step->child->next, ctxNode, exprContext, position,
3262                            nodeList, cbs, &rightResult, docOrder, errMsg);
3263        CHECK_RC;
3264        *docOrder = savedDocOrder;
3265
3266
3267        DBG(fprintf(stderr, "\nsubstring-* left,right:\n");
3268            rsPrint(&leftResult);
3269            rsPrint(&rightResult);
3270            )
3271        leftStr  = xpathFuncString( &leftResult  );
3272        rightStr = xpathFuncString( &rightResult );
3273        DBG(fprintf(stderr, "substring-* '%s' '%s' \n", leftStr, rightStr);)
3274        if (step->intvalue == f_contains) {
3275            if (strstr(leftStr, rightStr) != NULL) {
3276                rsSetBool (result, 1);
3277            } else {
3278                rsSetBool (result, 0);
3279            }
3280        } else
3281        if (step->intvalue == f_substringBefore) {
3282            pfrom = strstr(leftStr, rightStr);
3283            if (pfrom != NULL) {
3284                DBG(fprintf(stderr, "substring-before '%s' '%s' : ", leftStr, rightStr);)
3285                    *pfrom = '\0';
3286                DBG(fprintf(stderr, "'%s' \n", leftStr);)
3287                    rsSetString (result, leftStr);
3288            } else {
3289                rsSetString (result, "");
3290            }
3291        } else
3292        if (step->intvalue == f_substringAfter) {
3293            pfrom = strstr(leftStr, rightStr);
3294            if (pfrom != NULL) {
3295                rsSetString (result, pfrom + strlen (rightStr));
3296            } else {
3297                rsSetString (result, "");
3298            }
3299        } else {
3300            /* starts-with */
3301            i = strlen(rightStr);
3302            if(strncmp(leftStr, rightStr, i)==0) {
3303                rsSetBool (result, 1);
3304            } else {
3305                rsSetBool (result, 0);
3306            }
3307        }
3308        xpathRSFree (&leftResult);
3309        xpathRSFree (&rightResult);
3310        FREE(rightStr);
3311        FREE(leftStr);
3312        break;
3313
3314    case f_concat:
3315        if (xpathArity(step) < 2) {
3316            *errMsg = tdomstrdup("wrong number of parameters!");
3317            return XPATH_EVAL_ERR;
3318        }
3319        nextStep = step->child;
3320        pto = MALLOC(1);
3321        *pto = '\0';
3322        len = 0;
3323        while (nextStep) {
3324            xpathRSInit (&leftResult);
3325            savedDocOrder = *docOrder;
3326            rc = xpathEvalStep( nextStep, ctxNode, exprContext, position,
3327                                nodeList, cbs, &leftResult, docOrder, errMsg);
3328            if (rc) {
3329                FREE (pto);
3330                return rc;
3331            }
3332            *docOrder = savedDocOrder;
3333
3334            leftStr  = xpathFuncString( &leftResult  );
3335            pto = (char*)REALLOC(pto, 1+len+strlen(leftStr));
3336            memmove(pto + len, leftStr, strlen(leftStr));
3337            len += strlen(leftStr);
3338            *(pto + len) = '\0';
3339            xpathRSFree( &leftResult );
3340            FREE(leftStr);
3341            nextStep = nextStep->next;
3342        }
3343        rsSetString (result, pto);
3344        FREE(pto);
3345        break;
3346
3347    case f_substring:
3348        i = xpathArity(step);
3349        if (i != 2 && i != 3) {
3350            *errMsg = tdomstrdup("wrong number of parameters!");
3351            return XPATH_EVAL_ERR;
3352        }
3353        xpathRSInit (&leftResult);
3354        savedDocOrder = *docOrder;
3355        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
3356                            nodeList, cbs, &leftResult, docOrder, errMsg);
3357        CHECK_RC;
3358        *docOrder = savedDocOrder;
3359
3360        xpathRSInit (&rightResult);
3361        rc = xpathEvalStep( step->child->next, ctxNode, exprContext, position,
3362                            nodeList, cbs, &rightResult, docOrder, errMsg);
3363        CHECK_RC;
3364        *docOrder = savedDocOrder;
3365
3366        leftStr  = xpathFuncString( &leftResult );
3367        xpathRSFree (&leftResult);
3368        from = xpathRound(xpathFuncNumber(&rightResult, &NaN))-1;
3369        xpathRSFree( &rightResult );
3370        if (NaN) {
3371            FREE(leftStr);
3372            rsSetString (result, "");
3373            return XPATH_OK;
3374        }
3375
3376        if (step->child->next->next) {
3377            xpathRSInit (&rightResult);
3378            savedDocOrder = *docOrder;
3379            rc = xpathEvalStep( step->child->next->next, ctxNode, exprContext,
3380                                position, nodeList, cbs, &rightResult,
3381                                docOrder, errMsg);
3382            CHECK_RC;
3383            *docOrder = savedDocOrder;
3384
3385            dRight = xpathFuncNumber (&rightResult, &NaN);
3386            len = xpathRound(dRight);
3387            xpathRSFree (&rightResult);
3388            if (NaN) {
3389                if (NaN == 1) {
3390                    len = INT_MAX;
3391                } else {
3392                    FREE(leftStr);
3393                    rsSetString (result, "");
3394                    return XPATH_OK;
3395                }
3396            }
3397            xpathRSFree (&rightResult);
3398            if (from < 0) {
3399                len = len + from;
3400                if (len <= 0) {
3401                    FREE(leftStr);
3402                    rsSetString (result, "");
3403                    return XPATH_OK;
3404                }
3405                from = 0;
3406            }
3407        } else {
3408            if (from < 0) from = 0;
3409#if TclOnly8Bits
3410            len = strlen(leftStr) - from;
3411#else
3412            len = INT_MAX;
3413#endif
3414        }
3415
3416#if TclOnly8Bits
3417        if (from >= (int) strlen(leftStr)) {
3418            rsSetString (result, "");
3419            FREE(leftStr);
3420            return XPATH_OK;
3421        } else {
3422            if ( (len == INT_MAX) || ((from + len) > (int) strlen(leftStr)) ) {
3423                len =  strlen(leftStr) - from;
3424            }
3425        }
3426        DBG(fprintf(stderr, "substring leftStr='%s' from=%d len=%d \n",
3427                    leftStr, from, len);
3428            )
3429
3430            *(leftStr+from+len) = '\0';
3431        rsSetString (result, (leftStr+from));
3432#else
3433        pfrom = leftStr;
3434        while (*pfrom && (from > 0)) {
3435            i = UTF8_CHAR_LEN (*pfrom);
3436            if (!i) {
3437                FREE (leftStr);
3438                *errMsg = tdomstrdup("Can only handle UTF-8 chars up "
3439                                     "to 3 bytes length");
3440                return XPATH_I18N_ERR;
3441            }
3442            pfrom += i;
3443            from--;
3444        }
3445        if (len < INT_MAX) {
3446            pto = pfrom;
3447            while (*pto && (len > 0)) {
3448                i = UTF8_CHAR_LEN (*pto);
3449                if (!i) {
3450                    FREE (leftStr);
3451                    *errMsg = tdomstrdup("Can only handle UTF-8 chars up "
3452                                         "to 3 bytes length");
3453                    return XPATH_I18N_ERR;
3454                }
3455                pto += i;
3456                len--;
3457            }
3458            *pto = '\0';
3459        }
3460        rsSetString (result, pfrom);
3461#endif
3462        FREE(leftStr);
3463        break;
3464
3465    case f_translate:
3466        XPATH_ARITYCHECK(step,3,errMsg);
3467        xpathRSInit (&leftResult);
3468        savedDocOrder = *docOrder;
3469        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
3470                            nodeList, cbs, &leftResult, docOrder, errMsg);
3471        CHECK_RC;
3472        *docOrder = savedDocOrder;
3473        xpathRSInit (&rightResult);
3474        rc = xpathEvalStep( step->child->next, ctxNode, exprContext, position,
3475                            nodeList, cbs, &rightResult, docOrder, errMsg);
3476        CHECK_RC;
3477        *docOrder = savedDocOrder;
3478        xpathRSInit (&replaceResult);
3479        rc = xpathEvalStep( step->child->next->next, ctxNode, exprContext,
3480                            position, nodeList, cbs, &replaceResult, docOrder,
3481                            errMsg);
3482        CHECK_RC;
3483        *docOrder = savedDocOrder;
3484        leftStr    = xpathFuncString( &leftResult    );
3485        rightStr   = xpathFuncString( &rightResult   );
3486        replaceStr = xpathFuncString( &replaceResult );
3487
3488
3489#if TclOnly8Bits
3490        len = strlen(replaceStr);
3491        pfrom = pto = leftStr;
3492        while (*pfrom) {
3493            fStr = strchr(rightStr, *pfrom);
3494            if (fStr == NULL) {
3495                *pto++ = *pfrom;
3496            } else {
3497                i = (fStr - rightStr);
3498                if (i < len) {
3499                    *pto++ = *(replaceStr+i);
3500                }
3501            }
3502            pfrom++;
3503        }
3504        *pto = '\0';
3505        rsSetString (result, leftStr);
3506#else
3507        Tcl_DStringInit (&tstr);
3508        Tcl_DStringInit (&tfrom);
3509        Tcl_DStringInit (&tto);
3510        Tcl_DStringInit (&tresult);
3511
3512        Tcl_UtfToUniCharDString (leftStr, -1, &tstr);
3513        Tcl_UtfToUniCharDString (rightStr, -1, &tfrom);
3514        Tcl_UtfToUniCharDString (replaceStr, -1, &tto);
3515
3516        lenstr  = Tcl_DStringLength (&tstr) / sizeof (Tcl_UniChar);
3517        fromlen = Tcl_DStringLength (&tfrom) / sizeof (Tcl_UniChar);
3518        len     = Tcl_DStringLength (&tto) / sizeof (Tcl_UniChar);
3519
3520        upfrom = (Tcl_UniChar *)Tcl_DStringValue (&tstr);
3521        for (i = 0; i < lenstr; i++) {
3522            found = 0;
3523            ufStr = (Tcl_UniChar *)Tcl_DStringValue (&tfrom);
3524            for (j = 0; j < fromlen; j++) {
3525                if (*ufStr == *upfrom) {
3526                    found = 1;
3527                    break;
3528                }
3529                ufStr++;
3530            }
3531            if (found) {
3532                if (j < len) {
3533                    unichar = Tcl_UniCharAtIndex (replaceStr, j);
3534                    utfCharLen = Tcl_UniCharToUtf (unichar, utfBuf);
3535                    Tcl_DStringAppend (&tresult, utfBuf, utfCharLen);
3536                }
3537            } else {
3538                utfCharLen = Tcl_UniCharToUtf (*upfrom, utfBuf);
3539                Tcl_DStringAppend (&tresult, utfBuf, utfCharLen);
3540            }
3541            upfrom++;
3542        }
3543        rsSetString (result, Tcl_DStringValue (&tresult));
3544        Tcl_DStringFree (&tstr);
3545        Tcl_DStringFree (&tfrom);
3546        Tcl_DStringFree (&tto);
3547        Tcl_DStringFree (&tresult);
3548#endif
3549
3550        xpathRSFree( &replaceResult );
3551        xpathRSFree( &rightResult   );
3552        xpathRSFree( &leftResult    );
3553        FREE(leftStr); FREE(rightStr); FREE(replaceStr);
3554        break;
3555
3556    case f_count:
3557        XPATH_ARITYCHECK(step,1,errMsg);
3558        xpathRSInit (&leftResult);
3559        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
3560                            nodeList, cbs, &leftResult, docOrder, errMsg);
3561        if (rc) {
3562            xpathRSFree( &leftResult );
3563            return rc;
3564        }
3565        if (leftResult.type == EmptyResult) {
3566            rsSetInt (result, 0);
3567            return XPATH_OK;
3568        }
3569        if (leftResult.type != xNodeSetResult) {
3570            *errMsg = tdomstrdup("count() requires a node set!");
3571            xpathRSFree( &leftResult );
3572            return XPATH_EVAL_ERR;
3573        }
3574        rsSetInt (result, leftResult.nr_nodes);
3575        xpathRSFree (&leftResult);
3576        break;
3577
3578    case f_unparsedEntityUri:
3579        XPATH_ARITYCHECK(step,1,errMsg);
3580        if (!ctxNode->ownerDocument->unparsedEntities) {
3581            break;
3582        }
3583        xpathRSInit (&leftResult);
3584        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
3585                            nodeList, cbs, &leftResult, docOrder, errMsg);
3586        if (rc) {
3587            xpathRSFree( &leftResult );
3588            return rc;
3589        }
3590        leftStr = xpathFuncString (&leftResult);
3591        entryPtr = Tcl_FindHashEntry (ctxNode->ownerDocument->unparsedEntities,
3592                                      leftStr);
3593        if (entryPtr) {
3594            rsSetString (result, (char *)Tcl_GetHashValue (entryPtr));
3595        } else {
3596            rsSetString (result, "");
3597        }
3598        FREE(leftStr);
3599        xpathRSFree (&leftResult);
3600        break;
3601
3602    case f_localName:
3603    case f_name:
3604    case f_namespaceUri:
3605    case f_generateId:
3606        xpathRSInit (&leftResult);
3607        if (step->child == NULL) {
3608            /*  no parameter, the context node is the nodeset to
3609             *  operate with
3610             */
3611            rsAddNodeFast( &leftResult, ctxNode);
3612        } else {
3613            XPATH_ARITYCHECK(step,1,errMsg);
3614            xpathRSInit (&leftResult);
3615            rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
3616                                nodeList, cbs, &leftResult, docOrder, errMsg);
3617            if (rc) {
3618                xpathRSFree( &leftResult );
3619                return rc;
3620            }
3621        }
3622        if (leftResult.type == EmptyResult) {
3623            rsSetString (result, "");
3624            return XPATH_OK;
3625        }
3626
3627        if (step->intvalue == f_generateId) {
3628            if (leftResult.type != xNodeSetResult) {
3629                *errMsg = tdomstrdup("generate-id() requires a nodeset or no argument!");
3630                xpathRSFree (&leftResult);
3631                return XPATH_EVAL_ERR;
3632            }
3633            if (leftResult.nodes[0]->nodeType == ATTRIBUTE_NODE) {
3634                node = ((domAttrNode*)leftResult.nodes[0])->parentNode;
3635                i = 0;
3636                attr = node->firstAttr;
3637                while (attr) {
3638                    if ((domNode*)attr == leftResult.nodes[0]) break;
3639                    attr = attr->nextSibling;
3640                    i++;
3641                }
3642                sprintf(tmp,"id%p-%d", node, i);
3643            } else {
3644                sprintf(tmp,"id%p", leftResult.nodes[0]);
3645            }
3646            rsSetString (result, tmp);
3647        } else
3648
3649        if (step->intvalue == f_namespaceUri) {
3650            if (leftResult.type != xNodeSetResult) {
3651                *errMsg = tdomstrdup("namespace-uri() requires a node set!");
3652                xpathRSFree( &leftResult );
3653                return XPATH_EVAL_ERR;
3654            }
3655            if ( (leftResult.nr_nodes <= 0)
3656                 || (   leftResult.nodes[0]->nodeType != ELEMENT_NODE
3657                        && leftResult.nodes[0]->nodeType != ATTRIBUTE_NODE )
3658                )
3659                {
3660                    rsSetString (result, "");
3661                } else {
3662                    rsSetString (result, domNamespaceURI(leftResult.nodes[0]));
3663                }
3664        } else
3665
3666        if (step->intvalue == f_localName) {
3667            if (leftResult.type != xNodeSetResult) {
3668                *errMsg = tdomstrdup("local-name() requires a node set!");
3669                xpathRSFree( &leftResult );
3670                return XPATH_EVAL_ERR;
3671            }
3672            if (leftResult.nodes[0]->nodeType == ELEMENT_NODE) {
3673                if (leftResult.nodes[0] ==
3674                    leftResult.nodes[0]->ownerDocument->rootNode) {
3675                    rsSetString (result, "");
3676                } else {
3677                    rsSetString (result, domGetLocalName(leftResult.nodes[0]->nodeName));
3678                }
3679            } else
3680            if (leftResult.nodes[0]->nodeType == ATTRIBUTE_NODE) {
3681                str = domGetLocalName(((domAttrNode*)leftResult.nodes[0])->nodeName);
3682                if (str[0] == 'x' && strcmp(str, "xmlns")==0) {
3683                    rsSetString (result, "");
3684                } else {
3685                    rsSetString (result, str);
3686                }
3687            } else
3688            if (leftResult.nodes[0]->nodeType == PROCESSING_INSTRUCTION_NODE) {
3689                if (((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength > 79) {
3690                    memmove(tmp, ((domProcessingInstructionNode*)leftResult.nodes[0])->targetValue, 79);
3691                    tmp[79]= '\0';
3692                } else {
3693                    memmove(tmp, ((domProcessingInstructionNode*)leftResult.nodes[0])->targetValue,
3694                            ((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength);
3695                    tmp[((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength] = '\0';
3696                }
3697                rsSetString (result, tmp);
3698            } else {
3699                rsSetString (result, "");
3700            }
3701        } else
3702
3703        if (step->intvalue == f_name) {
3704            if (   leftResult.type != xNodeSetResult ) {
3705                *errMsg = tdomstrdup("name() requires a node set!");
3706                xpathRSFree( &leftResult );
3707                return XPATH_EVAL_ERR;
3708            }
3709            if (leftResult.nodes[0]->nodeType == ELEMENT_NODE) {
3710                if (leftResult.nodes[0] ==
3711                    leftResult.nodes[0]->ownerDocument->rootNode) {
3712                    rsSetString (result, "");
3713                } else {
3714                    rsSetString (result, leftResult.nodes[0]->nodeName);
3715                }
3716            } else
3717            if (leftResult.nodes[0]->nodeType == ATTRIBUTE_NODE) {
3718                if (leftResult.nodes[0]->nodeFlags & IS_NS_NODE) {
3719                    if (((domAttrNode *)leftResult.nodes[0])->nodeName[5] == '\0') {
3720                        rsSetString (result, "");
3721                    } else {
3722                        rsSetString (result, &((domAttrNode*)leftResult.nodes[0])->nodeName[6]);
3723                    }
3724                } else {
3725                    rsSetString (result, ((domAttrNode*)leftResult.nodes[0])->nodeName );
3726                }
3727            } else
3728            if (leftResult.nodes[0]->nodeType == PROCESSING_INSTRUCTION_NODE) {
3729                if (((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength > 79) {
3730                    memmove(tmp, ((domProcessingInstructionNode*)leftResult.nodes[0])->targetValue, 79);
3731                    tmp[79]= '\0';
3732                } else {
3733                    memmove(tmp, ((domProcessingInstructionNode*)leftResult.nodes[0])->targetValue,
3734                            ((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength);
3735                    tmp[((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength] = '\0';
3736                }
3737                rsSetString (result, tmp);
3738            } else {
3739                rsSetString (result, "");
3740            }
3741        }
3742        xpathRSFree( &leftResult );
3743        break;
3744
3745    case f_fqfunction:
3746        Tcl_DStringInit (&dStr);
3747        if (cbs->funcCB == NULL) {
3748            Tcl_DStringAppend (&dStr, "Unknown function ", -1);
3749        }
3750        Tcl_DStringAppend (&dStr, step->strvalue, -1);
3751        Tcl_DStringAppend (&dStr, "::", 2);
3752        nextStep = step->child;
3753        Tcl_DStringAppend (&dStr, nextStep->strvalue, -1);
3754        if (cbs->funcCB == NULL) {
3755            *errMsg = tdomstrdup (Tcl_DStringValue (&dStr));
3756            Tcl_DStringFree (&dStr);
3757            return XPATH_EVAL_ERR;
3758        }
3759        /* fall throu */
3760
3761    default:
3762        if (cbs->funcCB == NULL) {
3763            if (strlen(step->strvalue)>50) *(step->strvalue + 50) = '\0';
3764            sprintf(tmp, "Unknown function '%s'!", step->strvalue);
3765            *errMsg = tdomstrdup(tmp);
3766            return XPATH_EVAL_ERR;
3767        }
3768
3769        /* count number of arguments (to be able to allocate later) */
3770        argc = 0;
3771        if (step->intvalue == f_fqfunction) {
3772            nextStep = step->child->next;
3773        } else {
3774            nextStep = step->child;
3775        }
3776        while (nextStep) {
3777            argc++;
3778            nextStep = nextStep->next;
3779        }
3780        args = (xpathResultSets*)MALLOC((argc+1) * sizeof(xpathResultSets));
3781        args[0] = NULL;
3782        argc = 0;
3783        if (step->intvalue == f_fqfunction) {
3784            nextStep = step->child->next;
3785        } else {
3786            nextStep = step->child;
3787        }
3788        savedDocOrder = *docOrder;
3789        while (nextStep) {
3790            arg = (xpathResultSet*)MALLOC(sizeof(xpathResultSet));
3791            args[argc++] = arg;
3792            args[argc]   = NULL;
3793            xpathRSInit (arg);
3794            rc = xpathEvalStep( nextStep, ctxNode, exprContext, position,
3795                                nodeList, cbs, arg, docOrder, errMsg);
3796            if (rc) goto unknownfunccleanup;
3797            *docOrder = savedDocOrder;
3798            nextStep = nextStep->next;
3799        }
3800        if (step->intvalue == f_fqfunction) {
3801            rc = (cbs->funcCB) (cbs->funcClientData, Tcl_DStringValue (&dStr),
3802                                ctxNode, position, nodeList, exprContext,
3803                                argc, args, result, errMsg);
3804        } else {
3805            rc = (cbs->funcCB) (cbs->funcClientData, step->strvalue,
3806                                ctxNode, position, nodeList, exprContext,
3807                                argc, args, result, errMsg);
3808        }
3809    unknownfunccleanup:
3810        argc = 0;
3811        while ( args[argc] != NULL) {
3812            xpathRSFree( args[argc] );
3813            FREE((char*)args[argc++]);
3814        }
3815        FREE((char*)args);
3816        if (step->intvalue == f_fqfunction) {
3817            Tcl_DStringFree (&dStr);
3818        }
3819        return rc;
3820    }
3821    return XPATH_OK;
3822}
3823
3824/*----------------------------------------------------------------------------
3825|   xpathEvalStep
3826|
3827\---------------------------------------------------------------------------*/
3828static int xpathEvalStep (
3829    ast                step,
3830    domNode           *ctxNode,
3831    domNode           *exprContext,
3832    int                position,
3833    xpathResultSet    *nodeList,
3834    xpathCBs          *cbs,
3835    xpathResultSet    *result,
3836    int               *docOrder,
3837    char             **errMsg
3838)
3839{
3840    xpathResultSet   leftResult, rightResult;
3841    xpathResultSet  *pleftResult, *prightResult, tResult;
3842    int              i, j, k, rc, res, NaN, NaN1, switchResult, count = 0;
3843    domNode         *node, *child, *startingNode, *ancestor;
3844    domAttrNode     *attr;
3845    int              savedDocOrder, predLimit;
3846    int              left = 0, right = 0, useFastAdd;
3847    double           dLeft = 0.0, dRight = 0.0, dTmp;
3848    char            *leftStr = NULL, *rightStr = NULL;
3849    astType          savedAstType;
3850
3851    if (result->type == EmptyResult) useFastAdd = 1;
3852    else useFastAdd = 0;
3853
3854    switch (step->type) {
3855
3856    case AxisChild:
3857        DBG(fprintf(stderr, "AxisChild ctxNode->nodeType = %d \n",
3858                    ctxNode->nodeType);)
3859        *docOrder = 1;
3860        if (ctxNode->nodeType != ELEMENT_NODE) return XPATH_OK;
3861        DBG(fprintf(stderr, "AxisChild: scanning \n");)
3862        child = ctxNode->firstChild;
3863        if (step->intvalue) {
3864            while (child && (count < step->intvalue)) {
3865                DBG(fprintf(stderr, "AxisChild: child '%s' domNode%p \n",
3866                            child->nodeName, child);)
3867                if (xpathNodeTest(child, step)) {
3868                    DBG(fprintf(stderr,
3869                      "AxisChild: after node taking child '%s' domNode%p \n",
3870                                child->nodeName, child);)
3871                    rsAddNodeFast( result, child);
3872                    count++;
3873                }
3874                child = child->nextSibling;
3875            }
3876        } else {
3877            while (child) {
3878                DBG(fprintf(stderr, "AxisChild: child '%s' domNode%p \n",
3879                            child->nodeName, child);)
3880                if (xpathNodeTest(child, step)) {
3881                    DBG(fprintf(stderr,
3882                      "AxisChild: after node taking child '%s' domNode%p \n",
3883                                child->nodeName, child);)
3884                    rsAddNodeFast( result, child);
3885                }
3886                child = child->nextSibling;
3887            }
3888        }
3889        DBG( fprintf(stderr,"AxisChild result:\n");
3890             rsPrint(result);
3891        )
3892        break;
3893
3894    case SlashSlash:
3895        if (step->intvalue) predLimit = 1;
3896        else predLimit = 0;
3897        predLimit = 0;
3898        xpathRSInit (&tResult);
3899        node = ctxNode->firstChild;
3900        while (node) {
3901            if (node->nodeType == ELEMENT_NODE) {
3902                rc = xpathEvalStep (step, node, exprContext, position,
3903                                    nodeList, cbs, result, docOrder, errMsg);
3904                if (rc) {
3905                    xpathRSFree (&tResult);
3906                    return rc;
3907                }
3908            }
3909            if (xpathNodeTest(node, step)) {
3910                rsAddNodeFast( &tResult, node);
3911                if (predLimit) {
3912                    count++;
3913                    if (count >= step->intvalue) break;
3914                }
3915            }
3916            node = node->nextSibling;
3917        }
3918        if (node) {
3919            node = node->nextSibling;
3920            while (node) {
3921                if (node->nodeType == ELEMENT_NODE) {
3922                    rc = xpathEvalStep (step, node, exprContext, position,
3923                                        nodeList, cbs, result, docOrder,
3924                                        errMsg);
3925                    if (rc) {
3926                        xpathRSFree (&tResult);
3927                        return rc;
3928                    }
3929                }
3930                node = node->nextSibling;
3931            }
3932        }
3933        rc = xpathEvalPredicate (step->next, exprContext, result, &tResult,
3934                                  cbs, docOrder, errMsg);
3935        xpathRSFree (&tResult);
3936        CHECK_RC;
3937        break;
3938
3939    case AxisDescendant:
3940    case AxisDescendantOrSelf:
3941        if (step->next && step->next->type == Pred) {
3942            *docOrder = 1;
3943            if (ctxNode->nodeType == ATTRIBUTE_NODE
3944                && step->type == AxisDescendantOrSelf) {
3945                if (xpathNodeTest(ctxNode, step)) {
3946                    checkRsAddNode( result, ctxNode);
3947                }
3948                break;
3949            }
3950            if (ctxNode->nodeType != ELEMENT_NODE) return XPATH_OK;
3951            if (step->type == AxisDescendantOrSelf) {
3952                if (xpathNodeTest(ctxNode, step)) {
3953                    xpathRSInit (&tResult);
3954                    rsAddNodeFast( &tResult, ctxNode);
3955                    rc = xpathEvalPredicate (step->next, exprContext, result,
3956                                              &tResult, cbs, docOrder, errMsg);
3957                    xpathRSFree (&tResult);
3958                    CHECK_RC;
3959                }
3960            }
3961            savedAstType = step->type;
3962            step->type = SlashSlash;
3963            rc = xpathEvalStep (step, ctxNode, exprContext, position,
3964                                nodeList, cbs, result, docOrder, errMsg);
3965            step->type = savedAstType;
3966            CHECK_RC;
3967            break;
3968        }
3969        /* whithout following Pred step, // is the same as
3970           AxisDescendantOrSelf, fall throu */
3971
3972    case AxisDescendantLit:
3973    case AxisDescendantOrSelfLit:
3974        *docOrder = 1;
3975        if (step->intvalue
3976            && (step->type == AxisDescendantLit
3977                || step->type == AxisDescendantOrSelfLit)) predLimit = 1;
3978        else predLimit = 0;
3979        if (ctxNode->nodeType == ATTRIBUTE_NODE
3980            && (step->type == AxisDescendantOrSelf
3981                || step->type == AxisDescendantOrSelfLit)) {
3982            if (xpathNodeTest(ctxNode, step)) {
3983                checkRsAddNode( result, ctxNode);
3984            }
3985            break;
3986        }
3987        if (ctxNode->nodeType != ELEMENT_NODE) return XPATH_OK;
3988        if (step->type == AxisDescendantOrSelf
3989            || step->type == AxisDescendantOrSelfLit) {
3990            if (xpathNodeTest(ctxNode, step)) {
3991                checkRsAddNode( result, ctxNode);
3992                if (predLimit) {
3993                    count++;
3994                }
3995            }
3996        }
3997
3998        startingNode = ctxNode;
3999        node = ctxNode->firstChild;
4000        while (node && node != startingNode) {
4001            if (xpathNodeTest(node, step)) {
4002                 checkRsAddNode( result, node);
4003                 if (predLimit) {
4004                     count++;
4005                     if (count >= step->intvalue) break;
4006                 }
4007            }
4008            if ((node->nodeType == ELEMENT_NODE) && (node->firstChild)) {
4009                node = node->firstChild;
4010                continue;
4011            }
4012            if (node->nextSibling) {
4013                node = node->nextSibling;
4014                continue;
4015            }
4016            while ( node->parentNode &&
4017                    (node->parentNode != startingNode) &&
4018                    (node->parentNode->nextSibling == NULL) ) {
4019
4020                node = node->parentNode;
4021            }
4022            if ((node != startingNode) &&
4023                (node->parentNode)     &&
4024                (node->parentNode != startingNode)
4025                ) {
4026                node = node->parentNode->nextSibling;
4027            } else {
4028                break;
4029            }
4030        }
4031        break;
4032
4033    case AxisSelf:
4034        *docOrder = 1;
4035        DBG(fprintf(stderr, "AxisSelf :: \n");)
4036        if (xpathNodeTest(ctxNode, step)) {
4037            checkRsAddNode( result, ctxNode);
4038        }
4039        break;
4040
4041    case GetContextNode:
4042        checkRsAddNode( result, ctxNode);
4043        break;
4044
4045    case AxisAttribute:
4046        *docOrder = 1;
4047        DBG(fprintf(stderr, "AxisAttribute %s \n", step->child->strvalue);)
4048        if (ctxNode->nodeType != ELEMENT_NODE) return XPATH_OK;
4049        if (step->child->type == IsElement) {
4050            step->child->type = IsAttr;
4051        }
4052        if (step->child->type == IsAttr) {
4053            if (strcmp(step->child->strvalue, "*")==0) {
4054                attr = ctxNode->firstAttr;
4055                while (attr) {
4056                    if (!(attr->nodeFlags & IS_NS_NODE)) {
4057                        rsAddNodeFast (result, (domNode *)attr);
4058                    }
4059                    attr = attr->nextSibling;
4060                }
4061            } else {
4062                attr = ctxNode->firstAttr;
4063                while (attr && (attr->nodeFlags & IS_NS_NODE))
4064                    attr = attr->nextSibling;
4065                while (attr) {
4066                    if (xpathNodeTest( (domNode*)attr, step)) {
4067                        rsAddNodeFast (result, (domNode *)attr);
4068                    }
4069                    attr = attr->nextSibling;
4070                }
4071            }
4072        } else
4073        if (step->child->type == IsNSAttr) {
4074            attr = ctxNode->firstAttr;
4075            while (attr && (attr->nodeFlags & IS_NS_NODE))
4076                attr = attr->nextSibling;
4077            while (attr) {
4078                if (xpathNodeTest ( (domNode*)attr, step)) {
4079                    rsAddNodeFast (result, (domNode *)attr);
4080                }
4081                attr = attr->nextSibling;
4082            }
4083        }
4084        break;
4085
4086    case AxisParent:
4087        *docOrder = 1;
4088        if (ctxNode->nodeType == ATTRIBUTE_NODE) {
4089            if (xpathNodeTest(((domAttrNode *)ctxNode)->parentNode, step)) {
4090                rsAddNode(result,((domAttrNode *)ctxNode)->parentNode);
4091            }
4092        } else {
4093            if (ctxNode->parentNode) {
4094                if (xpathNodeTest(ctxNode->parentNode, step)) {
4095                    rsAddNode(result,ctxNode->parentNode);
4096                }
4097            } else {
4098                if (ctxNode->ownerDocument->rootNode != ctxNode
4099                    && xpathNodeTest (ctxNode->ownerDocument->rootNode,
4100                                      step)) {
4101                    rsAddNode (result, ctxNode->ownerDocument->rootNode);
4102                }
4103            }
4104        }
4105        break;
4106
4107    case GetParentNode:
4108        if (ctxNode->nodeType == ATTRIBUTE_NODE) {
4109            rsAddNode(result,((domAttrNode*)ctxNode)->parentNode);
4110        } else {
4111            if (ctxNode->parentNode) {
4112                rsAddNode(result,ctxNode->parentNode);
4113            } else {
4114                if (ctxNode != ctxNode->ownerDocument->rootNode) {
4115                    rsAddNode (result, ctxNode->ownerDocument->rootNode);
4116                }
4117            }
4118        }
4119        break;
4120
4121    case AxisAncestor:
4122    case AxisAncestorOrSelf:
4123        *docOrder = 0;
4124        xpathRSInit (&tResult);
4125        if (step->type == AxisAncestorOrSelf) {
4126            if (xpathNodeTest(ctxNode, step))
4127                rsAddNodeFast(&tResult, ctxNode);
4128        }
4129        if (ctxNode->nodeType == ATTRIBUTE_NODE) {
4130            ctxNode = ((domAttrNode *)ctxNode)->parentNode;
4131            if (xpathNodeTest(ctxNode, step))
4132                rsAddNodeFast(&tResult, ctxNode);
4133        }
4134        startingNode = ctxNode;
4135        while (ctxNode->parentNode) {
4136            ctxNode = ctxNode->parentNode;
4137            if (xpathNodeTest(ctxNode, step))
4138                rsAddNodeFast(&tResult, ctxNode);
4139        }
4140        if (startingNode != ctxNode->ownerDocument->rootNode) {
4141            if (xpathNodeTest (ctxNode->ownerDocument->rootNode, step)) {
4142                rsAddNodeFast (&tResult, ctxNode->ownerDocument->rootNode);
4143            }
4144        }
4145        for (i = tResult.nr_nodes - 1; i >= 0;  i--) {
4146            checkRsAddNode (result, tResult.nodes[i]);
4147        }
4148        xpathRSFree (&tResult);
4149        break;
4150
4151    case AxisFollowingSibling:
4152        *docOrder = 1;
4153        if (ctxNode->nodeType == ATTRIBUTE_NODE) {
4154            return XPATH_OK;
4155        }
4156        if (step->intvalue) {
4157            while (ctxNode->nextSibling && (count < step->intvalue)) {
4158                ctxNode = ctxNode->nextSibling;
4159                if (xpathNodeTest(ctxNode, step)) {
4160                    checkRsAddNode(result, ctxNode);
4161                    count++;
4162                }
4163            }
4164        } else {
4165            while (ctxNode->nextSibling) {
4166                ctxNode = ctxNode->nextSibling;
4167                if (xpathNodeTest(ctxNode, step)) {
4168                    checkRsAddNode(result, ctxNode);
4169                }
4170            }
4171        }
4172        break;
4173
4174    case AxisPrecedingSibling:
4175        *docOrder = 0;
4176        if (ctxNode->nodeType == ATTRIBUTE_NODE) {
4177            return XPATH_OK;
4178        }
4179        if (step->intvalue) {
4180            node = ctxNode->previousSibling;
4181            xpathRSInit (&tResult);
4182            while (node && (count < step->intvalue)) {
4183                if (xpathNodeTest (node, step)) {
4184                    rsAddNodeFast (&tResult, node);
4185                    count++;
4186                }
4187                node = node->previousSibling;
4188            }
4189            for (i = tResult.nr_nodes -1; i >= 0; i--) {
4190                checkRsAddNode (result, tResult.nodes[i]);
4191            }
4192            xpathRSFree (&tResult);
4193        } else {
4194            startingNode = ctxNode;
4195            if (startingNode->parentNode) {
4196                node = (startingNode->parentNode)->firstChild;
4197            } else {
4198                if (ctxNode == ctxNode->ownerDocument->rootNode)
4199                    return XPATH_OK;
4200                node = startingNode->ownerDocument->rootNode->firstChild;
4201            }
4202            while (node && (node != startingNode)) {
4203                if (xpathNodeTest(node, step)) {
4204                    checkRsAddNode(result, node);
4205                }
4206                node = node->nextSibling;
4207            }
4208        }
4209        break;
4210
4211    case AxisFollowing:
4212        *docOrder = 1;
4213        if (ctxNode->nodeType == ATTRIBUTE_NODE) {
4214            node = ((domAttrNode *)ctxNode)->parentNode->firstChild;
4215        } else {
4216            node = ctxNode;
4217            if (node->nextSibling) {
4218                node = node->nextSibling;
4219            } else {
4220                while (node->parentNode) {
4221                    node = node->parentNode;
4222                    if (node->nextSibling) break;
4223                }
4224                if (!node->nextSibling) return XPATH_OK;
4225                else node = node->nextSibling;
4226            }
4227        }
4228        while (1) {
4229            if (xpathNodeTest (node, step)) {
4230                checkRsAddNode (result, node);
4231                if (step->intvalue) {
4232                    count++;
4233                    if (count >= step->intvalue) break;
4234                }
4235            }
4236            if (node->nodeType == ELEMENT_NODE &&
4237                node->firstChild) {
4238                node = node->firstChild;
4239            } else
4240            if (node->nextSibling) {
4241                node = node->nextSibling;
4242            } else {
4243                while (node->parentNode) {
4244                    node = node->parentNode;
4245                    if (node->nextSibling) break;
4246                }
4247                if (!node->nextSibling) break;
4248                node = node->nextSibling;
4249            }
4250        }
4251        break;
4252
4253    case AxisPreceding:
4254        *docOrder = 0;
4255        if (ctxNode->nodeType == ATTRIBUTE_NODE) {
4256            ancestor = node = ((domAttrNode *)ctxNode)->parentNode;
4257        } else {
4258            ancestor = node = ctxNode;
4259        }
4260        i = 0;
4261        while (node->parentNode) {
4262            ancestor = node;
4263            node = node->parentNode;
4264            i++;
4265        }
4266        startingNode = node->firstChild;
4267        for (; i > 0; i--) {
4268            if (!startingNode)
4269                continue;
4270            if (startingNode->nodeType == ELEMENT_NODE) {
4271                node = startingNode->firstChild;
4272            } else {
4273                node = NULL;
4274            }
4275            while (startingNode != ancestor) {
4276                if (xpathNodeTest(startingNode, step)) {
4277                    checkRsAddNode(result, startingNode);
4278                }
4279                while ((node) && (node != startingNode)) {
4280                   if (xpathNodeTest(node, step)) {
4281                       checkRsAddNode(result, node);
4282                   }
4283                   if ((node->nodeType == ELEMENT_NODE) &&
4284                       (node->firstChild)) {
4285                       node = node->firstChild;
4286                       continue;
4287                   }
4288                   if (node->nextSibling) {
4289                       node = node->nextSibling;
4290                       continue;
4291                   }
4292                   while ((node->parentNode != startingNode) &&
4293                          (node->parentNode->nextSibling == NULL)) {
4294
4295                       node = node->parentNode;
4296                   }
4297                   if (node->parentNode != startingNode) {
4298                       node = node->parentNode->nextSibling;
4299                   } else {
4300                       break;
4301                   }
4302                }
4303                startingNode = startingNode->nextSibling;
4304                if (startingNode->nodeType == ELEMENT_NODE) {
4305                    node = startingNode->firstChild;
4306                } else {
4307                    node = NULL;
4308                }
4309            }
4310            if (ctxNode->nodeType == ATTRIBUTE_NODE) {
4311                node = ((domAttrNode *)ctxNode)->parentNode;
4312            } else {
4313                node = ctxNode;
4314            }
4315            for (j = 0; j < i - 1 ; j++) {
4316                ancestor = node;
4317                node = node->parentNode;
4318            }
4319            if (node->nodeType == ELEMENT_NODE) {
4320                startingNode = node->firstChild;
4321            } else {
4322                startingNode = NULL;
4323            }
4324        }
4325        break;
4326
4327    case AxisNamespace:
4328        *docOrder = 1;
4329        /* XPath rec 2.2: "the namespace axis contains the namespace
4330         * nodes of the context node; the axis will be empty unless
4331         * the context node is an element */
4332        if (ctxNode->nodeType != ELEMENT_NODE) {
4333            return XPATH_OK;
4334        }
4335        node = ctxNode;
4336
4337        while (node) {
4338            attr = node->firstAttr;
4339            while (attr && (attr->nodeFlags & IS_NS_NODE)) {
4340                if (step->child->type == IsElement) {
4341                    if ((step->child->strvalue[0] != '*')) {
4342                        if (strcmp(attr->nodeValue,
4343                                   step->child->strvalue)!=0) {
4344                            attr = attr->nextSibling;
4345                            continue;
4346                        }
4347                    }
4348                }
4349                rc = 0;
4350                for (i = 0; i < result->nr_nodes; i++) {
4351                    if (strcmp (attr->nodeName, ((domAttrNode*)result->nodes[i])->nodeName)==0) {
4352                        rc = 1; break;
4353                    }
4354                }
4355                if (rc) {attr = attr->nextSibling; continue;}
4356                rsAddNodeFast (result, (domNode *)attr);
4357                attr = attr->nextSibling;
4358            }
4359
4360            if (node == node->ownerDocument->documentElement) {
4361                if (ctxNode != ctxNode->ownerDocument->rootNode) {
4362                    node = ctxNode->ownerDocument->rootNode;
4363                } else {
4364                    node = NULL;
4365                }
4366            } else {
4367                node = node->parentNode;
4368            }
4369        }
4370        break;
4371
4372    case GetFQVar:
4373    case GetVar:
4374        if (cbs->varCB) {
4375            if (step->type == GetFQVar) {
4376                leftStr  = step->child->strvalue;
4377                rightStr = step->strvalue;
4378            } else {
4379                leftStr  = step->strvalue;
4380                rightStr = NULL;
4381            }
4382            rc = (cbs->varCB)(cbs->varClientData, leftStr, rightStr, result,
4383                              errMsg);
4384            CHECK_RC;
4385        }
4386        break;
4387
4388    case Literal:
4389        rsSetString (result, step->strvalue);
4390        break;
4391
4392    case Int:
4393        rsSetInt (result, step->intvalue);
4394        break;
4395
4396    case Real:
4397        rsSetReal (result, step->realvalue);
4398        break;
4399
4400    case Add:
4401    case Substract:
4402    case Mult:
4403    case Div:
4404    case Mod:
4405        xpathRSInit (&leftResult);
4406        xpathRSInit (&rightResult);
4407
4408        savedDocOrder = *docOrder;
4409        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
4410                            nodeList, cbs, &leftResult, docOrder, errMsg);
4411        CHECK_RC;
4412        DBG( fprintf(stderr,"left:\n");
4413             rsPrint(&leftResult);
4414        )
4415
4416        *docOrder = savedDocOrder;
4417        rc = xpathEvalStep( step->child->next, ctxNode, exprContext,  position,
4418                            nodeList, cbs, &rightResult, docOrder, errMsg);
4419        CHECK_RC;
4420        *docOrder = savedDocOrder;
4421
4422        DBG( fprintf(stderr,"right:\n");
4423             rsPrint(&rightResult);
4424        )
4425        if ((&leftResult)->type == RealResult) {
4426            dLeft = (&leftResult)->realvalue;
4427            NaN = 0;
4428            if (IS_NAN(dLeft)) NaN = 2;
4429            else if (IS_INF(dLeft)!=0) NaN = IS_INF(dLeft);
4430        } else {
4431            dLeft  = xpathFuncNumber(&leftResult, &NaN);
4432        }
4433        if ((&rightResult)->type == RealResult) {
4434            dRight = (&rightResult)->realvalue;
4435            NaN1 = 0;
4436            if (IS_NAN(dRight)) NaN1= 2;
4437            else if (IS_INF(dRight) !=0) NaN1 = IS_INF(dRight);
4438        } else {
4439            dRight = xpathFuncNumber(&rightResult, &NaN1);
4440        }
4441        if (NaN || NaN1) {
4442            if ((NaN == 2) || (NaN1 == 2)) {
4443                rsSetNaN (result);
4444            } else {
4445                switch (step->type) {
4446                case Substract:
4447                    NaN1 = -1 * NaN1;
4448                    /* fall throu */
4449                case Add:
4450                    if (NaN == NaN1) {
4451                        if (NaN == 1) rsSetInf (result);
4452                        else          rsSetNInf (result);
4453                    } else if ((rc = NaN + NaN1) != 0) {
4454                        if (rc == 1)  rsSetInf (result);
4455                        else          rsSetNInf (result);
4456                    } else {
4457                        rsSetNaN (result);
4458                    }
4459                    break;
4460                case Mult:
4461                    if ((dLeft == 0.0) || (dRight == 0.0)) rsSetNaN (result);
4462                    else if (NaN && NaN1) {
4463                        rc = NaN * NaN1;
4464                        if (rc == 1)  rsSetInf (result);
4465                        else          rsSetNInf (result);
4466                    } else {
4467                        if (NaN) dTmp = NaN * dRight;
4468                        else     dTmp = NaN1 * dLeft;
4469                        if (dTmp > 0.0)  rsSetInf (result);
4470                        else             rsSetNInf (result);
4471                    }
4472                    break;
4473                case Div:
4474                    if (NaN && NaN1)   rsSetNaN (result);
4475                    else if (NaN1)     rsSetInt (result, 0);
4476                    else {
4477                        if (dRight == 0.0) dTmp = NaN;
4478                        else dTmp = NaN * dRight;
4479                        if (dTmp > 0.0)  rsSetInf (result);
4480                        else             rsSetNInf (result);
4481                    }
4482                    break;
4483                case Mod:
4484                    rsSetNaN (result);
4485                    break;
4486                default: break;
4487                }
4488            }
4489            xpathRSFree (&rightResult);
4490            xpathRSFree (&leftResult);
4491            return XPATH_OK;
4492        }
4493        switch (step->type) {
4494        case Add:       rsSetReal (result, dLeft + dRight); break;
4495        case Substract: rsSetReal (result, dLeft - dRight); break;
4496        case Mult:      rsSetReal (result, dLeft * dRight); break;
4497        case Div:
4498            if (dRight == 0.0) {
4499                if (dLeft == 0.0) {
4500                    rsSetNaN (result);
4501                } else {
4502                    if (dLeft > 0) {
4503                        rsSetInf (result);
4504                    } else {
4505                        rsSetNInf (result);
4506                    }
4507                }
4508            } else {
4509                rsSetReal (result, dLeft / dRight);
4510            }
4511            break;
4512        case Mod:
4513            if (dRight == 0.0) {
4514                rsSetNaN (result);
4515            } else {
4516                rsSetInt  (result, ((int)dLeft) % ((int)dRight));
4517            }
4518            break;
4519        default:        break;
4520        }
4521        xpathRSFree (&rightResult);
4522        xpathRSFree (&leftResult);
4523        return XPATH_OK;
4524
4525    case CombineSets:
4526        xpathRSInit (&leftResult);
4527        xpathRSInit (&rightResult);
4528
4529        savedDocOrder = *docOrder;
4530        rc = xpathEvalStep (step->child, ctxNode, exprContext, position,
4531                            nodeList, cbs, &leftResult, docOrder, errMsg);
4532        CHECK_RC;
4533        DBG( fprintf(stderr,"left:\n");
4534             rsPrint(&leftResult);
4535        )
4536
4537        *docOrder = savedDocOrder;
4538        rc = xpathEvalStep( step->child->next, ctxNode, exprContext,  position,
4539                            nodeList, cbs, &rightResult, docOrder, errMsg);
4540        CHECK_RC;
4541        *docOrder = savedDocOrder;
4542
4543        DBG( fprintf(stderr,"right:\n");
4544             rsPrint(&rightResult);
4545        )
4546
4547        if (((leftResult.type != xNodeSetResult)
4548             && (leftResult.type != EmptyResult))
4549            ||
4550            ((rightResult.type != xNodeSetResult)
4551             && (rightResult.type != EmptyResult)))
4552        {
4553            *errMsg = tdomstrdup("| requires node sets!");
4554            xpathRSFree (&rightResult);
4555            xpathRSFree (&leftResult);
4556            return XPATH_EVAL_ERR;
4557        }
4558        if (leftResult.type == EmptyResult) {
4559            rsCopy (result, &rightResult);
4560            goto combineSetCleanup;
4561        }
4562        if (rightResult.type == EmptyResult) {
4563            rsCopy (result, &leftResult);
4564            goto combineSetCleanup;
4565        }
4566        *docOrder = 1;
4567        j = k = 0;
4568        for (i=0; i<(leftResult.nr_nodes+rightResult.nr_nodes); i++) {
4569            if (leftResult.nodes[j] == rightResult.nodes[k]) {
4570                rsAddNodeFast (result, leftResult.nodes[j]);
4571                j++; k++;
4572                if (j == leftResult.nr_nodes) break;
4573                if (k == rightResult.nr_nodes) break;
4574                i++;
4575                continue;
4576            }
4577            if (domPrecedes (leftResult.nodes[j], rightResult.nodes[k])) {
4578                rsAddNodeFast (result, leftResult.nodes[j]);
4579                j++;
4580                if (j == leftResult.nr_nodes) break;
4581            } else {
4582                rsAddNodeFast (result, rightResult.nodes[k]);
4583                k++;
4584                if (k == rightResult.nr_nodes) break;
4585            }
4586        }
4587
4588        if (j < leftResult.nr_nodes) {
4589            for (i=j; i< leftResult.nr_nodes; i++) {
4590                rsAddNodeFast ( result, leftResult.nodes[i]);
4591            }
4592        } else {
4593            for (i=k; i< rightResult.nr_nodes; i++) {
4594                rsAddNodeFast ( result, rightResult.nodes[i]);
4595            }
4596        }
4597    combineSetCleanup:
4598        xpathRSFree (&rightResult);
4599        xpathRSFree (&leftResult);
4600        return XPATH_OK;
4601
4602    case And:
4603    case Or:
4604    case Equal:
4605    case NotEqual:
4606        xpathRSInit (&leftResult);
4607        xpathRSInit (&rightResult);
4608
4609        savedDocOrder = *docOrder;
4610        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
4611                            nodeList, cbs, &leftResult, docOrder, errMsg);
4612        CHECK_RC;
4613        *docOrder = savedDocOrder;
4614
4615        DBG( fprintf(stderr,"left:\n");
4616             rsPrint(&leftResult);
4617        )
4618
4619        /*----------------------------------------------
4620        |   short circuit evalution for AND/OR
4621        \---------------------------------------------*/
4622        if (step->type == And) {
4623            left = xpathFuncBoolean(&leftResult);
4624            if (!left) {
4625                /* left result is false, so AND result is also false */
4626                rsSetBool (result, left);
4627                xpathRSFree (&leftResult);
4628                return XPATH_OK;
4629            }
4630        }
4631        if (step->type == Or) {
4632            left = xpathFuncBoolean(&leftResult);
4633            if (left) {
4634                /* left result is true, so OR result is also true */
4635                rsSetBool (result, left);
4636                xpathRSFree (&leftResult);
4637                return XPATH_OK;
4638            }
4639        }
4640
4641        rc = xpathEvalStep( step->child->next, ctxNode, exprContext,  position,
4642                            nodeList, cbs, &rightResult, docOrder, errMsg);
4643        CHECK_RC;
4644        *docOrder = savedDocOrder;
4645
4646        DBG( fprintf(stderr,"right:\n");
4647             rsPrint(&rightResult);
4648        )
4649        res = 0;
4650        if ((step->type == And) || (step->type == Or)) {
4651            right = xpathFuncBoolean(&rightResult);
4652            if (step->type == And) res = (left && right);
4653            if (step->type == Or) res = (left || right);
4654            rsSetBool (result, res);
4655            xpathRSFree (&rightResult);
4656            xpathRSFree (&leftResult);
4657            return XPATH_OK;
4658        }
4659
4660        if (   leftResult.type == xNodeSetResult
4661            || rightResult.type == xNodeSetResult) {
4662            if (leftResult.type == xNodeSetResult) {
4663                pleftResult = &leftResult;
4664                prightResult = &rightResult;
4665            } else {
4666                pleftResult = &rightResult;
4667                prightResult = &leftResult;
4668            }
4669            switch (prightResult->type) {
4670            case EmptyResult:
4671                res = 0;
4672                break;
4673            case xNodeSetResult:
4674                JDBG( fprintf(stderr,"\nleft+right result:\n");
4675                     rsPrint(pleftResult);
4676                     rsPrint(prightResult);
4677                )
4678                for (i=0; i < pleftResult->nr_nodes; i++) {
4679                    leftStr = xpathFuncStringForNode (pleftResult->nodes[i]);
4680                    for (j=0; j < prightResult->nr_nodes; j++) {
4681                        rightStr = xpathFuncStringForNode (prightResult->nodes[j]);
4682                        JDBG(fprintf(stderr, "leftStr='%s' rightStr='%s'\n", leftStr, rightStr);)
4683                        res = strcmp (leftStr, rightStr);
4684                        if      (step->type == Equal)    res = (res==0);
4685                        else if (step->type == NotEqual) res = (res!=0);
4686                        FREE(rightStr);
4687                        if (res) break;
4688                    }
4689                    FREE(leftStr);
4690                    if (res) break;
4691                }
4692                break;
4693            case BoolResult:
4694                if (step->type == Equal) res = (prightResult->intvalue != 0);
4695                else                     res = (prightResult->intvalue == 0);
4696                break;
4697            case IntResult:
4698            case RealResult:
4699                dRight = xpathFuncNumber (prightResult, &NaN);
4700                if (NaN) {
4701                    /* The real value of a node could never be inf/-inf */
4702                    /* And NaN is always != NaN (and != everything else) */
4703                    if (step->type == Equal) res = 0;
4704                    else                     res = 1;
4705                    break;
4706                }
4707                for (i=0; i < pleftResult->nr_nodes; i++) {
4708                    dLeft = xpathFuncNumberForNode (pleftResult->nodes[i], &NaN);
4709                    if (NaN) continue;
4710                    if (step->type == Equal) res = (dLeft == dRight);
4711                    else                     res = (dLeft != dRight);
4712                    if (res) break;
4713                }
4714                break;
4715            case NaNResult:
4716            case InfResult:
4717            case NInfResult:
4718                res = 0;
4719                break;
4720            case StringResult:
4721                rightStr = xpathFuncString (prightResult);
4722                for (i=0; i < pleftResult->nr_nodes; i++) {
4723                    leftStr = xpathFuncStringForNode (pleftResult->nodes[i]);
4724                    res = strcmp (leftStr, rightStr);
4725                    if (step->type == Equal) res = (res == 0);
4726                    else                     res = (res != 0);
4727                    FREE(leftStr);
4728                    if (res) break;
4729                }
4730                FREE(rightStr);
4731                break;
4732            }
4733        } else
4734        if (leftResult.type == BoolResult || rightResult.type == BoolResult) {
4735            left  = xpathFuncBoolean (&leftResult);
4736            right = xpathFuncBoolean (&rightResult);
4737            if (step->type == Equal) res = (left == right);
4738            else                     res = (left != right);
4739        } else
4740        if (
4741               leftResult.type  == IntResult
4742            || leftResult.type  == RealResult
4743            || rightResult.type == IntResult
4744            || rightResult.type == RealResult
4745            || rightResult.type == NaNResult
4746            || rightResult.type == InfResult
4747            || rightResult.type == NInfResult
4748            || leftResult.type  == NaNResult
4749            || leftResult.type  == InfResult
4750            || leftResult.type  == NInfResult
4751            ) {
4752            if (   leftResult.type == EmptyResult
4753                || rightResult.type == EmptyResult) {
4754                res = 0;
4755            } else {
4756                dLeft  = xpathFuncNumber (&leftResult, &NaN);
4757                dRight = xpathFuncNumber (&rightResult, &NaN1);
4758                if (NaN || NaN1) {
4759                    if (NaN == NaN1) {
4760                        if (NaN != 2) {
4761                            if (step->type == Equal) res = 1;
4762                        } else {
4763                            if (step->type == NotEqual) res = 1;
4764                        }
4765                    } else {
4766                        if (step->type == NotEqual) res = 1;
4767                    }
4768                } else {
4769                    if (step->type == Equal) res = (dLeft == dRight);
4770                    else                     res = (dLeft != dRight);
4771                }
4772            }
4773        } else {
4774            if (   leftResult.type == EmptyResult
4775                || rightResult.type == EmptyResult) {
4776                res = 0;
4777            } else {
4778                leftStr  = xpathFuncString (&leftResult);
4779                rightStr = xpathFuncString (&rightResult);
4780                res = strcmp (leftStr, rightStr);
4781                if (step->type == Equal) res = (res == 0);
4782                else                     res = (res != 0);
4783                FREE(leftStr);
4784                FREE(rightStr);
4785            }
4786        }
4787        rsSetBool (result, res);
4788        xpathRSFree (&rightResult);
4789        xpathRSFree (&leftResult);
4790        return XPATH_OK;
4791
4792    case Less:
4793    case LessOrEq:
4794    case Greater:
4795    case GreaterOrEq:
4796        xpathRSInit (&leftResult);
4797        xpathRSInit (&rightResult);
4798
4799        savedDocOrder = *docOrder;
4800        rc = xpathEvalStep( step->child, ctxNode, exprContext, position,
4801                            nodeList, cbs, &leftResult, docOrder, errMsg);
4802        CHECK_RC;
4803        *docOrder = savedDocOrder;
4804
4805        DBG( fprintf(stderr,"left:\n");
4806             rsPrint(&leftResult);
4807        )
4808        rc = xpathEvalStep( step->child->next, ctxNode, exprContext, position,
4809                            nodeList, cbs, &rightResult, docOrder, errMsg);
4810        CHECK_RC;
4811        *docOrder = savedDocOrder;
4812
4813        DBG( fprintf(stderr,"right:\n");
4814             rsPrint(&rightResult);
4815        )
4816        res = 0;
4817
4818        if (   leftResult.type == xNodeSetResult
4819            || rightResult.type == xNodeSetResult) {
4820            if (leftResult.type == xNodeSetResult) {
4821                pleftResult = &leftResult;
4822                prightResult = &rightResult;
4823                switchResult = 0;
4824            } else {
4825                pleftResult = &rightResult;
4826                prightResult = &leftResult;
4827                switchResult = 1;
4828            }
4829            switch (prightResult->type) {
4830            case EmptyResult:
4831                res = 0;
4832                break;
4833            case xNodeSetResult:
4834                JDBG( fprintf(stderr,"\nleft+right result:\n");
4835                     rsPrint(pleftResult);
4836                     rsPrint(prightResult);
4837                )
4838                for (i=0; i < pleftResult->nr_nodes; i++) {
4839                    dLeft = xpathFuncNumberForNode (pleftResult->nodes[i], &NaN);
4840                    if (NaN) continue;
4841                    for (j=0; j < prightResult->nr_nodes; j++) {
4842                        dRight = xpathFuncNumberForNode (prightResult->nodes[j], &NaN);
4843                        if (NaN)  continue;
4844                        if (switchResult) {
4845                            dTmp   = dLeft;
4846                            dLeft  = dRight;
4847                            dRight = dTmp;
4848                        }
4849                        if      (step->type == Less)     res = (dLeft < dRight);
4850                        else if (step->type == LessOrEq) res = (dLeft <= dRight);
4851                        else if (step->type == Greater)  res = (dLeft >  dRight);
4852                        else                             res = (dLeft >= dRight);
4853
4854                        if (res) break;
4855                    }
4856                    if (res) break;
4857                }
4858                break;
4859            case BoolResult:
4860                /* pleftResult is a non-emtpy nodeset, therefor: */
4861                dLeft = 1.0;
4862                dRight = xpathFuncNumber (prightResult, &NaN);
4863                if (NaN) break;
4864                if      (step->type == Less)     res = (dLeft < dRight);
4865                else if (step->type == LessOrEq) res = (dLeft <= dRight);
4866                else if (step->type == Greater)  res = (dLeft >  dRight);
4867                else                             res = (dLeft >= dRight);
4868
4869                if (switchResult) {
4870                    res = !res;
4871                }
4872                break;
4873            case NaNResult:
4874                break;
4875            case InfResult:
4876            case NInfResult:
4877            case IntResult:
4878            case RealResult:
4879            case StringResult:
4880                dRight = xpathFuncNumber (prightResult, &NaN);
4881                if (NaN) {
4882                    if (NaN == 2) break;
4883#ifdef DBL_MAX
4884                    if (NaN == 1) dRight = DBL_MAX;
4885                    else          dRight = -DBL_MAX;
4886#endif
4887                }
4888                for (i=0; i < pleftResult->nr_nodes; i++) {
4889                    dLeft = xpathFuncNumberForNode (pleftResult->nodes[i], &NaN);
4890                    if (NaN) continue;
4891                    if (switchResult) {
4892                        dTmp   = dLeft;
4893                        dLeft  = dRight;
4894                        dRight = dTmp;
4895                    }
4896                    if      (step->type == Less)     res = (dLeft < dRight);
4897                    else if (step->type == LessOrEq) res = (dLeft <= dRight);
4898                    else if (step->type == Greater)  res = (dLeft >  dRight);
4899                    else                             res = (dLeft >= dRight);
4900
4901                    if (res) break;
4902                }
4903                break;
4904            }
4905        } else {
4906            if (   leftResult.type == EmptyResult
4907                || rightResult.type == EmptyResult) {
4908                res = 0;
4909            } else {
4910                dLeft  = xpathFuncNumber (&leftResult, &NaN);
4911                if (NaN) {
4912                    if (NaN == 2) goto compareFinish;
4913#ifdef DBL_MAX
4914                    if (NaN == 1) dLeft = DBL_MAX;
4915                    else          dLeft = -DBL_MAX;
4916#endif
4917                }
4918                dRight = xpathFuncNumber (&rightResult, &NaN);
4919                if (NaN) {
4920                    if (NaN == 2) goto compareFinish;
4921#ifdef DBL_MAX
4922                    if (NaN == 1) dRight = DBL_MAX;
4923                    else          dRight = -DBL_MAX;
4924#endif
4925                }
4926                if      (step->type == Less)     res = (dLeft < dRight);
4927                else if (step->type == LessOrEq) res = (dLeft <= dRight);
4928                else if (step->type == Greater)  res = (dLeft >  dRight);
4929                else                             res = (dLeft >= dRight);
4930            }
4931        }
4932    compareFinish:
4933        rsSetBool (result, res);
4934        xpathRSFree (&rightResult);
4935        xpathRSFree (&leftResult);
4936        return XPATH_OK;
4937
4938    case SelectRoot:
4939        if (ctxNode->nodeType == ATTRIBUTE_NODE) {
4940            node = ((domAttrNode *)ctxNode)->parentNode;
4941            checkRsAddNode(result, node->ownerDocument->rootNode);
4942        } else {
4943            checkRsAddNode(result, ctxNode->ownerDocument->rootNode);
4944        }
4945        break;
4946
4947    case UnaryMinus:
4948        xpathRSInit (&leftResult);
4949        rc = xpathEvalSteps (step->child, nodeList, ctxNode, exprContext,
4950                             position, docOrder,cbs, &leftResult, errMsg);
4951        CHECK_RC;
4952        dLeft = xpathFuncNumber (&leftResult, &NaN);
4953        if (NaN) {
4954            if (NaN == 2)      rsSetNaN (result);
4955            else if (NaN == 1) rsSetNInf (result);
4956            else               rsSetInf (result);
4957        } else rsSetReal (result , -1 * dLeft);
4958        xpathRSFree (&leftResult);
4959        break;
4960
4961    case EvalSteps:
4962        rc = xpathEvalSteps (step->child, nodeList, ctxNode, exprContext,
4963                             position, docOrder,cbs, &leftResult, errMsg);
4964        CHECK_RC;
4965        if ((result->type != EmptyResult) && (leftResult.type != result->type)) {
4966            DBG( fprintf (stderr, "EvalSteps:\nresult:\n");
4967            rsPrint (result);
4968            fprintf (stderr, "leftResult:\n");
4969            rsPrint (&leftResult); )
4970            *errMsg = tdomstrdup("can not merge different result types!");
4971            return XPATH_EVAL_ERR;
4972        }
4973        switch (leftResult.type) {
4974            case xNodeSetResult:
4975                for (i=0; i<leftResult.nr_nodes; i++) {
4976                    DBG(fprintf(stderr, "EvalSteps: adding %d \n", i);)
4977                    checkRsAddNode (result, leftResult.nodes[i]);
4978                }
4979                break;
4980            case BoolResult:   rsSetBool(result, leftResult.intvalue);
4981                               break;
4982            case IntResult:    rsSetInt(result, leftResult.intvalue);
4983                               break;
4984            case RealResult:   rsSetReal(result, leftResult.realvalue);
4985                               break;
4986            case StringResult: rsSetString (result, leftResult.string);
4987                               break;
4988            case NaNResult:    rsSetNaN (result); break;
4989            case InfResult:    rsSetInf (result); break;
4990            case NInfResult:   rsSetNInf (result); break;
4991            default:           break;
4992        }
4993        xpathRSFree( &leftResult  );
4994        break;
4995
4996    case ExecFunction:
4997    case ExecIdKey:
4998        rc = xpathEvalFunction (step, ctxNode, exprContext, position, nodeList,
4999                                cbs, result, docOrder, errMsg);
5000        CHECK_RC;
5001        break;
5002    default:
5003        fprintf (stderr, "!! xpathEvalStep: not handled switch %s !!\n", astType2str[step->type]);
5004        return XPATH_EVAL_ERR;
5005    }
5006    return XPATH_OK;
5007
5008} /* xpathEvalStep */
5009
5010/*----------------------------------------------------------------------------
5011|   xpathEvalPredicate
5012|
5013\---------------------------------------------------------------------------*/
5014static int xpathEvalPredicate (
5015    ast                step,
5016    domNode           *exprContext,
5017    xpathResultSet    *result,
5018    xpathResultSet    *stepResult,
5019    xpathCBs          *cbs,
5020    int               *docOrder,
5021    char              **errMsg
5022)
5023{
5024    xpathResultSet predResult, tmpResult;
5025    int            i, rc, savedDocOrder, useFastAdd;
5026
5027    if (result->nr_nodes == 0) useFastAdd = 1;
5028    else useFastAdd = 0;
5029    savedDocOrder = *docOrder;
5030    while (step && step->type == Pred) {
5031        xpathRSInit (&tmpResult);
5032        if (step->child->type == Int) {
5033            if (stepResult->nr_nodes >= step->child->intvalue
5034                && step->child->intvalue > 0) {
5035                if (*docOrder) {
5036                    rsAddNode (&tmpResult,
5037                               stepResult->nodes[step->child->intvalue - 1]);
5038                } else {
5039                    rsAddNode (&tmpResult,
5040                               stepResult->nodes[stepResult->nr_nodes -
5041                                                 step->child->intvalue]);
5042                }
5043            }
5044            goto nextPred;
5045        }
5046        for (i=0; i<stepResult->nr_nodes; i++) {
5047            xpathRSInit (&predResult);
5048            rc = xpathEvalStep( step->child, stepResult->nodes[i],
5049                                exprContext, i, stepResult, cbs, &predResult,
5050                                docOrder, errMsg);
5051            CHECK_RC;
5052            *docOrder = savedDocOrder;
5053            DBG( fprintf(stderr, "after eval for Predicate: \n"); )
5054            DBG( rsPrint( &predResult); )
5055
5056            if (predResult.type == RealResult) {
5057                predResult.type = IntResult;
5058                predResult.intvalue = xpathRound(predResult.realvalue);
5059            }
5060            if (predResult.type == IntResult) {
5061                if (predResult.intvalue < 0) {
5062                    predResult.intvalue =
5063                        stepResult->nr_nodes + predResult.intvalue;
5064                }
5065                if (savedDocOrder) {
5066                    if (predResult.intvalue == (i+1)) {
5067                        rsAddNodeFast (&tmpResult, stepResult->nodes[i]);
5068                    }
5069                } else {
5070                    if (predResult.intvalue == (stepResult->nr_nodes - i)){
5071                        rsAddNodeFast (&tmpResult, stepResult->nodes[i]);
5072                    }
5073                }
5074            } else if (xpathFuncBoolean(&predResult)) {
5075                rsAddNodeFast (&tmpResult, stepResult->nodes[i]);
5076            }
5077            xpathRSFree (&predResult);
5078        }
5079    nextPred:
5080        DBG( fprintf(stderr, "result after Predicate: \n"); )
5081        DBG( rsPrint( &tmpResult); )
5082        xpathRSFree( stepResult );
5083        *stepResult = tmpResult;
5084        step = step->next;
5085    }
5086
5087    /* add remaining result set to overall result set */
5088    for (i=0; i<stepResult->nr_nodes; i++) {
5089        checkRsAddNode (result, stepResult->nodes[i]);
5090    }
5091
5092    return 0;
5093}
5094
5095
5096/*----------------------------------------------------------------------------
5097|   xpathEvalStepAndPredicates
5098|
5099\---------------------------------------------------------------------------*/
5100static int xpathEvalStepAndPredicates (
5101    ast                steps,
5102    xpathResultSet    *nodeList,
5103    domNode           *currentNode,
5104    domNode           *exprContext,
5105    int                currentPos,
5106    int               *docOrder,
5107    xpathCBs          *cbs,
5108    xpathResultSet    *result,
5109    char              **errMsg
5110)
5111{
5112    xpathResultSet  stepResult;
5113    int             rc;
5114
5115
5116    /* For AxisDescendantOrSelf/AxisDescendant, the predicate filtering
5117       is already done 'inlined' during xpathEvalStep, to do the filtering
5118       "with respect to the child axis" (XPath rec. 3.3) in an efficienter
5119       way, then up to now. */
5120    if (   steps->next
5121        && steps->next->type == Pred
5122        && steps->type != AxisDescendantOrSelf
5123        && steps->type != AxisDescendant) {
5124        xpathRSInit (&stepResult);
5125        rc = xpathEvalStep( steps, currentNode, exprContext, currentPos,
5126                            nodeList, cbs, &stepResult, docOrder, errMsg);
5127        if (rc) {
5128            xpathRSFree (&stepResult);
5129            return rc;
5130        }
5131        rc = xpathEvalPredicate (steps->next, exprContext, result, &stepResult,
5132                                 cbs, docOrder, errMsg);
5133        xpathRSFree (&stepResult);
5134        CHECK_RC;
5135    } else {
5136        /* for steps not followed by a predicate immediately add to
5137           the final result set */
5138        rc = xpathEvalStep( steps, currentNode, exprContext, currentPos, nodeList,
5139                            cbs, result, docOrder, errMsg);
5140        CHECK_RC;
5141        DBG( rsPrint( result); )
5142    }
5143    return 0;
5144}
5145
5146
5147/*----------------------------------------------------------------------------
5148|   xpathEvalSteps
5149|
5150\---------------------------------------------------------------------------*/
5151int xpathEvalSteps (
5152    ast                steps,
5153    xpathResultSet    *nodeList,
5154    domNode           *currentNode,
5155    domNode           *exprContext,
5156    int                currentPos,
5157    int               *docOrder,
5158    xpathCBs          *cbs,
5159    xpathResultSet    *result,
5160    char              **errMsg
5161)
5162{
5163    int i, rc, first = 1;
5164    xpathResultSet savedContext;
5165
5166    DBG (fprintf (stderr, "xpathEvalSteps start\n");)
5167    savedContext = *nodeList;
5168    xpathRSInit (result);
5169    while (steps) {
5170        DBG (fprintf (stderr, "xpathEvalSteps: eval step '%s'\n",
5171                      astType2str[steps->type]);)
5172        if (steps->type == Pred) {
5173            *errMsg = "Pred step not expected now!";
5174            return XPATH_EVAL_ERR;
5175        }
5176        if (first) {
5177            rc = xpathEvalStepAndPredicates (steps, nodeList, currentNode,
5178                                             exprContext, currentPos, docOrder,
5179                                             cbs, result, errMsg);
5180            CHECK_RC;
5181            first = 0;
5182        } else {
5183            DBG( fprintf(stderr, "doing location step nodeList->nr_nodes=%d \n",
5184                                 nodeList->nr_nodes);
5185            )
5186            if (result->type != xNodeSetResult) {
5187                xpathRSFree (result);
5188                xpathRSInit (result);
5189                *nodeList = savedContext;
5190                return 0;
5191            }
5192
5193            *nodeList = *result;
5194            xpathRSInit (result);
5195            for (i=0; i<nodeList->nr_nodes; i++) {
5196                rc = xpathEvalStepAndPredicates (steps, nodeList,
5197                                                 nodeList->nodes[i],
5198                                                 exprContext, i, docOrder, cbs,
5199                                                 result, errMsg);
5200                if (rc) {
5201                    xpathRSFree (result);
5202                    xpathRSFree (nodeList);
5203                    return rc;
5204                }
5205            }
5206            xpathRSFree (nodeList);
5207        }
5208        DBG( fprintf(stderr, "result after location step: \n"); )
5209        DBG( rsPrint( result); )
5210
5211        steps = steps->next;
5212        /* skip the already processed Predicate parts */
5213        while (steps && steps->type == Pred) steps = steps->next;
5214        *docOrder = 1;
5215    }
5216    *nodeList = savedContext;
5217    return 0;
5218}
5219
5220
5221/*----------------------------------------------------------------------------
5222|   xpathEval
5223|
5224\---------------------------------------------------------------------------*/
5225int xpathEval (
5226    domNode          * node,
5227    domNode          * exprContext,
5228    char             * xpath,
5229    char            ** prefixMappings,
5230    xpathCBs         * cbs,
5231    xpathParseVarCB  * parseVarCB,
5232    Tcl_HashTable    * cache,
5233    char            ** errMsg,
5234    xpathResultSet   * result
5235)
5236{
5237    xpathResultSet nodeList;
5238    int            rc, hnew = 1, docOrder = 1;
5239    ast            t;
5240    Tcl_HashEntry *h;
5241
5242    *errMsg = NULL;
5243    if (cache) {
5244        h = Tcl_CreateHashEntry (cache, xpath, &hnew);
5245    }
5246    if (hnew) {
5247        rc = xpathParse(xpath, exprContext, XPATH_EXPR, prefixMappings,
5248                        parseVarCB, &t, errMsg);
5249        CHECK_RC;
5250        if (cache) {
5251            Tcl_SetHashValue(h, t);
5252        }
5253    } else {
5254        t = (ast)Tcl_GetHashValue(h);
5255    }
5256
5257    xpathRSInit( &nodeList);
5258    rsAddNodeFast( &nodeList, node);
5259
5260    rc = xpathEvalSteps( t, &nodeList, node, exprContext, 0, &docOrder, cbs,
5261                         result, errMsg);
5262    if (!cache) {
5263        freeAst(t);
5264    }
5265    xpathRSFree( &nodeList );
5266    CHECK_RC;
5267
5268    DBG(rsPrint( result );)
5269    return 0;
5270
5271} /* xpathEval */
5272
5273/*----------------------------------------------------------------------------
5274|   xpathMatches
5275|
5276\---------------------------------------------------------------------------*/
5277int xpathMatches (
5278    ast                 step,
5279    domNode           * exprContext,
5280    domNode           * nodeToMatch,
5281    xpathCBs          * cbs,
5282    char             ** errMsg
5283)
5284{
5285    xpathResultSet  stepResult, nodeList, newNodeList;
5286    ast             childSteps;
5287    int             rc, i, j, currentPos = 0, nodeMatches, docOrder = 1;
5288    int             useFastAdd;
5289    const char     *localName = NULL, *nodeUri;
5290    domAttrNode    *attr;
5291    domNode        *child;
5292
5293    DBG(printAst(3,step));
5294    xpathRSInit (&nodeList);
5295    while (step) {
5296        TRACE1("xpathMatches type=%d \n", step->type);
5297        if (nodeList.nr_nodes == 0) useFastAdd = 1;
5298        else useFastAdd = 0;
5299        switch (step->type) {
5300
5301            case AxisAttribute:
5302                if (step->child->type != IsAttr && step->child->type != IsNSAttr) {
5303                    if (step->child->type == IsElement) {
5304                        step->child->type = IsAttr;
5305                    } else {
5306                        DBG(fprintf(stderr, "strange: AxisAttribute with no IsAttr below!\n");)
5307                        xpathRSFree (&nodeList); return 0;
5308                    }
5309                }
5310                attr = NULL;
5311                if (nodeToMatch->nodeType == ATTRIBUTE_NODE) {
5312                    rc = xpathMatches (step->child, exprContext, nodeToMatch, cbs,
5313                                       errMsg);
5314                    DBG(fprintf(stderr, "rc=%d attribute match\n", rc); )
5315                    if (rc != 1) { xpathRSFree (&nodeList); return 0; }
5316                    attr = (domAttrNode*) nodeToMatch;
5317                } else { xpathRSFree (&nodeList); return 0; }
5318                if (attr == NULL) { xpathRSFree (&nodeList); return 0; }
5319                break;
5320
5321            case AxisChild:
5322                if (step->child->type == IsElement) {
5323                    if (nodeToMatch->nodeType != ELEMENT_NODE) {
5324                        xpathRSFree (&nodeList); return 0;
5325                    }
5326                    if (nodeToMatch == nodeToMatch->ownerDocument->rootNode) {
5327                        xpathRSFree (&nodeList); return 0;
5328                    }
5329                    if ((step->child->strvalue[0] != '*') ||
5330                        (step->child->strvalue[1] != '\0'))
5331                    {
5332                        if (nodeToMatch->namespace) return 0;
5333                        if (strcmp(nodeToMatch->nodeName, step->child->strvalue)!=0) {
5334                            xpathRSFree (&nodeList); return 0;
5335                        }
5336                    }
5337                    break;
5338                }
5339                if (step->child->type == IsFQElement) {
5340                    if (nodeToMatch->nodeType != ELEMENT_NODE) {
5341                        xpathRSFree (&nodeList); return 0;
5342                    }
5343                    nodeUri = domNamespaceURI (nodeToMatch);
5344                    if (!nodeUri) { xpathRSFree (&nodeList); return 0; }
5345                    if (strcmp (step->child->strvalue, nodeUri) != 0) {
5346                        xpathRSFree (&nodeList); return 0;
5347                    }
5348                    localName = domGetLocalName (nodeToMatch->nodeName);
5349                    if (!localName) { xpathRSFree (&nodeList); return 0; }
5350                    if (strcmp (step->child->child->strvalue, localName)!=0) {
5351                        xpathRSFree (&nodeList); return 0;
5352                    }
5353                    break;
5354                }
5355                if (step->child->type == IsNSElement) {
5356                    nodeUri = domNamespaceURI (nodeToMatch);
5357                    if (!nodeUri) { xpathRSFree (&nodeList); return 0; }
5358                    if (strcmp (step->child->strvalue, nodeUri)!=0) {
5359                        xpathRSFree (&nodeList); return 0;
5360                    }
5361                    break;
5362                }
5363                DBG(fprintf(stderr, "strange: AxisChild with no IsElement, IsFQElement or IsNSElement below!\n");)
5364                return 0;
5365
5366            case IsElement:
5367                if (nodeToMatch->nodeType != ELEMENT_NODE) {
5368                    xpathRSFree (&nodeList); return 0;
5369                }
5370                if (nodeToMatch == nodeToMatch->ownerDocument->rootNode) {
5371                    xpathRSFree (&nodeList); return 0;
5372                }
5373                if ((step->strvalue[0] != '*') ||
5374                    (step->strvalue[1] != '\0'))
5375                {
5376                    if (nodeToMatch->namespace) return 0;
5377                    if (strcmp(nodeToMatch->nodeName, step->strvalue)!=0) {
5378                        xpathRSFree (&nodeList); return 0;
5379                    }
5380                }
5381                break;
5382
5383            case IsFQElement:
5384                if (nodeToMatch->nodeType != ELEMENT_NODE) {
5385                    xpathRSFree (&nodeList); return 0;
5386                }
5387                nodeUri = domNamespaceURI (nodeToMatch);
5388                if (!nodeUri) { xpathRSFree (&nodeList); return 0; }
5389                if (strcmp (step->strvalue, nodeUri) != 0) {
5390                    xpathRSFree (&nodeList); return 0;
5391                }
5392                localName = domGetLocalName (nodeToMatch->nodeName);
5393                if (!localName) { xpathRSFree (&nodeList); return 0; }
5394                if (strcmp (step->child->strvalue, localName)!=0)  {
5395                    xpathRSFree (&nodeList); return 0;
5396                }
5397                break;
5398
5399            case IsNSElement:
5400                nodeUri = domNamespaceURI (nodeToMatch);
5401                if (!nodeUri) { xpathRSFree (&nodeList); return 0; }
5402                if (strcmp (step->strvalue, nodeUri)!=0) {
5403                    xpathRSFree (&nodeList); return 0;
5404                }
5405                break;
5406
5407            case IsAttr:
5408                if ((nodeToMatch->nodeType != ATTRIBUTE_NODE)
5409                    || (nodeToMatch->nodeFlags & IS_NS_NODE)) {
5410                    xpathRSFree (&nodeList); return 0;
5411                }
5412                if (!((step->strvalue[0] == '*') && (step->strvalue[1] == '\0')))  {
5413                    if (strcmp( ((domAttrNode*)nodeToMatch)->nodeName, step->strvalue)!=0) {
5414                        xpathRSFree (&nodeList); return 0;
5415                    }
5416                }
5417                break;
5418
5419            case IsNSAttr:
5420                if ((nodeToMatch->nodeType != ATTRIBUTE_NODE)
5421                    || (nodeToMatch->nodeFlags & IS_NS_NODE)) {
5422                    xpathRSFree (&nodeList); return 0;
5423                }
5424                nodeUri = domNamespaceURI (nodeToMatch);
5425                if (!nodeUri) { xpathRSFree (&nodeList); return 0; }
5426                if (strcmp (step->strvalue, nodeUri) != 0) {
5427                    xpathRSFree (&nodeList); return 0;
5428                }
5429                if (strcmp (step->child->strvalue, "*")==0) break;
5430                localName = domGetLocalName (((domAttrNode *)nodeToMatch)->nodeName);
5431                if (!localName) { xpathRSFree (&nodeList); return 0; }
5432                if (strcmp (step->child->strvalue, localName)!=0)  {
5433                    xpathRSFree (&nodeList); return 0;
5434                }
5435                break;
5436
5437            case IsNode:
5438                DBG(fprintf(stderr, "IsNode: nodeTpye=%d \n", nodeToMatch->nodeType);)
5439                if (nodeToMatch->nodeType == ATTRIBUTE_NODE) {
5440                    xpathRSFree (&nodeList); return 0;
5441                }
5442                if ((nodeToMatch->nodeType == ELEMENT_NODE) &&
5443                    (nodeToMatch->ownerDocument->rootNode == nodeToMatch)) {
5444                    xpathRSFree (&nodeList); return 0;
5445                }
5446                break;
5447
5448            case IsText:
5449                if (nodeToMatch->nodeType != TEXT_NODE) {
5450                    xpathRSFree (&nodeList); return 0;
5451                }
5452                break;
5453
5454            case IsPI:
5455                if (nodeToMatch->nodeType != PROCESSING_INSTRUCTION_NODE) {
5456                    xpathRSFree (&nodeList); return 0;
5457                }
5458                break;
5459
5460            case IsSpecificPI:
5461                if (nodeToMatch->nodeType != PROCESSING_INSTRUCTION_NODE) {
5462                    xpathRSFree (&nodeList); return 0;
5463                }
5464                if (strncmp(((domProcessingInstructionNode*)nodeToMatch)->targetValue, step->strvalue, ((domProcessingInstructionNode*)nodeToMatch)->targetLength) != 0) {
5465                    xpathRSFree (&nodeList); return 0;
5466                }
5467                break;
5468
5469            case IsComment:
5470                if (nodeToMatch->nodeType != COMMENT_NODE) {
5471                    xpathRSFree (&nodeList); return 0;
5472                }
5473                break;
5474
5475            case IsRoot:
5476                if (nodeToMatch->nodeType == ATTRIBUTE_NODE) {
5477                    xpathRSFree (&nodeList); return 0;
5478                }
5479                if (nodeToMatch != nodeToMatch->ownerDocument->rootNode) {
5480                    xpathRSFree (&nodeList); return 0;
5481                }
5482                break;
5483
5484            case ToParent:
5485                if (nodeToMatch->nodeType == ATTRIBUTE_NODE) {
5486                    nodeToMatch = ((domAttrNode *)nodeToMatch)->parentNode;
5487                    break;
5488                }
5489                if (nodeToMatch == nodeToMatch->ownerDocument->rootNode) {
5490                    xpathRSFree (&nodeList); return 0;
5491                }
5492                if (nodeToMatch->parentNode) {
5493                    nodeToMatch = nodeToMatch->parentNode;
5494                } else {
5495                    nodeToMatch = nodeToMatch->ownerDocument->rootNode;
5496                }
5497                break;
5498
5499            case ToAncestors:
5500                if (step->next == NULL) { xpathRSFree (&nodeList); return 1;}
5501                while (1) {
5502                    if (nodeToMatch->nodeType == ATTRIBUTE_NODE) {
5503                        nodeToMatch = ((domAttrNode *)nodeToMatch)->parentNode;
5504                    } else {
5505                        if (nodeToMatch == nodeToMatch->ownerDocument->rootNode) {
5506                            xpathRSFree (&nodeList); return 0;
5507                        }
5508                        if (nodeToMatch->parentNode) {
5509                            nodeToMatch = nodeToMatch->parentNode;
5510                        } else {
5511                            nodeToMatch = nodeToMatch->ownerDocument->rootNode;
5512                        }
5513                    }
5514                    if (step->next == NULL) {
5515                        xpathRSFree (&nodeList); return 0;
5516                    }
5517                    rc = xpathMatches (step->next, exprContext, nodeToMatch,
5518                                       cbs, errMsg);
5519                    if (rc == 1) break;
5520                }
5521                break;
5522
5523            case FillWithCurrentNode:
5524                checkRsAddNode( &nodeList, nodeToMatch);
5525                currentPos = 0;
5526                DBG(
5527                  fprintf(stderr, "FillWithCurrentNode:\n");
5528                  rsPrint(&nodeList);
5529                )
5530                break;
5531
5532            case FillNodeList:
5533                if (nodeToMatch->nodeType == ATTRIBUTE_NODE) {
5534                    child = (domNode*)  ((domAttrNode*)nodeToMatch)->parentNode->firstAttr;
5535                    DBG(fprintf(stderr, "FillNodeList all attribute\n");)
5536                } else {
5537                    if (nodeToMatch->ownerDocument->rootNode == nodeToMatch) {
5538                        xpathRSFree (&nodeList); return 0;
5539                    }
5540                    DBG(if (nodeToMatch->parentNode) {
5541                            fprintf(stderr, "FillNodeList on %s/%s...\n", nodeToMatch->parentNode->nodeName,nodeToMatch->nodeName);
5542                        } else {
5543                            fprintf(stderr, "FillNodeList on (null)/%s...\n", nodeToMatch->nodeName);
5544                        }
5545                        fprintf (stderr, "Current nodeList is:\n");
5546                        rsPrint (&nodeList);
5547                    )
5548                    if (nodeToMatch->parentNode == NULL) {
5549                        child = nodeToMatch->ownerDocument->rootNode->firstChild;
5550                    } else {
5551                        child = nodeToMatch->parentNode->firstChild;
5552                    }
5553                }
5554                currentPos = -1;
5555                i = 0;
5556                while (child) {
5557                    rc = xpathMatches (step->child, exprContext, child, cbs, errMsg);
5558                    if (rc == 1) {
5559                        checkRsAddNode( &nodeList, child);
5560                        if (child == nodeToMatch) currentPos = i;
5561                        i++;
5562                        if (step->intvalue && i >= step->intvalue) break;
5563                    }
5564                    if (child->nodeType == ATTRIBUTE_NODE) {
5565                        child = (domNode*) ((domAttrNode*)child)->nextSibling;
5566                    } else {
5567                        child = child->nextSibling;
5568                    }
5569                }
5570                DBG(
5571                  rsPrint(&nodeList);
5572                  fprintf(stderr, "currentPos = %d \n", currentPos);
5573                )
5574                break;
5575
5576            case Pred:
5577                xpathRSInit (&stepResult);
5578                DBG(fprintf(stderr, "Befor Pred inner EvalStep. currentPos = %d\n", currentPos);)
5579                rc = xpathEvalStep (step->child, nodeToMatch, exprContext,
5580                                    currentPos, &nodeList, cbs, &stepResult,
5581                                    &docOrder, errMsg);
5582                CHECK_RC;
5583                DBG(
5584                  fprintf(stderr, "Pred inner EvalStep returned\n");
5585                  rsPrint(&stepResult);
5586                )
5587                nodeMatches = 0;
5588
5589                if (stepResult.type == RealResult) {
5590                    stepResult.type = IntResult;
5591                    stepResult.intvalue = xpathRound(stepResult.realvalue);
5592                }
5593                if (stepResult.type == IntResult) {
5594                    if (stepResult.intvalue < 0) {
5595                        stepResult.intvalue = nodeList.nr_nodes + stepResult.intvalue;
5596                    }
5597                    if ((stepResult.intvalue > 0 ) &&
5598                        (stepResult.intvalue <= nodeList.nr_nodes) &&
5599                        (stepResult.intvalue == (currentPos+1)) ) {
5600                         nodeMatches = 1;
5601                    }
5602                } else if (xpathFuncBoolean(&stepResult)) {
5603                    nodeMatches = 1;
5604                }
5605                xpathRSFree (&stepResult);
5606
5607                /* if nodeMatches == false we don't have to continue to filter */
5608                if (!nodeMatches) {
5609                    xpathRSFree (&nodeList); return 0;
5610                }
5611
5612                /* if the nr_nodes of nodeList is > 1 (ie. we filter a
5613                   FillNodeList step, not only a FillWithCurrentNode
5614                   step), build the resulting nodeList context after
5615                   this predicate */
5616
5617                if (nodeList.nr_nodes > 1) {
5618                    xpathRSInit (&newNodeList);
5619                    currentPos = -1;
5620                    j = 0;
5621                    for (i = 0; i < nodeList.nr_nodes; i++) {
5622                        xpathRSInit (&stepResult);
5623                        docOrder = 1;
5624                        rc = xpathEvalStep (step->child, nodeList.nodes[i],
5625                                            exprContext, i, &nodeList, cbs,
5626                                            &stepResult, &docOrder, errMsg);
5627                        if (rc) {
5628                            xpathRSFree (&stepResult);
5629                            xpathRSFree (&nodeList);
5630                            return rc;
5631                        }
5632
5633                        nodeMatches = 0;
5634
5635                        if (stepResult.type == RealResult) {
5636                            stepResult.type = IntResult;
5637                            stepResult.intvalue =
5638                                xpathRound(stepResult.realvalue);
5639                        }
5640                        if (stepResult.type == IntResult) {
5641                            if (stepResult.intvalue < 0) {
5642                                stepResult.intvalue =
5643                                    nodeList.nr_nodes + stepResult.intvalue;
5644                            }
5645                            if ((stepResult.intvalue > 0 ) &&
5646                                (stepResult.intvalue <= nodeList.nr_nodes) &&
5647                                (stepResult.intvalue == (currentPos+1)) ) {
5648                                nodeMatches = 1;
5649                            }
5650                        } else if (xpathFuncBoolean(&stepResult)) {
5651                            nodeMatches = 1;
5652                        }
5653                        if (nodeMatches) {
5654                            checkRsAddNode (&newNodeList, nodeList.nodes[i]);
5655                            if (nodeList.nodes[i] == nodeToMatch) {
5656                                currentPos = j;
5657                            }
5658                            j++;
5659                        }
5660                        xpathRSFree (&stepResult);
5661                    }
5662                    xpathRSFree (&nodeList);
5663                    nodeList = newNodeList;
5664                }
5665                break;
5666
5667            case CombinePath:
5668                childSteps = step->child;
5669                while (childSteps) {
5670                    rc = xpathMatches (childSteps->child, exprContext,
5671                                       nodeToMatch, cbs, errMsg);
5672                    if (rc == 1) break;
5673                    childSteps = childSteps->next;
5674                }
5675                if (childSteps == NULL) {
5676                    xpathRSFree (&nodeList); return 0;
5677                }
5678                break;
5679
5680            case ExecIdKey:
5681                xpathRSInit (&stepResult);
5682                rc = xpathEvalStep (step, nodeToMatch, exprContext,
5683                                    currentPos, &nodeList, cbs, &stepResult,
5684                                    &docOrder, errMsg);
5685                CHECK_RC;
5686                if (stepResult.type != xNodeSetResult) {
5687                    xpathRSFree (&stepResult);
5688                    xpathRSFree (&nodeList); return 0;
5689                }
5690                nodeMatches = 0;
5691                for (i = 0; i < stepResult.nr_nodes; i++) {
5692                    if (nodeToMatch == stepResult.nodes[i]) {
5693                        nodeMatches = 1;
5694                        break;
5695                    }
5696                }
5697                xpathRSFree (&stepResult);
5698                if (!nodeMatches) { xpathRSFree (&nodeList); return 0; }
5699                break;
5700
5701            default:
5702                DBG(
5703                fprintf(stderr, "wrong type %d for xpathMatches \n", step->type);
5704                fprintf(stderr, "AST:\n");
5705                )
5706                printAst (0, step);
5707                xpathRSFree (&nodeList); return 0;
5708                break;
5709        }
5710        step = step->next;
5711    }
5712    xpathRSFree (&nodeList);
5713    return 1;
5714}
5715
5716/*----------------------------------------------------------------------------
5717|   xpathGetPrio
5718|
5719\---------------------------------------------------------------------------*/
5720double xpathGetPrio (
5721    ast steps
5722)
5723{
5724    if (!steps) return 0.0;
5725
5726    DBG(printAst(0, steps);)
5727
5728    if (steps->next == NULL) {
5729        if (steps->type == IsElement) {
5730            if (strcmp(steps->strvalue, "*")==0) {
5731                return -0.5;
5732            } else {
5733                return 0.0;
5734            }
5735        } else
5736        if (steps->type == IsFQElement) {
5737            return 0.0;
5738        } else
5739        if (steps->type == IsNSElement) {
5740            return -0.25;
5741        } else
5742        if (steps->type == IsAttr) {
5743            if (strcmp(steps->strvalue, "*")==0) {
5744                return -0.5;
5745            } else {
5746                return 0.0;
5747            }
5748        } else
5749        if (steps->type == IsNSAttr) {
5750            if (strcmp(steps->child->strvalue, "*")==0) {
5751                return -0.25;
5752            } else {
5753                return 0.0;
5754            }
5755        } else
5756        if ( steps->type == IsNode
5757             || steps->type == IsText
5758             || steps->type == IsPI
5759             || steps->type == IsComment
5760             || steps->type == IsSpecificPI
5761            ) {
5762            return -0.5;
5763        } else
5764        if ( steps->type == AxisChild
5765             || steps->type == AxisAttribute
5766             || steps->type == EvalSteps
5767            ) {
5768            return (xpathGetPrio (steps->child));
5769        }
5770    }
5771    return 0.5;
5772
5773} /* xpathGetPrio */
5774
5775
5776/*----------------------------------------------------------------------------
5777|   nodeToXPath  -  returns a XPath addressing exactly the given node
5778|
5779\---------------------------------------------------------------------------*/
5780static void nodeToXPath (
5781    domNode  * node,
5782    char    ** xpath,
5783    int      * xpathLen,
5784    int      * xpathAllocated
5785)
5786{
5787    domNode *parent, *child;
5788    char    step[200], *nTest;
5789    int     sameNodes, nodeIndex, len;
5790
5791
5792    parent = node->parentNode;
5793    if (parent == NULL) {
5794        parent = node->ownerDocument->rootNode;
5795    } else {
5796        nodeToXPath (parent, xpath, xpathLen, xpathAllocated);
5797    }
5798
5799    step[0] = '\0';
5800    switch (node->nodeType) {
5801
5802    case ELEMENT_NODE:
5803        nodeIndex = 0;
5804        sameNodes = 0;
5805        child = parent->firstChild;
5806        while (child) {
5807            if (strcmp(child->nodeName, node->nodeName)==0) {
5808                sameNodes++;
5809                if (node == child) nodeIndex = sameNodes;
5810                if ((nodeIndex != 0) && (sameNodes > 2)) break;
5811            }
5812            child = child->nextSibling;
5813        }
5814        if (sameNodes == 1) {
5815            sprintf(step, "/%s", node->nodeName);
5816        } else {
5817            sprintf(step, "/%s[%d]", node->nodeName, nodeIndex);
5818        }
5819        break;
5820
5821    case TEXT_NODE:
5822    case COMMENT_NODE:
5823    case PROCESSING_INSTRUCTION_NODE:
5824        nodeIndex = 0;
5825        sameNodes = 0;
5826        child = parent->firstChild;
5827        while (child) {
5828            if (child->nodeType == node->nodeType) {
5829                sameNodes++;
5830                if (node == child) nodeIndex = sameNodes;
5831                if ((nodeIndex != 0) && (sameNodes > 2)) break;
5832            }
5833            child = child->nextSibling;
5834        }
5835        switch (node->nodeType) {
5836        case TEXT_NODE:                   nTest = "text()";  break;
5837        case COMMENT_NODE:                nTest = "comment()"; break;
5838        case PROCESSING_INSTRUCTION_NODE: nTest = "processing-instruction()"; break;
5839        default:                          nTest = "unknownNodeType()";
5840        }
5841        if (sameNodes == 1) {
5842            sprintf(step, "/%s", nTest);
5843        } else {
5844            sprintf(step, "/%s[%d]", nTest, nodeIndex);
5845        }
5846        break;
5847
5848    default:
5849        break;
5850    }
5851    len = strlen(step);
5852    if ( (len + *xpathLen) > *xpathAllocated ) {
5853        *xpathAllocated = *xpathAllocated * 2;
5854        *xpath = REALLOC(*xpath, *xpathAllocated + 1);
5855    }
5856    strcpy( *xpath + *xpathLen, step);
5857    *xpathLen += len;
5858
5859} /* nodeToXPath */
5860
5861
5862/*----------------------------------------------------------------------------
5863|   xpathNodeToXPath
5864|
5865\---------------------------------------------------------------------------*/
5866char * xpathNodeToXPath (
5867    domNode *node
5868)
5869{
5870    char  * xpath;
5871    int     xpathLen, xpathAllocated;
5872
5873
5874    xpathAllocated = 100;
5875    xpathLen       = 0;
5876    xpath          = MALLOC(xpathAllocated + 1);
5877
5878    nodeToXPath (node, &xpath, &xpathLen, &xpathAllocated);
5879
5880    return xpath;
5881
5882} /* xpathNodeToXPath */
5883
5884