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