xpath.c revision 78637da0ea1c833dfdfad87a9aa5bea14510d08a
1/* 2 * xpath.c: XML Path Language implementation 3 * XPath is a language for addressing parts of an XML document, 4 * designed to be used by both XSLT and XPointer 5 * 6 * Reference: W3C Recommendation 16 November 1999 7 * http://www.w3.org/TR/1999/REC-xpath-19991116 8 * Public reference: 9 * http://www.w3.org/TR/xpath 10 * 11 * See Copyright for the status of this software 12 * 13 * Author: daniel@veillard.com 14 * 15 */ 16 17#define IN_LIBXML 18#include "libxml.h" 19 20#include <string.h> 21 22#ifdef HAVE_SYS_TYPES_H 23#include <sys/types.h> 24#endif 25#ifdef HAVE_MATH_H 26#include <math.h> 27#endif 28#ifdef HAVE_FLOAT_H 29#include <float.h> 30#endif 31#ifdef HAVE_CTYPE_H 32#include <ctype.h> 33#endif 34#ifdef HAVE_SIGNAL_H 35#include <signal.h> 36#endif 37 38#include <libxml/xmlmemory.h> 39#include <libxml/tree.h> 40#include <libxml/valid.h> 41#include <libxml/xpath.h> 42#include <libxml/xpathInternals.h> 43#include <libxml/parserInternals.h> 44#include <libxml/hash.h> 45#ifdef LIBXML_XPTR_ENABLED 46#include <libxml/xpointer.h> 47#endif 48#ifdef LIBXML_DEBUG_ENABLED 49#include <libxml/debugXML.h> 50#endif 51#include <libxml/xmlerror.h> 52#include <libxml/threads.h> 53#include <libxml/globals.h> 54 55/************************************************************************ 56 * * 57 * Floating point stuff * 58 * * 59 ************************************************************************/ 60 61#ifndef TRIO_REPLACE_STDIO 62#define TRIO_PUBLIC static 63#endif 64#include "trionan.c" 65 66/* 67 * The lack of portability of this section of the libc is annoying ! 68 */ 69double xmlXPathNAN = 0; 70double xmlXPathPINF = 1; 71double xmlXPathNINF = -1; 72double xmlXPathNZERO = 0; 73static int xmlXPathInitialized = 0; 74 75/** 76 * xmlXPathInit: 77 * 78 * Initialize the XPath environment 79 */ 80void 81xmlXPathInit(void) { 82 if (xmlXPathInitialized) return; 83 84 xmlXPathPINF = trio_pinf(); 85 xmlXPathNINF = trio_ninf(); 86 xmlXPathNAN = trio_nan(); 87 xmlXPathNZERO = trio_nzero(); 88 89 xmlXPathInitialized = 1; 90} 91 92/** 93 * xmlXPathIsNaN: 94 * @val: a double value 95 * 96 * Provides a portable isnan() function to detect whether a double 97 * is a NotaNumber. Based on trio code 98 * http://sourceforge.net/projects/ctrio/ 99 * 100 * Returns 1 if the value is a NaN, 0 otherwise 101 */ 102int 103xmlXPathIsNaN(double val) { 104 return(trio_isnan(val)); 105} 106 107/** 108 * xmlXPathIsInf: 109 * @val: a double value 110 * 111 * Provides a portable isinf() function to detect whether a double 112 * is a +Infinite or -Infinite. Based on trio code 113 * http://sourceforge.net/projects/ctrio/ 114 * 115 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise 116 */ 117int 118xmlXPathIsInf(double val) { 119 return(trio_isinf(val)); 120} 121 122/** 123 * xmlXPathGetSign: 124 * @val: a double value 125 * 126 * Provides a portable function to detect the sign of a double 127 * Modified from trio code 128 * http://sourceforge.net/projects/ctrio/ 129 * 130 * Returns 1 if the value is Negative, 0 if positive 131 */ 132static int 133xmlXPathGetSign(double val) { 134 return(trio_signbit(val)); 135} 136 137 138#ifdef LIBXML_XPATH_ENABLED 139/* 140 * TODO: when compatibility allows remove all "fake node libxslt" strings 141 * the test should just be name[0] = ' ' 142 */ 143/* #define DEBUG */ 144/* #define DEBUG_STEP */ 145/* #define DEBUG_STEP_NTH */ 146/* #define DEBUG_EXPR */ 147/* #define DEBUG_EVAL_COUNTS */ 148 149static xmlNs xmlXPathXMLNamespaceStruct = { 150 NULL, 151 XML_NAMESPACE_DECL, 152 XML_XML_NAMESPACE, 153 BAD_CAST "xml", 154 NULL 155}; 156static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 157#ifndef LIBXML_THREAD_ENABLED 158/* 159 * Optimizer is disabled only when threaded apps are detected while 160 * the library ain't compiled for thread safety. 161 */ 162static int xmlXPathDisableOptimizer = 0; 163#endif 164 165/************************************************************************ 166 * * 167 * Parser Types * 168 * * 169 ************************************************************************/ 170 171/* 172 * Types are private: 173 */ 174 175typedef enum { 176 XPATH_OP_END=0, 177 XPATH_OP_AND, 178 XPATH_OP_OR, 179 XPATH_OP_EQUAL, 180 XPATH_OP_CMP, 181 XPATH_OP_PLUS, 182 XPATH_OP_MULT, 183 XPATH_OP_UNION, 184 XPATH_OP_ROOT, 185 XPATH_OP_NODE, 186 XPATH_OP_RESET, 187 XPATH_OP_COLLECT, 188 XPATH_OP_VALUE, 189 XPATH_OP_VARIABLE, 190 XPATH_OP_FUNCTION, 191 XPATH_OP_ARG, 192 XPATH_OP_PREDICATE, 193 XPATH_OP_FILTER, 194 XPATH_OP_SORT 195#ifdef LIBXML_XPTR_ENABLED 196 ,XPATH_OP_RANGETO 197#endif 198} xmlXPathOp; 199 200typedef enum { 201 AXIS_ANCESTOR = 1, 202 AXIS_ANCESTOR_OR_SELF, 203 AXIS_ATTRIBUTE, 204 AXIS_CHILD, 205 AXIS_DESCENDANT, 206 AXIS_DESCENDANT_OR_SELF, 207 AXIS_FOLLOWING, 208 AXIS_FOLLOWING_SIBLING, 209 AXIS_NAMESPACE, 210 AXIS_PARENT, 211 AXIS_PRECEDING, 212 AXIS_PRECEDING_SIBLING, 213 AXIS_SELF 214} xmlXPathAxisVal; 215 216typedef enum { 217 NODE_TEST_NONE = 0, 218 NODE_TEST_TYPE = 1, 219 NODE_TEST_PI = 2, 220 NODE_TEST_ALL = 3, 221 NODE_TEST_NS = 4, 222 NODE_TEST_NAME = 5 223} xmlXPathTestVal; 224 225typedef enum { 226 NODE_TYPE_NODE = 0, 227 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 228 NODE_TYPE_TEXT = XML_TEXT_NODE, 229 NODE_TYPE_PI = XML_PI_NODE 230} xmlXPathTypeVal; 231 232 233typedef struct _xmlXPathStepOp xmlXPathStepOp; 234typedef xmlXPathStepOp *xmlXPathStepOpPtr; 235struct _xmlXPathStepOp { 236 xmlXPathOp op; 237 int ch1; 238 int ch2; 239 int value; 240 int value2; 241 int value3; 242 void *value4; 243 void *value5; 244 void *cache; 245 void *cacheURI; 246}; 247 248struct _xmlXPathCompExpr { 249 int nbStep; 250 int maxStep; 251 xmlXPathStepOp *steps; /* ops for computation */ 252 int last; 253 xmlChar *expr; 254#ifdef DEBUG_EVAL_COUNTS 255 int nb; 256 xmlChar *string; 257#endif 258}; 259 260/************************************************************************ 261 * * 262 * Parser Type functions * 263 * * 264 ************************************************************************/ 265 266/** 267 * xmlXPathNewCompExpr: 268 * 269 * Create a new Xpath component 270 * 271 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 272 */ 273static xmlXPathCompExprPtr 274xmlXPathNewCompExpr(void) { 275 xmlXPathCompExprPtr cur; 276 277 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 278 if (cur == NULL) { 279 xmlGenericError(xmlGenericErrorContext, 280 "xmlXPathNewCompExpr : malloc failed\n"); 281 return(NULL); 282 } 283 memset(cur, 0, sizeof(xmlXPathCompExpr)); 284 cur->maxStep = 10; 285 cur->nbStep = 0; 286 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 287 sizeof(xmlXPathStepOp)); 288 if (cur->steps == NULL) { 289 xmlGenericError(xmlGenericErrorContext, 290 "xmlXPathNewCompExpr : malloc failed\n"); 291 xmlFree(cur); 292 return(NULL); 293 } 294 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 295 cur->last = -1; 296#ifdef DEBUG_EVAL_COUNTS 297 cur->nb = 0; 298#endif 299 return(cur); 300} 301 302/** 303 * xmlXPathFreeCompExpr: 304 * @comp: an XPATH comp 305 * 306 * Free up the memory allocated by @comp 307 */ 308void 309xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 310{ 311 xmlXPathStepOpPtr op; 312 int i; 313 314 if (comp == NULL) 315 return; 316 for (i = 0; i < comp->nbStep; i++) { 317 op = &comp->steps[i]; 318 if (op->value4 != NULL) { 319 if (op->op == XPATH_OP_VALUE) 320 xmlXPathFreeObject(op->value4); 321 else 322 xmlFree(op->value4); 323 } 324 if (op->value5 != NULL) 325 xmlFree(op->value5); 326 } 327 if (comp->steps != NULL) { 328 xmlFree(comp->steps); 329 } 330#ifdef DEBUG_EVAL_COUNTS 331 if (comp->string != NULL) { 332 xmlFree(comp->string); 333 } 334#endif 335 if (comp->expr != NULL) { 336 xmlFree(comp->expr); 337 } 338 339 xmlFree(comp); 340} 341 342/** 343 * xmlXPathCompExprAdd: 344 * @comp: the compiled expression 345 * @ch1: first child index 346 * @ch2: second child index 347 * @op: an op 348 * @value: the first int value 349 * @value2: the second int value 350 * @value3: the third int value 351 * @value4: the first string value 352 * @value5: the second string value 353 * 354 * Add an step to an XPath Compiled Expression 355 * 356 * Returns -1 in case of failure, the index otherwise 357 */ 358static int 359xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 360 xmlXPathOp op, int value, 361 int value2, int value3, void *value4, void *value5) { 362 if (comp->nbStep >= comp->maxStep) { 363 xmlXPathStepOp *real; 364 365 comp->maxStep *= 2; 366 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 367 comp->maxStep * sizeof(xmlXPathStepOp)); 368 if (real == NULL) { 369 comp->maxStep /= 2; 370 xmlGenericError(xmlGenericErrorContext, 371 "xmlXPathCompExprAdd : realloc failed\n"); 372 return(-1); 373 } 374 comp->steps = real; 375 } 376 comp->last = comp->nbStep; 377 comp->steps[comp->nbStep].ch1 = ch1; 378 comp->steps[comp->nbStep].ch2 = ch2; 379 comp->steps[comp->nbStep].op = op; 380 comp->steps[comp->nbStep].value = value; 381 comp->steps[comp->nbStep].value2 = value2; 382 comp->steps[comp->nbStep].value3 = value3; 383 comp->steps[comp->nbStep].value4 = value4; 384 comp->steps[comp->nbStep].value5 = value5; 385 comp->steps[comp->nbStep].cache = NULL; 386 return(comp->nbStep++); 387} 388 389/** 390 * xmlXPathCompSwap: 391 * @comp: the compiled expression 392 * @op: operation index 393 * 394 * Swaps 2 operations in the compiled expression 395 */ 396static void 397xmlXPathCompSwap(xmlXPathStepOpPtr op) { 398 int tmp; 399 400#ifndef LIBXML_THREAD_ENABLED 401 /* 402 * Since this manipulates possibly shared variables, this is 403 * disable if one detects that the library is used in a multithreaded 404 * application 405 */ 406 if (xmlXPathDisableOptimizer) 407 return; 408#endif 409 410 tmp = op->ch1; 411 op->ch1 = op->ch2; 412 op->ch2 = tmp; 413} 414 415#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 416 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 417 (op), (val), (val2), (val3), (val4), (val5)) 418#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 419 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 420 (op), (val), (val2), (val3), (val4), (val5)) 421 422#define PUSH_LEAVE_EXPR(op, val, val2) \ 423xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 424 425#define PUSH_UNARY_EXPR(op, ch, val, val2) \ 426xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 427 428#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 429xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL) 430 431/************************************************************************ 432 * * 433 * Debugging related functions * 434 * * 435 ************************************************************************/ 436 437#define TODO \ 438 xmlGenericError(xmlGenericErrorContext, \ 439 "Unimplemented block at %s:%d\n", \ 440 __FILE__, __LINE__); 441 442#define STRANGE \ 443 xmlGenericError(xmlGenericErrorContext, \ 444 "Internal error at %s:%d\n", \ 445 __FILE__, __LINE__); 446 447#ifdef LIBXML_DEBUG_ENABLED 448static void 449xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 450 int i; 451 char shift[100]; 452 453 for (i = 0;((i < depth) && (i < 25));i++) 454 shift[2 * i] = shift[2 * i + 1] = ' '; 455 shift[2 * i] = shift[2 * i + 1] = 0; 456 if (cur == NULL) { 457 fprintf(output, shift); 458 fprintf(output, "Node is NULL !\n"); 459 return; 460 461 } 462 463 if ((cur->type == XML_DOCUMENT_NODE) || 464 (cur->type == XML_HTML_DOCUMENT_NODE)) { 465 fprintf(output, shift); 466 fprintf(output, " /\n"); 467 } else if (cur->type == XML_ATTRIBUTE_NODE) 468 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 469 else 470 xmlDebugDumpOneNode(output, cur, depth); 471} 472static void 473xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 474 xmlNodePtr tmp; 475 int i; 476 char shift[100]; 477 478 for (i = 0;((i < depth) && (i < 25));i++) 479 shift[2 * i] = shift[2 * i + 1] = ' '; 480 shift[2 * i] = shift[2 * i + 1] = 0; 481 if (cur == NULL) { 482 fprintf(output, shift); 483 fprintf(output, "Node is NULL !\n"); 484 return; 485 486 } 487 488 while (cur != NULL) { 489 tmp = cur; 490 cur = cur->next; 491 xmlDebugDumpOneNode(output, tmp, depth); 492 } 493} 494 495static void 496xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 497 int i; 498 char shift[100]; 499 500 for (i = 0;((i < depth) && (i < 25));i++) 501 shift[2 * i] = shift[2 * i + 1] = ' '; 502 shift[2 * i] = shift[2 * i + 1] = 0; 503 504 if (cur == NULL) { 505 fprintf(output, shift); 506 fprintf(output, "NodeSet is NULL !\n"); 507 return; 508 509 } 510 511 if (cur != NULL) { 512 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 513 for (i = 0;i < cur->nodeNr;i++) { 514 fprintf(output, shift); 515 fprintf(output, "%d", i + 1); 516 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 517 } 518 } 519} 520 521static void 522xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 523 int i; 524 char shift[100]; 525 526 for (i = 0;((i < depth) && (i < 25));i++) 527 shift[2 * i] = shift[2 * i + 1] = ' '; 528 shift[2 * i] = shift[2 * i + 1] = 0; 529 530 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 531 fprintf(output, shift); 532 fprintf(output, "Value Tree is NULL !\n"); 533 return; 534 535 } 536 537 fprintf(output, shift); 538 fprintf(output, "%d", i + 1); 539 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 540} 541#if defined(LIBXML_XPTR_ENABLED) 542static void 543xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 544 int i; 545 char shift[100]; 546 547 for (i = 0;((i < depth) && (i < 25));i++) 548 shift[2 * i] = shift[2 * i + 1] = ' '; 549 shift[2 * i] = shift[2 * i + 1] = 0; 550 551 if (cur == NULL) { 552 fprintf(output, shift); 553 fprintf(output, "LocationSet is NULL !\n"); 554 return; 555 556 } 557 558 for (i = 0;i < cur->locNr;i++) { 559 fprintf(output, shift); 560 fprintf(output, "%d : ", i + 1); 561 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 562 } 563} 564#endif /* LIBXML_XPTR_ENABLED */ 565 566/** 567 * xmlXPathDebugDumpObject: 568 * @output: the FILE * to dump the output 569 * @cur: the object to inspect 570 * @depth: indentation level 571 * 572 * Dump the content of the object for debugging purposes 573 */ 574void 575xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 576 int i; 577 char shift[100]; 578 579 for (i = 0;((i < depth) && (i < 25));i++) 580 shift[2 * i] = shift[2 * i + 1] = ' '; 581 shift[2 * i] = shift[2 * i + 1] = 0; 582 583 fprintf(output, shift); 584 585 if (cur == NULL) { 586 fprintf(output, "Object is empty (NULL)\n"); 587 return; 588 } 589 switch(cur->type) { 590 case XPATH_UNDEFINED: 591 fprintf(output, "Object is uninitialized\n"); 592 break; 593 case XPATH_NODESET: 594 fprintf(output, "Object is a Node Set :\n"); 595 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 596 break; 597 case XPATH_XSLT_TREE: 598 fprintf(output, "Object is an XSLT value tree :\n"); 599 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 600 break; 601 case XPATH_BOOLEAN: 602 fprintf(output, "Object is a Boolean : "); 603 if (cur->boolval) fprintf(output, "true\n"); 604 else fprintf(output, "false\n"); 605 break; 606 case XPATH_NUMBER: 607 switch (xmlXPathIsInf(cur->floatval)) { 608 case 1: 609 fprintf(output, "Object is a number : Infinity\n"); 610 break; 611 case -1: 612 fprintf(output, "Object is a number : -Infinity\n"); 613 break; 614 default: 615 if (xmlXPathIsNaN(cur->floatval)) { 616 fprintf(output, "Object is a number : NaN\n"); 617 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 618 fprintf(output, "Object is a number : 0\n"); 619 } else { 620 fprintf(output, "Object is a number : %0g\n", cur->floatval); 621 } 622 } 623 break; 624 case XPATH_STRING: 625 fprintf(output, "Object is a string : "); 626 xmlDebugDumpString(output, cur->stringval); 627 fprintf(output, "\n"); 628 break; 629 case XPATH_POINT: 630 fprintf(output, "Object is a point : index %d in node", cur->index); 631 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 632 fprintf(output, "\n"); 633 break; 634 case XPATH_RANGE: 635 if ((cur->user2 == NULL) || 636 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 637 fprintf(output, "Object is a collapsed range :\n"); 638 fprintf(output, shift); 639 if (cur->index >= 0) 640 fprintf(output, "index %d in ", cur->index); 641 fprintf(output, "node\n"); 642 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 643 depth + 1); 644 } else { 645 fprintf(output, "Object is a range :\n"); 646 fprintf(output, shift); 647 fprintf(output, "From "); 648 if (cur->index >= 0) 649 fprintf(output, "index %d in ", cur->index); 650 fprintf(output, "node\n"); 651 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 652 depth + 1); 653 fprintf(output, shift); 654 fprintf(output, "To "); 655 if (cur->index2 >= 0) 656 fprintf(output, "index %d in ", cur->index2); 657 fprintf(output, "node\n"); 658 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 659 depth + 1); 660 fprintf(output, "\n"); 661 } 662 break; 663 case XPATH_LOCATIONSET: 664#if defined(LIBXML_XPTR_ENABLED) 665 fprintf(output, "Object is a Location Set:\n"); 666 xmlXPathDebugDumpLocationSet(output, 667 (xmlLocationSetPtr) cur->user, depth); 668#endif 669 break; 670 case XPATH_USERS: 671 fprintf(output, "Object is user defined\n"); 672 break; 673 } 674} 675 676static void 677xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 678 xmlXPathStepOpPtr op, int depth) { 679 int i; 680 char shift[100]; 681 682 for (i = 0;((i < depth) && (i < 25));i++) 683 shift[2 * i] = shift[2 * i + 1] = ' '; 684 shift[2 * i] = shift[2 * i + 1] = 0; 685 686 fprintf(output, shift); 687 if (op == NULL) { 688 fprintf(output, "Step is NULL\n"); 689 return; 690 } 691 switch (op->op) { 692 case XPATH_OP_END: 693 fprintf(output, "END"); break; 694 case XPATH_OP_AND: 695 fprintf(output, "AND"); break; 696 case XPATH_OP_OR: 697 fprintf(output, "OR"); break; 698 case XPATH_OP_EQUAL: 699 if (op->value) 700 fprintf(output, "EQUAL ="); 701 else 702 fprintf(output, "EQUAL !="); 703 break; 704 case XPATH_OP_CMP: 705 if (op->value) 706 fprintf(output, "CMP <"); 707 else 708 fprintf(output, "CMP >"); 709 if (!op->value2) 710 fprintf(output, "="); 711 break; 712 case XPATH_OP_PLUS: 713 if (op->value == 0) 714 fprintf(output, "PLUS -"); 715 else if (op->value == 1) 716 fprintf(output, "PLUS +"); 717 else if (op->value == 2) 718 fprintf(output, "PLUS unary -"); 719 else if (op->value == 3) 720 fprintf(output, "PLUS unary - -"); 721 break; 722 case XPATH_OP_MULT: 723 if (op->value == 0) 724 fprintf(output, "MULT *"); 725 else if (op->value == 1) 726 fprintf(output, "MULT div"); 727 else 728 fprintf(output, "MULT mod"); 729 break; 730 case XPATH_OP_UNION: 731 fprintf(output, "UNION"); break; 732 case XPATH_OP_ROOT: 733 fprintf(output, "ROOT"); break; 734 case XPATH_OP_NODE: 735 fprintf(output, "NODE"); break; 736 case XPATH_OP_RESET: 737 fprintf(output, "RESET"); break; 738 case XPATH_OP_SORT: 739 fprintf(output, "SORT"); break; 740 case XPATH_OP_COLLECT: { 741 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 742 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 743 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 744 const xmlChar *prefix = op->value4; 745 const xmlChar *name = op->value5; 746 747 fprintf(output, "COLLECT "); 748 switch (axis) { 749 case AXIS_ANCESTOR: 750 fprintf(output, " 'ancestors' "); break; 751 case AXIS_ANCESTOR_OR_SELF: 752 fprintf(output, " 'ancestors-or-self' "); break; 753 case AXIS_ATTRIBUTE: 754 fprintf(output, " 'attributes' "); break; 755 case AXIS_CHILD: 756 fprintf(output, " 'child' "); break; 757 case AXIS_DESCENDANT: 758 fprintf(output, " 'descendant' "); break; 759 case AXIS_DESCENDANT_OR_SELF: 760 fprintf(output, " 'descendant-or-self' "); break; 761 case AXIS_FOLLOWING: 762 fprintf(output, " 'following' "); break; 763 case AXIS_FOLLOWING_SIBLING: 764 fprintf(output, " 'following-siblings' "); break; 765 case AXIS_NAMESPACE: 766 fprintf(output, " 'namespace' "); break; 767 case AXIS_PARENT: 768 fprintf(output, " 'parent' "); break; 769 case AXIS_PRECEDING: 770 fprintf(output, " 'preceding' "); break; 771 case AXIS_PRECEDING_SIBLING: 772 fprintf(output, " 'preceding-sibling' "); break; 773 case AXIS_SELF: 774 fprintf(output, " 'self' "); break; 775 } 776 switch (test) { 777 case NODE_TEST_NONE: 778 fprintf(output, "'none' "); break; 779 case NODE_TEST_TYPE: 780 fprintf(output, "'type' "); break; 781 case NODE_TEST_PI: 782 fprintf(output, "'PI' "); break; 783 case NODE_TEST_ALL: 784 fprintf(output, "'all' "); break; 785 case NODE_TEST_NS: 786 fprintf(output, "'namespace' "); break; 787 case NODE_TEST_NAME: 788 fprintf(output, "'name' "); break; 789 } 790 switch (type) { 791 case NODE_TYPE_NODE: 792 fprintf(output, "'node' "); break; 793 case NODE_TYPE_COMMENT: 794 fprintf(output, "'comment' "); break; 795 case NODE_TYPE_TEXT: 796 fprintf(output, "'text' "); break; 797 case NODE_TYPE_PI: 798 fprintf(output, "'PI' "); break; 799 } 800 if (prefix != NULL) 801 fprintf(output, "%s:", prefix); 802 if (name != NULL) 803 fprintf(output, "%s", (const char *) name); 804 break; 805 806 } 807 case XPATH_OP_VALUE: { 808 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 809 810 fprintf(output, "ELEM "); 811 xmlXPathDebugDumpObject(output, object, 0); 812 goto finish; 813 } 814 case XPATH_OP_VARIABLE: { 815 const xmlChar *prefix = op->value5; 816 const xmlChar *name = op->value4; 817 818 if (prefix != NULL) 819 fprintf(output, "VARIABLE %s:%s", prefix, name); 820 else 821 fprintf(output, "VARIABLE %s", name); 822 break; 823 } 824 case XPATH_OP_FUNCTION: { 825 int nbargs = op->value; 826 const xmlChar *prefix = op->value5; 827 const xmlChar *name = op->value4; 828 829 if (prefix != NULL) 830 fprintf(output, "FUNCTION %s:%s(%d args)", 831 prefix, name, nbargs); 832 else 833 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 834 break; 835 } 836 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 837 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 838 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 839#ifdef LIBXML_XPTR_ENABLED 840 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 841#endif 842 default: 843 fprintf(output, "UNKNOWN %d\n", op->op); return; 844 } 845 fprintf(output, "\n"); 846finish: 847 if (op->ch1 >= 0) 848 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 849 if (op->ch2 >= 0) 850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 851} 852 853/** 854 * xmlXPathDebugDumpCompExpr: 855 * @output: the FILE * for the output 856 * @comp: the precompiled XPath expression 857 * @depth: the indentation level. 858 * 859 * Dumps the tree of the compiled XPath expression. 860 */ 861void 862xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 863 int depth) { 864 int i; 865 char shift[100]; 866 867 for (i = 0;((i < depth) && (i < 25));i++) 868 shift[2 * i] = shift[2 * i + 1] = ' '; 869 shift[2 * i] = shift[2 * i + 1] = 0; 870 871 fprintf(output, shift); 872 873 if (comp == NULL) { 874 fprintf(output, "Compiled Expression is NULL\n"); 875 return; 876 } 877 fprintf(output, "Compiled Expression : %d elements\n", 878 comp->nbStep); 879 i = comp->last; 880 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 881} 882#endif /* LIBXML_DEBUG_ENABLED */ 883 884/************************************************************************ 885 * * 886 * Parser stacks related functions and macros * 887 * * 888 ************************************************************************/ 889 890/** 891 * valuePop: 892 * @ctxt: an XPath evaluation context 893 * 894 * Pops the top XPath object from the value stack 895 * 896 * Returns the XPath object just removed 897 */ 898extern xmlXPathObjectPtr 899valuePop(xmlXPathParserContextPtr ctxt) 900{ 901 xmlXPathObjectPtr ret; 902 903 if (ctxt->valueNr <= 0) 904 return (0); 905 ctxt->valueNr--; 906 if (ctxt->valueNr > 0) 907 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 908 else 909 ctxt->value = NULL; 910 ret = ctxt->valueTab[ctxt->valueNr]; 911 ctxt->valueTab[ctxt->valueNr] = 0; 912 return (ret); 913} 914/** 915 * valuePush: 916 * @ctxt: an XPath evaluation context 917 * @value: the XPath object 918 * 919 * Pushes a new XPath object on top of the value stack 920 * 921 * returns the number of items on the value stack 922 */ 923extern int 924valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 925{ 926 if (ctxt->valueNr >= ctxt->valueMax) { 927 ctxt->valueMax *= 2; 928 ctxt->valueTab = 929 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 930 ctxt->valueMax * 931 sizeof(ctxt->valueTab[0])); 932 if (ctxt->valueTab == NULL) { 933 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 934 return (0); 935 } 936 } 937 ctxt->valueTab[ctxt->valueNr] = value; 938 ctxt->value = value; 939 return (ctxt->valueNr++); 940} 941 942/** 943 * xmlXPathPopBoolean: 944 * @ctxt: an XPath parser context 945 * 946 * Pops a boolean from the stack, handling conversion if needed. 947 * Check error with #xmlXPathCheckError. 948 * 949 * Returns the boolean 950 */ 951int 952xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 953 xmlXPathObjectPtr obj; 954 int ret; 955 956 obj = valuePop(ctxt); 957 if (obj == NULL) { 958 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 959 return(0); 960 } 961 ret = xmlXPathCastToBoolean(obj); 962 xmlXPathFreeObject(obj); 963 return(ret); 964} 965 966/** 967 * xmlXPathPopNumber: 968 * @ctxt: an XPath parser context 969 * 970 * Pops a number from the stack, handling conversion if needed. 971 * Check error with #xmlXPathCheckError. 972 * 973 * Returns the number 974 */ 975double 976xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 977 xmlXPathObjectPtr obj; 978 double ret; 979 980 obj = valuePop(ctxt); 981 if (obj == NULL) { 982 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 983 return(0); 984 } 985 ret = xmlXPathCastToNumber(obj); 986 xmlXPathFreeObject(obj); 987 return(ret); 988} 989 990/** 991 * xmlXPathPopString: 992 * @ctxt: an XPath parser context 993 * 994 * Pops a string from the stack, handling conversion if needed. 995 * Check error with #xmlXPathCheckError. 996 * 997 * Returns the string 998 */ 999xmlChar * 1000xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 1001 xmlXPathObjectPtr obj; 1002 xmlChar * ret; 1003 1004 obj = valuePop(ctxt); 1005 if (obj == NULL) { 1006 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 1007 return(NULL); 1008 } 1009 ret = xmlXPathCastToString(obj); 1010 /* TODO: needs refactoring somewhere else */ 1011 if (obj->stringval == ret) 1012 obj->stringval = NULL; 1013 xmlXPathFreeObject(obj); 1014 return(ret); 1015} 1016 1017/** 1018 * xmlXPathPopNodeSet: 1019 * @ctxt: an XPath parser context 1020 * 1021 * Pops a node-set from the stack, handling conversion if needed. 1022 * Check error with #xmlXPathCheckError. 1023 * 1024 * Returns the node-set 1025 */ 1026xmlNodeSetPtr 1027xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 1028 xmlXPathObjectPtr obj; 1029 xmlNodeSetPtr ret; 1030 1031 if (ctxt->value == NULL) { 1032 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 1033 return(NULL); 1034 } 1035 if (!xmlXPathStackIsNodeSet(ctxt)) { 1036 xmlXPathSetTypeError(ctxt); 1037 return(NULL); 1038 } 1039 obj = valuePop(ctxt); 1040 ret = obj->nodesetval; 1041 /* to fix memory leak of not clearing obj->user */ 1042 if (obj->boolval && obj->user != NULL) 1043 xmlFreeNodeList((xmlNodePtr) obj->user); 1044 xmlXPathFreeNodeSetList(obj); 1045 return(ret); 1046} 1047 1048/** 1049 * xmlXPathPopExternal: 1050 * @ctxt: an XPath parser context 1051 * 1052 * Pops an external object from the stack, handling conversion if needed. 1053 * Check error with #xmlXPathCheckError. 1054 * 1055 * Returns the object 1056 */ 1057void * 1058xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 1059 xmlXPathObjectPtr obj; 1060 void * ret; 1061 1062 if (ctxt->value == NULL) { 1063 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 1064 return(NULL); 1065 } 1066 if (ctxt->value->type != XPATH_USERS) { 1067 xmlXPathSetTypeError(ctxt); 1068 return(NULL); 1069 } 1070 obj = valuePop(ctxt); 1071 ret = obj->user; 1072 xmlXPathFreeObject(obj); 1073 return(ret); 1074} 1075 1076/* 1077 * Macros for accessing the content. Those should be used only by the parser, 1078 * and not exported. 1079 * 1080 * Dirty macros, i.e. one need to make assumption on the context to use them 1081 * 1082 * CUR_PTR return the current pointer to the xmlChar to be parsed. 1083 * CUR returns the current xmlChar value, i.e. a 8 bit value 1084 * in ISO-Latin or UTF-8. 1085 * This should be used internally by the parser 1086 * only to compare to ASCII values otherwise it would break when 1087 * running with UTF-8 encoding. 1088 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 1089 * to compare on ASCII based substring. 1090 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 1091 * strings within the parser. 1092 * CURRENT Returns the current char value, with the full decoding of 1093 * UTF-8 if we are using this mode. It returns an int. 1094 * NEXT Skip to the next character, this does the proper decoding 1095 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 1096 * It returns the pointer to the current xmlChar. 1097 */ 1098 1099#define CUR (*ctxt->cur) 1100#define SKIP(val) ctxt->cur += (val) 1101#define NXT(val) ctxt->cur[(val)] 1102#define CUR_PTR ctxt->cur 1103#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 1104 1105#define COPY_BUF(l,b,i,v) \ 1106 if (l == 1) b[i++] = (xmlChar) v; \ 1107 else i += xmlCopyChar(l,&b[i],v) 1108 1109#define NEXTL(l) ctxt->cur += l 1110 1111#define SKIP_BLANKS \ 1112 while (IS_BLANK(*(ctxt->cur))) NEXT 1113 1114#define CURRENT (*ctxt->cur) 1115#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 1116 1117 1118#ifndef DBL_DIG 1119#define DBL_DIG 16 1120#endif 1121#ifndef DBL_EPSILON 1122#define DBL_EPSILON 1E-9 1123#endif 1124 1125#define UPPER_DOUBLE 1E9 1126#define LOWER_DOUBLE 1E-5 1127 1128#define INTEGER_DIGITS DBL_DIG 1129#define FRACTION_DIGITS (DBL_DIG + 1) 1130#define EXPONENT_DIGITS (3 + 2) 1131 1132/** 1133 * xmlXPathFormatNumber: 1134 * @number: number to format 1135 * @buffer: output buffer 1136 * @buffersize: size of output buffer 1137 * 1138 * Convert the number into a string representation. 1139 */ 1140static void 1141xmlXPathFormatNumber(double number, char buffer[], int buffersize) 1142{ 1143 switch (xmlXPathIsInf(number)) { 1144 case 1: 1145 if (buffersize > (int)sizeof("Infinity")) 1146 snprintf(buffer, buffersize, "Infinity"); 1147 break; 1148 case -1: 1149 if (buffersize > (int)sizeof("-Infinity")) 1150 snprintf(buffer, buffersize, "-Infinity"); 1151 break; 1152 default: 1153 if (xmlXPathIsNaN(number)) { 1154 if (buffersize > (int)sizeof("NaN")) 1155 snprintf(buffer, buffersize, "NaN"); 1156 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 1157 snprintf(buffer, buffersize, "0"); 1158 } else if (number == ((int) number)) { 1159 char work[30]; 1160 char *ptr, *cur; 1161 int res, value = (int) number; 1162 1163 ptr = &buffer[0]; 1164 if (value < 0) { 1165 *ptr++ = '-'; 1166 value = -value; 1167 } 1168 if (value == 0) { 1169 *ptr++ = '0'; 1170 } else { 1171 cur = &work[0]; 1172 while (value != 0) { 1173 res = value % 10; 1174 value = value / 10; 1175 *cur++ = '0' + res; 1176 } 1177 cur--; 1178 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) { 1179 *ptr++ = *cur--; 1180 } 1181 } 1182 if (ptr - buffer < buffersize) { 1183 *ptr = 0; 1184 } else if (buffersize > 0) { 1185 ptr--; 1186 *ptr = 0; 1187 } 1188 } else { 1189 /* 3 is sign, decimal point, and terminating zero */ 1190 char work[DBL_DIG + EXPONENT_DIGITS + 3]; 1191 int integer_place, fraction_place; 1192 char *ptr; 1193 char *after_fraction; 1194 double absolute_value; 1195 int size; 1196 1197 absolute_value = fabs(number); 1198 1199 /* 1200 * First choose format - scientific or regular floating point. 1201 * In either case, result is in work, and after_fraction points 1202 * just past the fractional part. 1203 */ 1204 if ( ((absolute_value > UPPER_DOUBLE) || 1205 (absolute_value < LOWER_DOUBLE)) && 1206 (absolute_value != 0.0) ) { 1207 /* Use scientific notation */ 1208 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 1209 fraction_place = DBL_DIG - 1; 1210 snprintf(work, sizeof(work),"%*.*e", 1211 integer_place, fraction_place, number); 1212 after_fraction = strchr(work + DBL_DIG, 'e'); 1213 } 1214 else { 1215 /* Use regular notation */ 1216 if (absolute_value > 0.0) 1217 integer_place = 1 + (int)log10(absolute_value); 1218 else 1219 integer_place = 0; 1220 fraction_place = (integer_place > 0) 1221 ? DBL_DIG - integer_place 1222 : DBL_DIG; 1223 size = snprintf(work, sizeof(work), "%0.*f", 1224 fraction_place, number); 1225 after_fraction = work + size; 1226 } 1227 1228 /* Remove fractional trailing zeroes */ 1229 ptr = after_fraction; 1230 while (*(--ptr) == '0') 1231 ; 1232 if (*ptr != '.') 1233 ptr++; 1234 strcpy(ptr, after_fraction); 1235 1236 /* Finally copy result back to caller */ 1237 size = strlen(work) + 1; 1238 if (size > buffersize) { 1239 work[buffersize - 1] = 0; 1240 size = buffersize; 1241 } 1242 memcpy(buffer, work, size); 1243 } 1244 break; 1245 } 1246} 1247 1248/************************************************************************ 1249 * * 1250 * Error handling routines * 1251 * * 1252 ************************************************************************/ 1253 1254 1255static const char *xmlXPathErrorMessages[] = { 1256 "Ok", 1257 "Number encoding", 1258 "Unfinished literal", 1259 "Start of literal", 1260 "Expected $ for variable reference", 1261 "Undefined variable", 1262 "Invalid predicate", 1263 "Invalid expression", 1264 "Missing closing curly brace", 1265 "Unregistered function", 1266 "Invalid operand", 1267 "Invalid type", 1268 "Invalid number of arguments", 1269 "Invalid context size", 1270 "Invalid context position", 1271 "Memory allocation error", 1272 "Syntax error", 1273 "Resource error", 1274 "Sub resource error", 1275 "Undefined namespace prefix", 1276 "Encoding error", 1277 "Char out of XML range" 1278}; 1279 1280/** 1281 * xmlXPatherror: 1282 * @ctxt: the XPath Parser context 1283 * @file: the file name 1284 * @line: the line number 1285 * @no: the error number 1286 * 1287 * Formats an error message. 1288 */ 1289void 1290xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 1291 int line ATTRIBUTE_UNUSED, int no) { 1292 int n; 1293 const xmlChar *cur; 1294 const xmlChar *base; 1295 1296 cur = ctxt->cur; 1297 base = ctxt->base; 1298 if ((cur == NULL) || (base == NULL)) { 1299 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) { 1300 xmlGenericError(xmlGenericErrorContext, 1301 "XPath error %s in %s\n", xmlXPathErrorMessages[no], 1302 ctxt->comp->expr); 1303 } else { 1304 xmlGenericError(xmlGenericErrorContext, 1305 "XPath error %s\n", xmlXPathErrorMessages[no]); 1306 } 1307 1308 return; 1309 } 1310 xmlGenericError(xmlGenericErrorContext, 1311 "XPath error %s\n", xmlXPathErrorMessages[no]); 1312 1313 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) { 1314 cur--; 1315 } 1316 n = 0; 1317 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r')) 1318 cur--; 1319 if ((*cur == '\n') || (*cur == '\r')) cur++; 1320 base = cur; 1321 n = 0; 1322 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) { 1323 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++); 1324 n++; 1325 } 1326 xmlGenericError(xmlGenericErrorContext, "\n"); 1327 cur = ctxt->cur; 1328 while ((*cur == '\n') || (*cur == '\r')) 1329 cur--; 1330 n = 0; 1331 while ((cur != base) && (n++ < 80)) { 1332 xmlGenericError(xmlGenericErrorContext, " "); 1333 base++; 1334 } 1335 xmlGenericError(xmlGenericErrorContext,"^\n"); 1336} 1337 1338 1339/************************************************************************ 1340 * * 1341 * Routines to handle NodeSets * 1342 * * 1343 ************************************************************************/ 1344 1345/** 1346 * xmlXPathOrderDocElems: 1347 * @doc: an input document 1348 * 1349 * Call this routine to speed up XPath computation on static documents. 1350 * This stamps all the element nodes with the document order 1351 * Like for line information, the order is kept in the element->content 1352 * field, the value stored is actually - the node number (startting at -1) 1353 * to be able to differenciate from line numbers. 1354 * 1355 * Returns the number of element found in the document or -1 in case 1356 * of error. 1357 */ 1358long 1359xmlXPathOrderDocElems(xmlDocPtr doc) { 1360 long count = 0; 1361 xmlNodePtr cur; 1362 1363 if (doc == NULL) 1364 return(-1); 1365 cur = doc->children; 1366 while (cur != NULL) { 1367 if (cur->type == XML_ELEMENT_NODE) { 1368 cur->content = (void *) (-(++count)); 1369 if (cur->children != NULL) { 1370 cur = cur->children; 1371 continue; 1372 } 1373 } 1374 if (cur->next != NULL) { 1375 cur = cur->next; 1376 continue; 1377 } 1378 do { 1379 cur = cur->parent; 1380 if (cur == NULL) 1381 break; 1382 if (cur == (xmlNodePtr) doc) { 1383 cur = NULL; 1384 break; 1385 } 1386 if (cur->next != NULL) { 1387 cur = cur->next; 1388 break; 1389 } 1390 } while (cur != NULL); 1391 } 1392 return(count); 1393} 1394 1395/** 1396 * xmlXPathCmpNodes: 1397 * @node1: the first node 1398 * @node2: the second node 1399 * 1400 * Compare two nodes w.r.t document order 1401 * 1402 * Returns -2 in case of error 1 if first point < second point, 0 if 1403 * that's the same node, -1 otherwise 1404 */ 1405int 1406xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 1407 int depth1, depth2; 1408 int attr1 = 0, attr2 = 0; 1409 xmlNodePtr cur, root; 1410 1411 if ((node1 == NULL) || (node2 == NULL)) 1412 return(-2); 1413 /* 1414 * a couple of optimizations which will avoid computations in most cases 1415 */ 1416 if (node1->type == XML_ATTRIBUTE_NODE) { 1417 attr1 = 1; 1418 node1 = node1->parent; 1419 } 1420 if (node2->type == XML_ATTRIBUTE_NODE) { 1421 attr2 = 1; 1422 node2 = node2->parent; 1423 } 1424 if (node1 == node2) { 1425 if (attr1 == attr2) 1426 return(0); 1427 if (attr2 == 1) 1428 return(1); 1429 return(-1); 1430 } 1431 if ((node1->type == XML_NAMESPACE_DECL) || 1432 (node2->type == XML_NAMESPACE_DECL)) 1433 return(1); 1434 if (node1 == node2->prev) 1435 return(1); 1436 if (node1 == node2->next) 1437 return(-1); 1438 1439 /* 1440 * Speedup using document order if availble. 1441 */ 1442 if ((node1->type == XML_ELEMENT_NODE) && 1443 (node2->type == XML_ELEMENT_NODE) && 1444 (0 > (long) node1->content) && 1445 (0 > (long) node2->content) && 1446 (node1->doc == node2->doc)) { 1447 long l1, l2; 1448 1449 l1 = -((long) node1->content); 1450 l2 = -((long) node2->content); 1451 if (l1 < l2) 1452 return(1); 1453 if (l1 > l2) 1454 return(-1); 1455 } 1456 1457 /* 1458 * compute depth to root 1459 */ 1460 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 1461 if (cur == node1) 1462 return(1); 1463 depth2++; 1464 } 1465 root = cur; 1466 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 1467 if (cur == node2) 1468 return(-1); 1469 depth1++; 1470 } 1471 /* 1472 * Distinct document (or distinct entities :-( ) case. 1473 */ 1474 if (root != cur) { 1475 return(-2); 1476 } 1477 /* 1478 * get the nearest common ancestor. 1479 */ 1480 while (depth1 > depth2) { 1481 depth1--; 1482 node1 = node1->parent; 1483 } 1484 while (depth2 > depth1) { 1485 depth2--; 1486 node2 = node2->parent; 1487 } 1488 while (node1->parent != node2->parent) { 1489 node1 = node1->parent; 1490 node2 = node2->parent; 1491 /* should not happen but just in case ... */ 1492 if ((node1 == NULL) || (node2 == NULL)) 1493 return(-2); 1494 } 1495 /* 1496 * Find who's first. 1497 */ 1498 if (node1 == node2->next) 1499 return(-1); 1500 for (cur = node1->next;cur != NULL;cur = cur->next) 1501 if (cur == node2) 1502 return(1); 1503 return(-1); /* assume there is no sibling list corruption */ 1504} 1505 1506/** 1507 * xmlXPathNodeSetSort: 1508 * @set: the node set 1509 * 1510 * Sort the node set in document order 1511 */ 1512void 1513xmlXPathNodeSetSort(xmlNodeSetPtr set) { 1514 int i, j, incr, len; 1515 xmlNodePtr tmp; 1516 1517 if (set == NULL) 1518 return; 1519 1520 /* Use Shell's sort to sort the node-set */ 1521 len = set->nodeNr; 1522 for (incr = len / 2; incr > 0; incr /= 2) { 1523 for (i = incr; i < len; i++) { 1524 j = i - incr; 1525 while (j >= 0) { 1526 if (xmlXPathCmpNodes(set->nodeTab[j], 1527 set->nodeTab[j + incr]) == -1) { 1528 tmp = set->nodeTab[j]; 1529 set->nodeTab[j] = set->nodeTab[j + incr]; 1530 set->nodeTab[j + incr] = tmp; 1531 j -= incr; 1532 } else 1533 break; 1534 } 1535 } 1536 } 1537} 1538 1539#define XML_NODESET_DEFAULT 10 1540/** 1541 * xmlXPathNodeSetDupNs: 1542 * @node: the parent node of the namespace XPath node 1543 * @ns: the libxml namespace declaration node. 1544 * 1545 * Namespace node in libxml don't match the XPath semantic. In a node set 1546 * the namespace nodes are duplicated and the next pointer is set to the 1547 * parent node in the XPath semantic. 1548 * 1549 * Returns the newly created object. 1550 */ 1551static xmlNodePtr 1552xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 1553 xmlNsPtr cur; 1554 1555 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 1556 return(NULL); 1557 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 1558 return((xmlNodePtr) ns); 1559 1560 /* 1561 * Allocate a new Namespace and fill the fields. 1562 */ 1563 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 1564 if (cur == NULL) { 1565 xmlGenericError(xmlGenericErrorContext, 1566 "xmlXPathNodeSetDupNs : malloc failed\n"); 1567 return(NULL); 1568 } 1569 memset(cur, 0, sizeof(xmlNs)); 1570 cur->type = XML_NAMESPACE_DECL; 1571 if (ns->href != NULL) 1572 cur->href = xmlStrdup(ns->href); 1573 if (ns->prefix != NULL) 1574 cur->prefix = xmlStrdup(ns->prefix); 1575 cur->next = (xmlNsPtr) node; 1576 return((xmlNodePtr) cur); 1577} 1578 1579/** 1580 * xmlXPathNodeSetFreeNs: 1581 * @ns: the XPath namespace node found in a nodeset. 1582 * 1583 * Namespace node in libxml don't match the XPath semantic. In a node set 1584 * the namespace nodes are duplicated and the next pointer is set to the 1585 * parent node in the XPath semantic. Check if such a node need to be freed 1586 */ 1587void 1588xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 1589 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 1590 return; 1591 1592 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 1593 if (ns->href != NULL) 1594 xmlFree((xmlChar *)ns->href); 1595 if (ns->prefix != NULL) 1596 xmlFree((xmlChar *)ns->prefix); 1597 xmlFree(ns); 1598 } 1599} 1600 1601/** 1602 * xmlXPathNodeSetCreate: 1603 * @val: an initial xmlNodePtr, or NULL 1604 * 1605 * Create a new xmlNodeSetPtr of type double and of value @val 1606 * 1607 * Returns the newly created object. 1608 */ 1609xmlNodeSetPtr 1610xmlXPathNodeSetCreate(xmlNodePtr val) { 1611 xmlNodeSetPtr ret; 1612 1613 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 1614 if (ret == NULL) { 1615 xmlGenericError(xmlGenericErrorContext, 1616 "xmlXPathNodeSetCreate: out of memory\n"); 1617 return(NULL); 1618 } 1619 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 1620 if (val != NULL) { 1621 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1622 sizeof(xmlNodePtr)); 1623 if (ret->nodeTab == NULL) { 1624 xmlGenericError(xmlGenericErrorContext, 1625 "xmlXPathNodeSetCreate: out of memory\n"); 1626 return(NULL); 1627 } 1628 memset(ret->nodeTab, 0 , 1629 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1630 ret->nodeMax = XML_NODESET_DEFAULT; 1631 if (val->type == XML_NAMESPACE_DECL) { 1632 xmlNsPtr ns = (xmlNsPtr) val; 1633 1634 ret->nodeTab[ret->nodeNr++] = 1635 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 1636 } else 1637 ret->nodeTab[ret->nodeNr++] = val; 1638 } 1639 return(ret); 1640} 1641 1642/** 1643 * xmlXPathNodeSetContains: 1644 * @cur: the node-set 1645 * @val: the node 1646 * 1647 * checks whether @cur contains @val 1648 * 1649 * Returns true (1) if @cur contains @val, false (0) otherwise 1650 */ 1651int 1652xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 1653 int i; 1654 1655 if (val->type == XML_NAMESPACE_DECL) { 1656 for (i = 0; i < cur->nodeNr; i++) { 1657 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 1658 xmlNsPtr ns1, ns2; 1659 1660 ns1 = (xmlNsPtr) val; 1661 ns2 = (xmlNsPtr) cur->nodeTab[i]; 1662 if (ns1 == ns2) 1663 return(1); 1664 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 1665 (xmlStrEqual(ns1->prefix, ns2->prefix))) 1666 return(1); 1667 } 1668 } 1669 } else { 1670 for (i = 0; i < cur->nodeNr; i++) { 1671 if (cur->nodeTab[i] == val) 1672 return(1); 1673 } 1674 } 1675 return(0); 1676} 1677 1678/** 1679 * xmlXPathNodeSetAddNs: 1680 * @cur: the initial node set 1681 * @node: the hosting node 1682 * @ns: a the namespace node 1683 * 1684 * add a new namespace node to an existing NodeSet 1685 */ 1686void 1687xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 1688 int i; 1689 1690 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) || 1691 (node->type != XML_ELEMENT_NODE)) 1692 return; 1693 1694 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 1695 /* 1696 * check against doublons 1697 */ 1698 for (i = 0;i < cur->nodeNr;i++) { 1699 if ((cur->nodeTab[i] != NULL) && 1700 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 1701 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 1702 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 1703 return; 1704 } 1705 1706 /* 1707 * grow the nodeTab if needed 1708 */ 1709 if (cur->nodeMax == 0) { 1710 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1711 sizeof(xmlNodePtr)); 1712 if (cur->nodeTab == NULL) { 1713 xmlGenericError(xmlGenericErrorContext, 1714 "xmlXPathNodeSetAdd: out of memory\n"); 1715 return; 1716 } 1717 memset(cur->nodeTab, 0 , 1718 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1719 cur->nodeMax = XML_NODESET_DEFAULT; 1720 } else if (cur->nodeNr == cur->nodeMax) { 1721 xmlNodePtr *temp; 1722 1723 cur->nodeMax *= 2; 1724 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 1725 sizeof(xmlNodePtr)); 1726 if (temp == NULL) { 1727 xmlGenericError(xmlGenericErrorContext, 1728 "xmlXPathNodeSetAdd: out of memory\n"); 1729 return; 1730 } 1731 cur->nodeTab = temp; 1732 } 1733 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 1734} 1735 1736/** 1737 * xmlXPathNodeSetAdd: 1738 * @cur: the initial node set 1739 * @val: a new xmlNodePtr 1740 * 1741 * add a new xmlNodePtr to an existing NodeSet 1742 */ 1743void 1744xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 1745 int i; 1746 1747 if (val == NULL) return; 1748 1749#if 0 1750 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 1751 return; /* an XSLT fake node */ 1752#endif 1753 1754 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 1755 /* 1756 * check against doublons 1757 */ 1758 for (i = 0;i < cur->nodeNr;i++) 1759 if (cur->nodeTab[i] == val) return; 1760 1761 /* 1762 * grow the nodeTab if needed 1763 */ 1764 if (cur->nodeMax == 0) { 1765 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1766 sizeof(xmlNodePtr)); 1767 if (cur->nodeTab == NULL) { 1768 xmlGenericError(xmlGenericErrorContext, 1769 "xmlXPathNodeSetAdd: out of memory\n"); 1770 return; 1771 } 1772 memset(cur->nodeTab, 0 , 1773 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1774 cur->nodeMax = XML_NODESET_DEFAULT; 1775 } else if (cur->nodeNr == cur->nodeMax) { 1776 xmlNodePtr *temp; 1777 1778 cur->nodeMax *= 2; 1779 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 1780 sizeof(xmlNodePtr)); 1781 if (temp == NULL) { 1782 xmlGenericError(xmlGenericErrorContext, 1783 "xmlXPathNodeSetAdd: out of memory\n"); 1784 return; 1785 } 1786 cur->nodeTab = temp; 1787 } 1788 if (val->type == XML_NAMESPACE_DECL) { 1789 xmlNsPtr ns = (xmlNsPtr) val; 1790 1791 cur->nodeTab[cur->nodeNr++] = 1792 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 1793 } else 1794 cur->nodeTab[cur->nodeNr++] = val; 1795} 1796 1797/** 1798 * xmlXPathNodeSetAddUnique: 1799 * @cur: the initial node set 1800 * @val: a new xmlNodePtr 1801 * 1802 * add a new xmlNodePtr to an existing NodeSet, optimized version 1803 * when we are sure the node is not already in the set. 1804 */ 1805void 1806xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 1807 if (val == NULL) return; 1808 1809#if 0 1810 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 1811 return; /* an XSLT fake node */ 1812#endif 1813 1814 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 1815 /* 1816 * grow the nodeTab if needed 1817 */ 1818 if (cur->nodeMax == 0) { 1819 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1820 sizeof(xmlNodePtr)); 1821 if (cur->nodeTab == NULL) { 1822 xmlGenericError(xmlGenericErrorContext, 1823 "xmlXPathNodeSetAddUnique: out of memory\n"); 1824 return; 1825 } 1826 memset(cur->nodeTab, 0 , 1827 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1828 cur->nodeMax = XML_NODESET_DEFAULT; 1829 } else if (cur->nodeNr == cur->nodeMax) { 1830 xmlNodePtr *temp; 1831 1832 cur->nodeMax *= 2; 1833 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 1834 sizeof(xmlNodePtr)); 1835 if (temp == NULL) { 1836 xmlGenericError(xmlGenericErrorContext, 1837 "xmlXPathNodeSetAddUnique: out of memory\n"); 1838 return; 1839 } 1840 cur->nodeTab = temp; 1841 } 1842 if (val->type == XML_NAMESPACE_DECL) { 1843 xmlNsPtr ns = (xmlNsPtr) val; 1844 1845 cur->nodeTab[cur->nodeNr++] = 1846 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 1847 } else 1848 cur->nodeTab[cur->nodeNr++] = val; 1849} 1850 1851/** 1852 * xmlXPathNodeSetMerge: 1853 * @val1: the first NodeSet or NULL 1854 * @val2: the second NodeSet 1855 * 1856 * Merges two nodesets, all nodes from @val2 are added to @val1 1857 * if @val1 is NULL, a new set is created and copied from @val2 1858 * 1859 * Returns @val1 once extended or NULL in case of error. 1860 */ 1861xmlNodeSetPtr 1862xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 1863 int i, j, initNr, skip; 1864 1865 if (val2 == NULL) return(val1); 1866 if (val1 == NULL) { 1867 val1 = xmlXPathNodeSetCreate(NULL); 1868 } 1869 1870 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 1871 initNr = val1->nodeNr; 1872 1873 for (i = 0;i < val2->nodeNr;i++) { 1874 /* 1875 * check against doublons 1876 */ 1877 skip = 0; 1878 for (j = 0; j < initNr; j++) { 1879 if (val1->nodeTab[j] == val2->nodeTab[i]) { 1880 skip = 1; 1881 break; 1882 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) && 1883 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) { 1884 xmlNsPtr ns1, ns2; 1885 ns1 = (xmlNsPtr) val1->nodeTab[j]; 1886 ns2 = (xmlNsPtr) val2->nodeTab[i]; 1887 if ((ns1->next == ns2->next) && 1888 (xmlStrEqual(ns1->prefix, ns2->prefix))) { 1889 skip = 1; 1890 break; 1891 } 1892 } 1893 } 1894 if (skip) 1895 continue; 1896 1897 /* 1898 * grow the nodeTab if needed 1899 */ 1900 if (val1->nodeMax == 0) { 1901 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1902 sizeof(xmlNodePtr)); 1903 if (val1->nodeTab == NULL) { 1904 xmlGenericError(xmlGenericErrorContext, 1905 "xmlXPathNodeSetMerge: out of memory\n"); 1906 return(NULL); 1907 } 1908 memset(val1->nodeTab, 0 , 1909 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1910 val1->nodeMax = XML_NODESET_DEFAULT; 1911 } else if (val1->nodeNr == val1->nodeMax) { 1912 xmlNodePtr *temp; 1913 1914 val1->nodeMax *= 2; 1915 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 1916 sizeof(xmlNodePtr)); 1917 if (temp == NULL) { 1918 xmlGenericError(xmlGenericErrorContext, 1919 "xmlXPathNodeSetMerge: out of memory\n"); 1920 return(NULL); 1921 } 1922 val1->nodeTab = temp; 1923 } 1924 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { 1925 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; 1926 1927 val1->nodeTab[val1->nodeNr++] = 1928 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 1929 } else 1930 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; 1931 } 1932 1933 return(val1); 1934} 1935 1936/** 1937 * xmlXPathNodeSetMergeUnique: 1938 * @val1: the first NodeSet or NULL 1939 * @val2: the second NodeSet 1940 * 1941 * Merges two nodesets, all nodes from @val2 are added to @val1 1942 * if @val1 is NULL, a new set is created and copied from @val2 1943 * 1944 * Returns @val1 once extended or NULL in case of error. 1945 */ 1946static xmlNodeSetPtr 1947xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 1948 int i; 1949 1950 if (val2 == NULL) return(val1); 1951 if (val1 == NULL) { 1952 val1 = xmlXPathNodeSetCreate(NULL); 1953 } 1954 1955 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 1956 1957 for (i = 0;i < val2->nodeNr;i++) { 1958 /* 1959 * grow the nodeTab if needed 1960 */ 1961 if (val1->nodeMax == 0) { 1962 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1963 sizeof(xmlNodePtr)); 1964 if (val1->nodeTab == NULL) { 1965 xmlGenericError(xmlGenericErrorContext, 1966 "xmlXPathNodeSetMerge: out of memory\n"); 1967 return(NULL); 1968 } 1969 memset(val1->nodeTab, 0 , 1970 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1971 val1->nodeMax = XML_NODESET_DEFAULT; 1972 } else if (val1->nodeNr == val1->nodeMax) { 1973 xmlNodePtr *temp; 1974 1975 val1->nodeMax *= 2; 1976 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 1977 sizeof(xmlNodePtr)); 1978 if (temp == NULL) { 1979 xmlGenericError(xmlGenericErrorContext, 1980 "xmlXPathNodeSetMerge: out of memory\n"); 1981 return(NULL); 1982 } 1983 val1->nodeTab = temp; 1984 } 1985 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { 1986 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; 1987 1988 val1->nodeTab[val1->nodeNr++] = 1989 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 1990 } else 1991 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; 1992 } 1993 1994 return(val1); 1995} 1996 1997/** 1998 * xmlXPathNodeSetDel: 1999 * @cur: the initial node set 2000 * @val: an xmlNodePtr 2001 * 2002 * Removes an xmlNodePtr from an existing NodeSet 2003 */ 2004void 2005xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 2006 int i; 2007 2008 if (cur == NULL) return; 2009 if (val == NULL) return; 2010 2011 /* 2012 * check against doublons 2013 */ 2014 for (i = 0;i < cur->nodeNr;i++) 2015 if (cur->nodeTab[i] == val) break; 2016 2017 if (i >= cur->nodeNr) { 2018#ifdef DEBUG 2019 xmlGenericError(xmlGenericErrorContext, 2020 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 2021 val->name); 2022#endif 2023 return; 2024 } 2025 if ((cur->nodeTab[i] != NULL) && 2026 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 2027 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 2028 cur->nodeNr--; 2029 for (;i < cur->nodeNr;i++) 2030 cur->nodeTab[i] = cur->nodeTab[i + 1]; 2031 cur->nodeTab[cur->nodeNr] = NULL; 2032} 2033 2034/** 2035 * xmlXPathNodeSetRemove: 2036 * @cur: the initial node set 2037 * @val: the index to remove 2038 * 2039 * Removes an entry from an existing NodeSet list. 2040 */ 2041void 2042xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 2043 if (cur == NULL) return; 2044 if (val >= cur->nodeNr) return; 2045 if ((cur->nodeTab[val] != NULL) && 2046 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 2047 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 2048 cur->nodeNr--; 2049 for (;val < cur->nodeNr;val++) 2050 cur->nodeTab[val] = cur->nodeTab[val + 1]; 2051 cur->nodeTab[cur->nodeNr] = NULL; 2052} 2053 2054/** 2055 * xmlXPathFreeNodeSet: 2056 * @obj: the xmlNodeSetPtr to free 2057 * 2058 * Free the NodeSet compound (not the actual nodes !). 2059 */ 2060void 2061xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 2062 if (obj == NULL) return; 2063 if (obj->nodeTab != NULL) { 2064 int i; 2065 2066 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 2067 for (i = 0;i < obj->nodeNr;i++) 2068 if ((obj->nodeTab[i] != NULL) && 2069 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 2070 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 2071 xmlFree(obj->nodeTab); 2072 } 2073 xmlFree(obj); 2074} 2075 2076/** 2077 * xmlXPathFreeValueTree: 2078 * @obj: the xmlNodeSetPtr to free 2079 * 2080 * Free the NodeSet compound and the actual tree, this is different 2081 * from xmlXPathFreeNodeSet() 2082 */ 2083static void 2084xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 2085 int i; 2086 2087 if (obj == NULL) return; 2088 2089 if (obj->nodeTab != NULL) { 2090 for (i = 0;i < obj->nodeNr;i++) { 2091 if (obj->nodeTab[i] != NULL) { 2092 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 2093 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 2094 } else { 2095 xmlFreeNodeList(obj->nodeTab[i]); 2096 } 2097 } 2098 } 2099 xmlFree(obj->nodeTab); 2100 } 2101 xmlFree(obj); 2102} 2103 2104#if defined(DEBUG) || defined(DEBUG_STEP) 2105/** 2106 * xmlGenericErrorContextNodeSet: 2107 * @output: a FILE * for the output 2108 * @obj: the xmlNodeSetPtr to free 2109 * 2110 * Quick display of a NodeSet 2111 */ 2112void 2113xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 2114 int i; 2115 2116 if (output == NULL) output = xmlGenericErrorContext; 2117 if (obj == NULL) { 2118 fprintf(output, "NodeSet == NULL !\n"); 2119 return; 2120 } 2121 if (obj->nodeNr == 0) { 2122 fprintf(output, "NodeSet is empty\n"); 2123 return; 2124 } 2125 if (obj->nodeTab == NULL) { 2126 fprintf(output, " nodeTab == NULL !\n"); 2127 return; 2128 } 2129 for (i = 0; i < obj->nodeNr; i++) { 2130 if (obj->nodeTab[i] == NULL) { 2131 fprintf(output, " NULL !\n"); 2132 return; 2133 } 2134 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 2135 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 2136 fprintf(output, " /"); 2137 else if (obj->nodeTab[i]->name == NULL) 2138 fprintf(output, " noname!"); 2139 else fprintf(output, " %s", obj->nodeTab[i]->name); 2140 } 2141 fprintf(output, "\n"); 2142} 2143#endif 2144 2145/** 2146 * xmlXPathNewNodeSet: 2147 * @val: the NodePtr value 2148 * 2149 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 2150 * it with the single Node @val 2151 * 2152 * Returns the newly created object. 2153 */ 2154xmlXPathObjectPtr 2155xmlXPathNewNodeSet(xmlNodePtr val) { 2156 xmlXPathObjectPtr ret; 2157 2158 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 2159 if (ret == NULL) { 2160 xmlGenericError(xmlGenericErrorContext, 2161 "xmlXPathNewNodeSet: out of memory\n"); 2162 return(NULL); 2163 } 2164 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 2165 ret->type = XPATH_NODESET; 2166 ret->boolval = 0; 2167 ret->nodesetval = xmlXPathNodeSetCreate(val); 2168 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 2169 return(ret); 2170} 2171 2172/** 2173 * xmlXPathNewValueTree: 2174 * @val: the NodePtr value 2175 * 2176 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 2177 * it with the tree root @val 2178 * 2179 * Returns the newly created object. 2180 */ 2181xmlXPathObjectPtr 2182xmlXPathNewValueTree(xmlNodePtr val) { 2183 xmlXPathObjectPtr ret; 2184 2185 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 2186 if (ret == NULL) { 2187 xmlGenericError(xmlGenericErrorContext, 2188 "xmlXPathNewNodeSet: out of memory\n"); 2189 return(NULL); 2190 } 2191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 2192 ret->type = XPATH_XSLT_TREE; 2193 ret->boolval = 1; 2194 ret->user = (void *) val; 2195 ret->nodesetval = xmlXPathNodeSetCreate(val); 2196 return(ret); 2197} 2198 2199/** 2200 * xmlXPathNewNodeSetList: 2201 * @val: an existing NodeSet 2202 * 2203 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 2204 * it with the Nodeset @val 2205 * 2206 * Returns the newly created object. 2207 */ 2208xmlXPathObjectPtr 2209xmlXPathNewNodeSetList(xmlNodeSetPtr val) 2210{ 2211 xmlXPathObjectPtr ret; 2212 int i; 2213 2214 if (val == NULL) 2215 ret = NULL; 2216 else if (val->nodeTab == NULL) 2217 ret = xmlXPathNewNodeSet(NULL); 2218 else { 2219 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 2220 for (i = 1; i < val->nodeNr; ++i) 2221 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]); 2222 } 2223 2224 return (ret); 2225} 2226 2227/** 2228 * xmlXPathWrapNodeSet: 2229 * @val: the NodePtr value 2230 * 2231 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 2232 * 2233 * Returns the newly created object. 2234 */ 2235xmlXPathObjectPtr 2236xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 2237 xmlXPathObjectPtr ret; 2238 2239 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 2240 if (ret == NULL) { 2241 xmlGenericError(xmlGenericErrorContext, 2242 "xmlXPathWrapNodeSet: out of memory\n"); 2243 return(NULL); 2244 } 2245 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 2246 ret->type = XPATH_NODESET; 2247 ret->nodesetval = val; 2248 return(ret); 2249} 2250 2251/** 2252 * xmlXPathFreeNodeSetList: 2253 * @obj: an existing NodeSetList object 2254 * 2255 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 2256 * the list contrary to xmlXPathFreeObject(). 2257 */ 2258void 2259xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 2260 if (obj == NULL) return; 2261 xmlFree(obj); 2262} 2263 2264/** 2265 * xmlXPathDifference: 2266 * @nodes1: a node-set 2267 * @nodes2: a node-set 2268 * 2269 * Implements the EXSLT - Sets difference() function: 2270 * node-set set:difference (node-set, node-set) 2271 * 2272 * Returns the difference between the two node sets, or nodes1 if 2273 * nodes2 is empty 2274 */ 2275xmlNodeSetPtr 2276xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2277 xmlNodeSetPtr ret; 2278 int i, l1; 2279 xmlNodePtr cur; 2280 2281 if (xmlXPathNodeSetIsEmpty(nodes2)) 2282 return(nodes1); 2283 2284 ret = xmlXPathNodeSetCreate(NULL); 2285 if (xmlXPathNodeSetIsEmpty(nodes1)) 2286 return(ret); 2287 2288 l1 = xmlXPathNodeSetGetLength(nodes1); 2289 2290 for (i = 0; i < l1; i++) { 2291 cur = xmlXPathNodeSetItem(nodes1, i); 2292 if (!xmlXPathNodeSetContains(nodes2, cur)) 2293 xmlXPathNodeSetAddUnique(ret, cur); 2294 } 2295 return(ret); 2296} 2297 2298/** 2299 * xmlXPathIntersection: 2300 * @nodes1: a node-set 2301 * @nodes2: a node-set 2302 * 2303 * Implements the EXSLT - Sets intersection() function: 2304 * node-set set:intersection (node-set, node-set) 2305 * 2306 * Returns a node set comprising the nodes that are within both the 2307 * node sets passed as arguments 2308 */ 2309xmlNodeSetPtr 2310xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2311 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 2312 int i, l1; 2313 xmlNodePtr cur; 2314 2315 if (xmlXPathNodeSetIsEmpty(nodes1)) 2316 return(ret); 2317 if (xmlXPathNodeSetIsEmpty(nodes2)) 2318 return(ret); 2319 2320 l1 = xmlXPathNodeSetGetLength(nodes1); 2321 2322 for (i = 0; i < l1; i++) { 2323 cur = xmlXPathNodeSetItem(nodes1, i); 2324 if (xmlXPathNodeSetContains(nodes2, cur)) 2325 xmlXPathNodeSetAddUnique(ret, cur); 2326 } 2327 return(ret); 2328} 2329 2330/** 2331 * xmlXPathDistinctSorted: 2332 * @nodes: a node-set, sorted by document order 2333 * 2334 * Implements the EXSLT - Sets distinct() function: 2335 * node-set set:distinct (node-set) 2336 * 2337 * Returns a subset of the nodes contained in @nodes, or @nodes if 2338 * it is empty 2339 */ 2340xmlNodeSetPtr 2341xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 2342 xmlNodeSetPtr ret; 2343 xmlHashTablePtr hash; 2344 int i, l; 2345 xmlChar * strval; 2346 xmlNodePtr cur; 2347 2348 if (xmlXPathNodeSetIsEmpty(nodes)) 2349 return(nodes); 2350 2351 ret = xmlXPathNodeSetCreate(NULL); 2352 l = xmlXPathNodeSetGetLength(nodes); 2353 hash = xmlHashCreate (l); 2354 for (i = 0; i < l; i++) { 2355 cur = xmlXPathNodeSetItem(nodes, i); 2356 strval = xmlXPathCastNodeToString(cur); 2357 if (xmlHashLookup(hash, strval) == NULL) { 2358 xmlHashAddEntry(hash, strval, strval); 2359 xmlXPathNodeSetAddUnique(ret, cur); 2360 } else { 2361 xmlFree(strval); 2362 } 2363 } 2364 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 2365 return(ret); 2366} 2367 2368/** 2369 * xmlXPathDistinct: 2370 * @nodes: a node-set 2371 * 2372 * Implements the EXSLT - Sets distinct() function: 2373 * node-set set:distinct (node-set) 2374 * @nodes is sorted by document order, then #exslSetsDistinctSorted 2375 * is called with the sorted node-set 2376 * 2377 * Returns a subset of the nodes contained in @nodes, or @nodes if 2378 * it is empty 2379 */ 2380xmlNodeSetPtr 2381xmlXPathDistinct (xmlNodeSetPtr nodes) { 2382 if (xmlXPathNodeSetIsEmpty(nodes)) 2383 return(nodes); 2384 2385 xmlXPathNodeSetSort(nodes); 2386 return(xmlXPathDistinctSorted(nodes)); 2387} 2388 2389/** 2390 * xmlXPathHasSameNodes: 2391 * @nodes1: a node-set 2392 * @nodes2: a node-set 2393 * 2394 * Implements the EXSLT - Sets has-same-nodes function: 2395 * boolean set:has-same-node(node-set, node-set) 2396 * 2397 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 2398 * otherwise 2399 */ 2400int 2401xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2402 int i, l; 2403 xmlNodePtr cur; 2404 2405 if (xmlXPathNodeSetIsEmpty(nodes1) || 2406 xmlXPathNodeSetIsEmpty(nodes2)) 2407 return(0); 2408 2409 l = xmlXPathNodeSetGetLength(nodes1); 2410 for (i = 0; i < l; i++) { 2411 cur = xmlXPathNodeSetItem(nodes1, i); 2412 if (xmlXPathNodeSetContains(nodes2, cur)) 2413 return(1); 2414 } 2415 return(0); 2416} 2417 2418/** 2419 * xmlXPathNodeLeadingSorted: 2420 * @nodes: a node-set, sorted by document order 2421 * @node: a node 2422 * 2423 * Implements the EXSLT - Sets leading() function: 2424 * node-set set:leading (node-set, node-set) 2425 * 2426 * Returns the nodes in @nodes that precede @node in document order, 2427 * @nodes if @node is NULL or an empty node-set if @nodes 2428 * doesn't contain @node 2429 */ 2430xmlNodeSetPtr 2431xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 2432 int i, l; 2433 xmlNodePtr cur; 2434 xmlNodeSetPtr ret; 2435 2436 if (node == NULL) 2437 return(nodes); 2438 2439 ret = xmlXPathNodeSetCreate(NULL); 2440 if (xmlXPathNodeSetIsEmpty(nodes) || 2441 (!xmlXPathNodeSetContains(nodes, node))) 2442 return(ret); 2443 2444 l = xmlXPathNodeSetGetLength(nodes); 2445 for (i = 0; i < l; i++) { 2446 cur = xmlXPathNodeSetItem(nodes, i); 2447 if (cur == node) 2448 break; 2449 xmlXPathNodeSetAddUnique(ret, cur); 2450 } 2451 return(ret); 2452} 2453 2454/** 2455 * xmlXPathNodeLeading: 2456 * @nodes: a node-set 2457 * @node: a node 2458 * 2459 * Implements the EXSLT - Sets leading() function: 2460 * node-set set:leading (node-set, node-set) 2461 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 2462 * is called. 2463 * 2464 * Returns the nodes in @nodes that precede @node in document order, 2465 * @nodes if @node is NULL or an empty node-set if @nodes 2466 * doesn't contain @node 2467 */ 2468xmlNodeSetPtr 2469xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 2470 xmlXPathNodeSetSort(nodes); 2471 return(xmlXPathNodeLeadingSorted(nodes, node)); 2472} 2473 2474/** 2475 * xmlXPathLeadingSorted: 2476 * @nodes1: a node-set, sorted by document order 2477 * @nodes2: a node-set, sorted by document order 2478 * 2479 * Implements the EXSLT - Sets leading() function: 2480 * node-set set:leading (node-set, node-set) 2481 * 2482 * Returns the nodes in @nodes1 that precede the first node in @nodes2 2483 * in document order, @nodes1 if @nodes2 is NULL or empty or 2484 * an empty node-set if @nodes1 doesn't contain @nodes2 2485 */ 2486xmlNodeSetPtr 2487xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2488 if (xmlXPathNodeSetIsEmpty(nodes2)) 2489 return(nodes1); 2490 return(xmlXPathNodeLeadingSorted(nodes1, 2491 xmlXPathNodeSetItem(nodes2, 1))); 2492} 2493 2494/** 2495 * xmlXPathLeading: 2496 * @nodes1: a node-set 2497 * @nodes2: a node-set 2498 * 2499 * Implements the EXSLT - Sets leading() function: 2500 * node-set set:leading (node-set, node-set) 2501 * @nodes1 and @nodes2 are sorted by document order, then 2502 * #exslSetsLeadingSorted is called. 2503 * 2504 * Returns the nodes in @nodes1 that precede the first node in @nodes2 2505 * in document order, @nodes1 if @nodes2 is NULL or empty or 2506 * an empty node-set if @nodes1 doesn't contain @nodes2 2507 */ 2508xmlNodeSetPtr 2509xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2510 if (xmlXPathNodeSetIsEmpty(nodes2)) 2511 return(nodes1); 2512 if (xmlXPathNodeSetIsEmpty(nodes1)) 2513 return(xmlXPathNodeSetCreate(NULL)); 2514 xmlXPathNodeSetSort(nodes1); 2515 xmlXPathNodeSetSort(nodes2); 2516 return(xmlXPathNodeLeadingSorted(nodes1, 2517 xmlXPathNodeSetItem(nodes2, 1))); 2518} 2519 2520/** 2521 * xmlXPathNodeTrailingSorted: 2522 * @nodes: a node-set, sorted by document order 2523 * @node: a node 2524 * 2525 * Implements the EXSLT - Sets trailing() function: 2526 * node-set set:trailing (node-set, node-set) 2527 * 2528 * Returns the nodes in @nodes that follow @node in document order, 2529 * @nodes if @node is NULL or an empty node-set if @nodes 2530 * doesn't contain @node 2531 */ 2532xmlNodeSetPtr 2533xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 2534 int i, l; 2535 xmlNodePtr cur; 2536 xmlNodeSetPtr ret; 2537 2538 if (node == NULL) 2539 return(nodes); 2540 2541 ret = xmlXPathNodeSetCreate(NULL); 2542 if (xmlXPathNodeSetIsEmpty(nodes) || 2543 (!xmlXPathNodeSetContains(nodes, node))) 2544 return(ret); 2545 2546 l = xmlXPathNodeSetGetLength(nodes); 2547 for (i = l; i > 0; i--) { 2548 cur = xmlXPathNodeSetItem(nodes, i); 2549 if (cur == node) 2550 break; 2551 xmlXPathNodeSetAddUnique(ret, cur); 2552 } 2553 return(ret); 2554} 2555 2556/** 2557 * xmlXPathNodeTrailing: 2558 * @nodes: a node-set 2559 * @node: a node 2560 * 2561 * Implements the EXSLT - Sets trailing() function: 2562 * node-set set:trailing (node-set, node-set) 2563 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 2564 * is called. 2565 * 2566 * Returns the nodes in @nodes that follow @node in document order, 2567 * @nodes if @node is NULL or an empty node-set if @nodes 2568 * doesn't contain @node 2569 */ 2570xmlNodeSetPtr 2571xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 2572 xmlXPathNodeSetSort(nodes); 2573 return(xmlXPathNodeTrailingSorted(nodes, node)); 2574} 2575 2576/** 2577 * xmlXPathTrailingSorted: 2578 * @nodes1: a node-set, sorted by document order 2579 * @nodes2: a node-set, sorted by document order 2580 * 2581 * Implements the EXSLT - Sets trailing() function: 2582 * node-set set:trailing (node-set, node-set) 2583 * 2584 * Returns the nodes in @nodes1 that follow the first node in @nodes2 2585 * in document order, @nodes1 if @nodes2 is NULL or empty or 2586 * an empty node-set if @nodes1 doesn't contain @nodes2 2587 */ 2588xmlNodeSetPtr 2589xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2590 if (xmlXPathNodeSetIsEmpty(nodes2)) 2591 return(nodes1); 2592 return(xmlXPathNodeTrailingSorted(nodes1, 2593 xmlXPathNodeSetItem(nodes2, 0))); 2594} 2595 2596/** 2597 * xmlXPathTrailing: 2598 * @nodes1: a node-set 2599 * @nodes2: a node-set 2600 * 2601 * Implements the EXSLT - Sets trailing() function: 2602 * node-set set:trailing (node-set, node-set) 2603 * @nodes1 and @nodes2 are sorted by document order, then 2604 * #xmlXPathTrailingSorted is called. 2605 * 2606 * Returns the nodes in @nodes1 that follow the first node in @nodes2 2607 * in document order, @nodes1 if @nodes2 is NULL or empty or 2608 * an empty node-set if @nodes1 doesn't contain @nodes2 2609 */ 2610xmlNodeSetPtr 2611xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2612 if (xmlXPathNodeSetIsEmpty(nodes2)) 2613 return(nodes1); 2614 if (xmlXPathNodeSetIsEmpty(nodes1)) 2615 return(xmlXPathNodeSetCreate(NULL)); 2616 xmlXPathNodeSetSort(nodes1); 2617 xmlXPathNodeSetSort(nodes2); 2618 return(xmlXPathNodeTrailingSorted(nodes1, 2619 xmlXPathNodeSetItem(nodes2, 0))); 2620} 2621 2622/************************************************************************ 2623 * * 2624 * Routines to handle extra functions * 2625 * * 2626 ************************************************************************/ 2627 2628/** 2629 * xmlXPathRegisterFunc: 2630 * @ctxt: the XPath context 2631 * @name: the function name 2632 * @f: the function implementation or NULL 2633 * 2634 * Register a new function. If @f is NULL it unregisters the function 2635 * 2636 * Returns 0 in case of success, -1 in case of error 2637 */ 2638int 2639xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 2640 xmlXPathFunction f) { 2641 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 2642} 2643 2644/** 2645 * xmlXPathRegisterFuncNS: 2646 * @ctxt: the XPath context 2647 * @name: the function name 2648 * @ns_uri: the function namespace URI 2649 * @f: the function implementation or NULL 2650 * 2651 * Register a new function. If @f is NULL it unregisters the function 2652 * 2653 * Returns 0 in case of success, -1 in case of error 2654 */ 2655int 2656xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 2657 const xmlChar *ns_uri, xmlXPathFunction f) { 2658 if (ctxt == NULL) 2659 return(-1); 2660 if (name == NULL) 2661 return(-1); 2662 2663 if (ctxt->funcHash == NULL) 2664 ctxt->funcHash = xmlHashCreate(0); 2665 if (ctxt->funcHash == NULL) 2666 return(-1); 2667 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f)); 2668} 2669 2670/** 2671 * xmlXPathRegisterFuncLookup: 2672 * @ctxt: the XPath context 2673 * @f: the lookup function 2674 * @funcCtxt: the lookup data 2675 * 2676 * Registers an external mechanism to do function lookup. 2677 */ 2678void 2679xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 2680 xmlXPathFuncLookupFunc f, 2681 void *funcCtxt) { 2682 if (ctxt == NULL) 2683 return; 2684 ctxt->funcLookupFunc = (void *) f; 2685 ctxt->funcLookupData = funcCtxt; 2686} 2687 2688/** 2689 * xmlXPathFunctionLookup: 2690 * @ctxt: the XPath context 2691 * @name: the function name 2692 * 2693 * Search in the Function array of the context for the given 2694 * function. 2695 * 2696 * Returns the xmlXPathFunction or NULL if not found 2697 */ 2698xmlXPathFunction 2699xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 2700 if (ctxt == NULL) 2701 return (NULL); 2702 2703 if (ctxt->funcLookupFunc != NULL) { 2704 xmlXPathFunction ret; 2705 xmlXPathFuncLookupFunc f; 2706 2707 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc; 2708 ret = f(ctxt->funcLookupData, name, NULL); 2709 if (ret != NULL) 2710 return(ret); 2711 } 2712 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 2713} 2714 2715/** 2716 * xmlXPathFunctionLookupNS: 2717 * @ctxt: the XPath context 2718 * @name: the function name 2719 * @ns_uri: the function namespace URI 2720 * 2721 * Search in the Function array of the context for the given 2722 * function. 2723 * 2724 * Returns the xmlXPathFunction or NULL if not found 2725 */ 2726xmlXPathFunction 2727xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 2728 const xmlChar *ns_uri) { 2729 if (ctxt == NULL) 2730 return(NULL); 2731 if (name == NULL) 2732 return(NULL); 2733 2734 if (ctxt->funcLookupFunc != NULL) { 2735 xmlXPathFunction ret; 2736 xmlXPathFuncLookupFunc f; 2737 2738 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc; 2739 ret = f(ctxt->funcLookupData, name, ns_uri); 2740 if (ret != NULL) 2741 return(ret); 2742 } 2743 2744 if (ctxt->funcHash == NULL) 2745 return(NULL); 2746 2747 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri)); 2748} 2749 2750/** 2751 * xmlXPathRegisteredFuncsCleanup: 2752 * @ctxt: the XPath context 2753 * 2754 * Cleanup the XPath context data associated to registered functions 2755 */ 2756void 2757xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 2758 if (ctxt == NULL) 2759 return; 2760 2761 xmlHashFree(ctxt->funcHash, NULL); 2762 ctxt->funcHash = NULL; 2763} 2764 2765/************************************************************************ 2766 * * 2767 * Routines to handle Variable * 2768 * * 2769 ************************************************************************/ 2770 2771/** 2772 * xmlXPathRegisterVariable: 2773 * @ctxt: the XPath context 2774 * @name: the variable name 2775 * @value: the variable value or NULL 2776 * 2777 * Register a new variable value. If @value is NULL it unregisters 2778 * the variable 2779 * 2780 * Returns 0 in case of success, -1 in case of error 2781 */ 2782int 2783xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 2784 xmlXPathObjectPtr value) { 2785 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 2786} 2787 2788/** 2789 * xmlXPathRegisterVariableNS: 2790 * @ctxt: the XPath context 2791 * @name: the variable name 2792 * @ns_uri: the variable namespace URI 2793 * @value: the variable value or NULL 2794 * 2795 * Register a new variable value. If @value is NULL it unregisters 2796 * the variable 2797 * 2798 * Returns 0 in case of success, -1 in case of error 2799 */ 2800int 2801xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 2802 const xmlChar *ns_uri, 2803 xmlXPathObjectPtr value) { 2804 if (ctxt == NULL) 2805 return(-1); 2806 if (name == NULL) 2807 return(-1); 2808 2809 if (ctxt->varHash == NULL) 2810 ctxt->varHash = xmlHashCreate(0); 2811 if (ctxt->varHash == NULL) 2812 return(-1); 2813 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 2814 (void *) value, 2815 (xmlHashDeallocator)xmlXPathFreeObject)); 2816} 2817 2818/** 2819 * xmlXPathRegisterVariableLookup: 2820 * @ctxt: the XPath context 2821 * @f: the lookup function 2822 * @data: the lookup data 2823 * 2824 * register an external mechanism to do variable lookup 2825 */ 2826void 2827xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 2828 xmlXPathVariableLookupFunc f, void *data) { 2829 if (ctxt == NULL) 2830 return; 2831 ctxt->varLookupFunc = (void *) f; 2832 ctxt->varLookupData = data; 2833} 2834 2835/** 2836 * xmlXPathVariableLookup: 2837 * @ctxt: the XPath context 2838 * @name: the variable name 2839 * 2840 * Search in the Variable array of the context for the given 2841 * variable value. 2842 * 2843 * Returns a copy of the value or NULL if not found 2844 */ 2845xmlXPathObjectPtr 2846xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 2847 if (ctxt == NULL) 2848 return(NULL); 2849 2850 if (ctxt->varLookupFunc != NULL) { 2851 xmlXPathObjectPtr ret; 2852 2853 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 2854 (ctxt->varLookupData, name, NULL); 2855 return(ret); 2856 } 2857 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 2858} 2859 2860/** 2861 * xmlXPathVariableLookupNS: 2862 * @ctxt: the XPath context 2863 * @name: the variable name 2864 * @ns_uri: the variable namespace URI 2865 * 2866 * Search in the Variable array of the context for the given 2867 * variable value. 2868 * 2869 * Returns the a copy of the value or NULL if not found 2870 */ 2871xmlXPathObjectPtr 2872xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 2873 const xmlChar *ns_uri) { 2874 if (ctxt == NULL) 2875 return(NULL); 2876 2877 if (ctxt->varLookupFunc != NULL) { 2878 xmlXPathObjectPtr ret; 2879 2880 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 2881 (ctxt->varLookupData, name, ns_uri); 2882 if (ret != NULL) return(ret); 2883 } 2884 2885 if (ctxt->varHash == NULL) 2886 return(NULL); 2887 if (name == NULL) 2888 return(NULL); 2889 2890 return(xmlXPathObjectCopy((xmlXPathObjectPtr) 2891 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 2892} 2893 2894/** 2895 * xmlXPathRegisteredVariablesCleanup: 2896 * @ctxt: the XPath context 2897 * 2898 * Cleanup the XPath context data associated to registered variables 2899 */ 2900void 2901xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 2902 if (ctxt == NULL) 2903 return; 2904 2905 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 2906 ctxt->varHash = NULL; 2907} 2908 2909/** 2910 * xmlXPathRegisterNs: 2911 * @ctxt: the XPath context 2912 * @prefix: the namespace prefix 2913 * @ns_uri: the namespace name 2914 * 2915 * Register a new namespace. If @ns_uri is NULL it unregisters 2916 * the namespace 2917 * 2918 * Returns 0 in case of success, -1 in case of error 2919 */ 2920int 2921xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 2922 const xmlChar *ns_uri) { 2923 if (ctxt == NULL) 2924 return(-1); 2925 if (prefix == NULL) 2926 return(-1); 2927 2928 if (ctxt->nsHash == NULL) 2929 ctxt->nsHash = xmlHashCreate(10); 2930 if (ctxt->nsHash == NULL) 2931 return(-1); 2932 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 2933 (xmlHashDeallocator)xmlFree)); 2934} 2935 2936/** 2937 * xmlXPathNsLookup: 2938 * @ctxt: the XPath context 2939 * @prefix: the namespace prefix value 2940 * 2941 * Search in the namespace declaration array of the context for the given 2942 * namespace name associated to the given prefix 2943 * 2944 * Returns the value or NULL if not found 2945 */ 2946const xmlChar * 2947xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 2948 if (ctxt == NULL) 2949 return(NULL); 2950 if (prefix == NULL) 2951 return(NULL); 2952 2953#ifdef XML_XML_NAMESPACE 2954 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 2955 return(XML_XML_NAMESPACE); 2956#endif 2957 2958 if (ctxt->namespaces != NULL) { 2959 int i; 2960 2961 for (i = 0;i < ctxt->nsNr;i++) { 2962 if ((ctxt->namespaces[i] != NULL) && 2963 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 2964 return(ctxt->namespaces[i]->href); 2965 } 2966 } 2967 2968 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 2969} 2970 2971/** 2972 * xmlXPathRegisteredNsCleanup: 2973 * @ctxt: the XPath context 2974 * 2975 * Cleanup the XPath context data associated to registered variables 2976 */ 2977void 2978xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 2979 if (ctxt == NULL) 2980 return; 2981 2982 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); 2983 ctxt->nsHash = NULL; 2984} 2985 2986/************************************************************************ 2987 * * 2988 * Routines to handle Values * 2989 * * 2990 ************************************************************************/ 2991 2992/* Allocations are terrible, one need to optimize all this !!! */ 2993 2994/** 2995 * xmlXPathNewFloat: 2996 * @val: the double value 2997 * 2998 * Create a new xmlXPathObjectPtr of type double and of value @val 2999 * 3000 * Returns the newly created object. 3001 */ 3002xmlXPathObjectPtr 3003xmlXPathNewFloat(double val) { 3004 xmlXPathObjectPtr ret; 3005 3006 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3007 if (ret == NULL) { 3008 xmlGenericError(xmlGenericErrorContext, 3009 "xmlXPathNewFloat: out of memory\n"); 3010 return(NULL); 3011 } 3012 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 3013 ret->type = XPATH_NUMBER; 3014 ret->floatval = val; 3015 return(ret); 3016} 3017 3018/** 3019 * xmlXPathNewBoolean: 3020 * @val: the boolean value 3021 * 3022 * Create a new xmlXPathObjectPtr of type boolean and of value @val 3023 * 3024 * Returns the newly created object. 3025 */ 3026xmlXPathObjectPtr 3027xmlXPathNewBoolean(int val) { 3028 xmlXPathObjectPtr ret; 3029 3030 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3031 if (ret == NULL) { 3032 xmlGenericError(xmlGenericErrorContext, 3033 "xmlXPathNewBoolean: out of memory\n"); 3034 return(NULL); 3035 } 3036 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 3037 ret->type = XPATH_BOOLEAN; 3038 ret->boolval = (val != 0); 3039 return(ret); 3040} 3041 3042/** 3043 * xmlXPathNewString: 3044 * @val: the xmlChar * value 3045 * 3046 * Create a new xmlXPathObjectPtr of type string and of value @val 3047 * 3048 * Returns the newly created object. 3049 */ 3050xmlXPathObjectPtr 3051xmlXPathNewString(const xmlChar *val) { 3052 xmlXPathObjectPtr ret; 3053 3054 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3055 if (ret == NULL) { 3056 xmlGenericError(xmlGenericErrorContext, 3057 "xmlXPathNewString: out of memory\n"); 3058 return(NULL); 3059 } 3060 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 3061 ret->type = XPATH_STRING; 3062 if (val != NULL) 3063 ret->stringval = xmlStrdup(val); 3064 else 3065 ret->stringval = xmlStrdup((const xmlChar *)""); 3066 return(ret); 3067} 3068 3069/** 3070 * xmlXPathWrapString: 3071 * @val: the xmlChar * value 3072 * 3073 * Wraps the @val string into an XPath object. 3074 * 3075 * Returns the newly created object. 3076 */ 3077xmlXPathObjectPtr 3078xmlXPathWrapString (xmlChar *val) { 3079 xmlXPathObjectPtr ret; 3080 3081 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3082 if (ret == NULL) { 3083 xmlGenericError(xmlGenericErrorContext, 3084 "xmlXPathWrapString: out of memory\n"); 3085 return(NULL); 3086 } 3087 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 3088 ret->type = XPATH_STRING; 3089 ret->stringval = val; 3090 return(ret); 3091} 3092 3093/** 3094 * xmlXPathNewCString: 3095 * @val: the char * value 3096 * 3097 * Create a new xmlXPathObjectPtr of type string and of value @val 3098 * 3099 * Returns the newly created object. 3100 */ 3101xmlXPathObjectPtr 3102xmlXPathNewCString(const char *val) { 3103 xmlXPathObjectPtr ret; 3104 3105 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3106 if (ret == NULL) { 3107 xmlGenericError(xmlGenericErrorContext, 3108 "xmlXPathNewCString: out of memory\n"); 3109 return(NULL); 3110 } 3111 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 3112 ret->type = XPATH_STRING; 3113 ret->stringval = xmlStrdup(BAD_CAST val); 3114 return(ret); 3115} 3116 3117/** 3118 * xmlXPathWrapCString: 3119 * @val: the char * value 3120 * 3121 * Wraps a string into an XPath object. 3122 * 3123 * Returns the newly created object. 3124 */ 3125xmlXPathObjectPtr 3126xmlXPathWrapCString (char * val) { 3127 return(xmlXPathWrapString((xmlChar *)(val))); 3128} 3129 3130/** 3131 * xmlXPathWrapExternal: 3132 * @val: the user data 3133 * 3134 * Wraps the @val data into an XPath object. 3135 * 3136 * Returns the newly created object. 3137 */ 3138xmlXPathObjectPtr 3139xmlXPathWrapExternal (void *val) { 3140 xmlXPathObjectPtr ret; 3141 3142 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3143 if (ret == NULL) { 3144 xmlGenericError(xmlGenericErrorContext, 3145 "xmlXPathWrapExternal: out of memory\n"); 3146 return(NULL); 3147 } 3148 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 3149 ret->type = XPATH_USERS; 3150 ret->user = val; 3151 return(ret); 3152} 3153 3154/** 3155 * xmlXPathObjectCopy: 3156 * @val: the original object 3157 * 3158 * allocate a new copy of a given object 3159 * 3160 * Returns the newly created object. 3161 */ 3162xmlXPathObjectPtr 3163xmlXPathObjectCopy(xmlXPathObjectPtr val) { 3164 xmlXPathObjectPtr ret; 3165 3166 if (val == NULL) 3167 return(NULL); 3168 3169 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3170 if (ret == NULL) { 3171 xmlGenericError(xmlGenericErrorContext, 3172 "xmlXPathObjectCopy: out of memory\n"); 3173 return(NULL); 3174 } 3175 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 3176 switch (val->type) { 3177 case XPATH_BOOLEAN: 3178 case XPATH_NUMBER: 3179 case XPATH_POINT: 3180 case XPATH_RANGE: 3181 break; 3182 case XPATH_STRING: 3183 ret->stringval = xmlStrdup(val->stringval); 3184 break; 3185 case XPATH_XSLT_TREE: 3186 if ((val->nodesetval != NULL) && 3187 (val->nodesetval->nodeTab != NULL)) { 3188 xmlNodePtr cur, tmp; 3189 xmlDocPtr top; 3190 3191 ret->boolval = 1; 3192 top = xmlNewDoc(NULL); 3193 top->name = (char *) 3194 xmlStrdup(val->nodesetval->nodeTab[0]->name); 3195 ret->user = top; 3196 if (top != NULL) { 3197 top->doc = top; 3198 cur = val->nodesetval->nodeTab[0]->children; 3199 while (cur != NULL) { 3200 tmp = xmlDocCopyNode(cur, top, 1); 3201 xmlAddChild((xmlNodePtr) top, tmp); 3202 cur = cur->next; 3203 } 3204 } 3205 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 3206 } else 3207 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 3208 /* Deallocate the copied tree value */ 3209 break; 3210 case XPATH_NODESET: 3211 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 3212 /* Do not deallocate the copied tree value */ 3213 ret->boolval = 0; 3214 break; 3215 case XPATH_LOCATIONSET: 3216#ifdef LIBXML_XPTR_ENABLED 3217 { 3218 xmlLocationSetPtr loc = val->user; 3219 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 3220 break; 3221 } 3222#endif 3223 case XPATH_USERS: 3224 ret->user = val->user; 3225 break; 3226 case XPATH_UNDEFINED: 3227 xmlGenericError(xmlGenericErrorContext, 3228 "xmlXPathObjectCopy: unsupported type %d\n", 3229 val->type); 3230 break; 3231 } 3232 return(ret); 3233} 3234 3235/** 3236 * xmlXPathFreeObject: 3237 * @obj: the object to free 3238 * 3239 * Free up an xmlXPathObjectPtr object. 3240 */ 3241void 3242xmlXPathFreeObject(xmlXPathObjectPtr obj) { 3243 if (obj == NULL) return; 3244 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 3245 if (obj->boolval) { 3246 if (obj->user != NULL) { 3247 xmlXPathFreeNodeSet(obj->nodesetval); 3248 xmlFreeNodeList((xmlNodePtr) obj->user); 3249 } else if (obj->nodesetval != NULL) 3250 xmlXPathFreeValueTree(obj->nodesetval); 3251 } else { 3252 if (obj->nodesetval != NULL) 3253 xmlXPathFreeNodeSet(obj->nodesetval); 3254 } 3255#ifdef LIBXML_XPTR_ENABLED 3256 } else if (obj->type == XPATH_LOCATIONSET) { 3257 if (obj->user != NULL) 3258 xmlXPtrFreeLocationSet(obj->user); 3259#endif 3260 } else if (obj->type == XPATH_STRING) { 3261 if (obj->stringval != NULL) 3262 xmlFree(obj->stringval); 3263 } 3264 3265 xmlFree(obj); 3266} 3267 3268 3269/************************************************************************ 3270 * * 3271 * Type Casting Routines * 3272 * * 3273 ************************************************************************/ 3274 3275/** 3276 * xmlXPathCastBooleanToString: 3277 * @val: a boolean 3278 * 3279 * Converts a boolean to its string value. 3280 * 3281 * Returns a newly allocated string. 3282 */ 3283xmlChar * 3284xmlXPathCastBooleanToString (int val) { 3285 xmlChar *ret; 3286 if (val) 3287 ret = xmlStrdup((const xmlChar *) "true"); 3288 else 3289 ret = xmlStrdup((const xmlChar *) "false"); 3290 return(ret); 3291} 3292 3293/** 3294 * xmlXPathCastNumberToString: 3295 * @val: a number 3296 * 3297 * Converts a number to its string value. 3298 * 3299 * Returns a newly allocated string. 3300 */ 3301xmlChar * 3302xmlXPathCastNumberToString (double val) { 3303 xmlChar *ret; 3304 switch (xmlXPathIsInf(val)) { 3305 case 1: 3306 ret = xmlStrdup((const xmlChar *) "Infinity"); 3307 break; 3308 case -1: 3309 ret = xmlStrdup((const xmlChar *) "-Infinity"); 3310 break; 3311 default: 3312 if (xmlXPathIsNaN(val)) { 3313 ret = xmlStrdup((const xmlChar *) "NaN"); 3314 } else if (val == 0 && xmlXPathGetSign(val) != 0) { 3315 ret = xmlStrdup((const xmlChar *) "0"); 3316 } else { 3317 /* could be improved */ 3318 char buf[100]; 3319 xmlXPathFormatNumber(val, buf, 100); 3320 ret = xmlStrdup((const xmlChar *) buf); 3321 } 3322 } 3323 return(ret); 3324} 3325 3326/** 3327 * xmlXPathCastNodeToString: 3328 * @node: a node 3329 * 3330 * Converts a node to its string value. 3331 * 3332 * Returns a newly allocated string. 3333 */ 3334xmlChar * 3335xmlXPathCastNodeToString (xmlNodePtr node) { 3336 return(xmlNodeGetContent(node)); 3337} 3338 3339/** 3340 * xmlXPathCastNodeSetToString: 3341 * @ns: a node-set 3342 * 3343 * Converts a node-set to its string value. 3344 * 3345 * Returns a newly allocated string. 3346 */ 3347xmlChar * 3348xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 3349 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 3350 return(xmlStrdup((const xmlChar *) "")); 3351 3352 xmlXPathNodeSetSort(ns); 3353 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 3354} 3355 3356/** 3357 * xmlXPathCastToString: 3358 * @val: an XPath object 3359 * 3360 * Converts an existing object to its string() equivalent 3361 * 3362 * Returns the string value of the object, NULL in case of error. 3363 * A new string is allocated only if needed (@val isn't a 3364 * string object). 3365 */ 3366xmlChar * 3367xmlXPathCastToString(xmlXPathObjectPtr val) { 3368 xmlChar *ret = NULL; 3369 3370 if (val == NULL) 3371 return(xmlStrdup((const xmlChar *) "")); 3372 switch (val->type) { 3373 case XPATH_UNDEFINED: 3374#ifdef DEBUG_EXPR 3375 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 3376#endif 3377 ret = xmlStrdup((const xmlChar *) ""); 3378 break; 3379 case XPATH_NODESET: 3380 case XPATH_XSLT_TREE: 3381 ret = xmlXPathCastNodeSetToString(val->nodesetval); 3382 break; 3383 case XPATH_STRING: 3384 return(xmlStrdup(val->stringval)); 3385 case XPATH_BOOLEAN: 3386 ret = xmlXPathCastBooleanToString(val->boolval); 3387 break; 3388 case XPATH_NUMBER: { 3389 ret = xmlXPathCastNumberToString(val->floatval); 3390 break; 3391 } 3392 case XPATH_USERS: 3393 case XPATH_POINT: 3394 case XPATH_RANGE: 3395 case XPATH_LOCATIONSET: 3396 TODO 3397 ret = xmlStrdup((const xmlChar *) ""); 3398 break; 3399 } 3400 return(ret); 3401} 3402 3403/** 3404 * xmlXPathConvertString: 3405 * @val: an XPath object 3406 * 3407 * Converts an existing object to its string() equivalent 3408 * 3409 * Returns the new object, the old one is freed (or the operation 3410 * is done directly on @val) 3411 */ 3412xmlXPathObjectPtr 3413xmlXPathConvertString(xmlXPathObjectPtr val) { 3414 xmlChar *res = NULL; 3415 3416 if (val == NULL) 3417 return(xmlXPathNewCString("")); 3418 3419 switch (val->type) { 3420 case XPATH_UNDEFINED: 3421#ifdef DEBUG_EXPR 3422 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 3423#endif 3424 break; 3425 case XPATH_NODESET: 3426 case XPATH_XSLT_TREE: 3427 res = xmlXPathCastNodeSetToString(val->nodesetval); 3428 break; 3429 case XPATH_STRING: 3430 return(val); 3431 case XPATH_BOOLEAN: 3432 res = xmlXPathCastBooleanToString(val->boolval); 3433 break; 3434 case XPATH_NUMBER: 3435 res = xmlXPathCastNumberToString(val->floatval); 3436 break; 3437 case XPATH_USERS: 3438 case XPATH_POINT: 3439 case XPATH_RANGE: 3440 case XPATH_LOCATIONSET: 3441 TODO; 3442 break; 3443 } 3444 xmlXPathFreeObject(val); 3445 if (res == NULL) 3446 return(xmlXPathNewCString("")); 3447 return(xmlXPathWrapString(res)); 3448} 3449 3450/** 3451 * xmlXPathCastBooleanToNumber: 3452 * @val: a boolean 3453 * 3454 * Converts a boolean to its number value 3455 * 3456 * Returns the number value 3457 */ 3458double 3459xmlXPathCastBooleanToNumber(int val) { 3460 if (val) 3461 return(1.0); 3462 return(0.0); 3463} 3464 3465/** 3466 * xmlXPathCastStringToNumber: 3467 * @val: a string 3468 * 3469 * Converts a string to its number value 3470 * 3471 * Returns the number value 3472 */ 3473double 3474xmlXPathCastStringToNumber(const xmlChar * val) { 3475 return(xmlXPathStringEvalNumber(val)); 3476} 3477 3478/** 3479 * xmlXPathCastNodeToNumber: 3480 * @node: a node 3481 * 3482 * Converts a node to its number value 3483 * 3484 * Returns the number value 3485 */ 3486double 3487xmlXPathCastNodeToNumber (xmlNodePtr node) { 3488 xmlChar *strval; 3489 double ret; 3490 3491 if (node == NULL) 3492 return(xmlXPathNAN); 3493 strval = xmlXPathCastNodeToString(node); 3494 if (strval == NULL) 3495 return(xmlXPathNAN); 3496 ret = xmlXPathCastStringToNumber(strval); 3497 xmlFree(strval); 3498 3499 return(ret); 3500} 3501 3502/** 3503 * xmlXPathCastNodeSetToNumber: 3504 * @ns: a node-set 3505 * 3506 * Converts a node-set to its number value 3507 * 3508 * Returns the number value 3509 */ 3510double 3511xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 3512 xmlChar *str; 3513 double ret; 3514 3515 if (ns == NULL) 3516 return(xmlXPathNAN); 3517 str = xmlXPathCastNodeSetToString(ns); 3518 ret = xmlXPathCastStringToNumber(str); 3519 xmlFree(str); 3520 return(ret); 3521} 3522 3523/** 3524 * xmlXPathCastToNumber: 3525 * @val: an XPath object 3526 * 3527 * Converts an XPath object to its number value 3528 * 3529 * Returns the number value 3530 */ 3531double 3532xmlXPathCastToNumber(xmlXPathObjectPtr val) { 3533 double ret = 0.0; 3534 3535 if (val == NULL) 3536 return(xmlXPathNAN); 3537 switch (val->type) { 3538 case XPATH_UNDEFINED: 3539#ifdef DEGUB_EXPR 3540 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 3541#endif 3542 ret = xmlXPathNAN; 3543 break; 3544 case XPATH_NODESET: 3545 case XPATH_XSLT_TREE: 3546 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 3547 break; 3548 case XPATH_STRING: 3549 ret = xmlXPathCastStringToNumber(val->stringval); 3550 break; 3551 case XPATH_NUMBER: 3552 ret = val->floatval; 3553 break; 3554 case XPATH_BOOLEAN: 3555 ret = xmlXPathCastBooleanToNumber(val->boolval); 3556 break; 3557 case XPATH_USERS: 3558 case XPATH_POINT: 3559 case XPATH_RANGE: 3560 case XPATH_LOCATIONSET: 3561 TODO; 3562 ret = xmlXPathNAN; 3563 break; 3564 } 3565 return(ret); 3566} 3567 3568/** 3569 * xmlXPathConvertNumber: 3570 * @val: an XPath object 3571 * 3572 * Converts an existing object to its number() equivalent 3573 * 3574 * Returns the new object, the old one is freed (or the operation 3575 * is done directly on @val) 3576 */ 3577xmlXPathObjectPtr 3578xmlXPathConvertNumber(xmlXPathObjectPtr val) { 3579 xmlXPathObjectPtr ret; 3580 3581 if (val == NULL) 3582 return(xmlXPathNewFloat(0.0)); 3583 if (val->type == XPATH_NUMBER) 3584 return(val); 3585 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 3586 xmlXPathFreeObject(val); 3587 return(ret); 3588} 3589 3590/** 3591 * xmlXPathCastNumberToBoolean: 3592 * @val: a number 3593 * 3594 * Converts a number to its boolean value 3595 * 3596 * Returns the boolean value 3597 */ 3598int 3599xmlXPathCastNumberToBoolean (double val) { 3600 if (xmlXPathIsNaN(val) || (val == 0.0)) 3601 return(0); 3602 return(1); 3603} 3604 3605/** 3606 * xmlXPathCastStringToBoolean: 3607 * @val: a string 3608 * 3609 * Converts a string to its boolean value 3610 * 3611 * Returns the boolean value 3612 */ 3613int 3614xmlXPathCastStringToBoolean (const xmlChar *val) { 3615 if ((val == NULL) || (xmlStrlen(val) == 0)) 3616 return(0); 3617 return(1); 3618} 3619 3620/** 3621 * xmlXPathCastNodeSetToBoolean: 3622 * @ns: a node-set 3623 * 3624 * Converts a node-set to its boolean value 3625 * 3626 * Returns the boolean value 3627 */ 3628int 3629xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 3630 if ((ns == NULL) || (ns->nodeNr == 0)) 3631 return(0); 3632 return(1); 3633} 3634 3635/** 3636 * xmlXPathCastToBoolean: 3637 * @val: an XPath object 3638 * 3639 * Converts an XPath object to its boolean value 3640 * 3641 * Returns the boolean value 3642 */ 3643int 3644xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 3645 int ret = 0; 3646 3647 if (val == NULL) 3648 return(0); 3649 switch (val->type) { 3650 case XPATH_UNDEFINED: 3651#ifdef DEBUG_EXPR 3652 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 3653#endif 3654 ret = 0; 3655 break; 3656 case XPATH_NODESET: 3657 case XPATH_XSLT_TREE: 3658 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 3659 break; 3660 case XPATH_STRING: 3661 ret = xmlXPathCastStringToBoolean(val->stringval); 3662 break; 3663 case XPATH_NUMBER: 3664 ret = xmlXPathCastNumberToBoolean(val->floatval); 3665 break; 3666 case XPATH_BOOLEAN: 3667 ret = val->boolval; 3668 break; 3669 case XPATH_USERS: 3670 case XPATH_POINT: 3671 case XPATH_RANGE: 3672 case XPATH_LOCATIONSET: 3673 TODO; 3674 ret = 0; 3675 break; 3676 } 3677 return(ret); 3678} 3679 3680 3681/** 3682 * xmlXPathConvertBoolean: 3683 * @val: an XPath object 3684 * 3685 * Converts an existing object to its boolean() equivalent 3686 * 3687 * Returns the new object, the old one is freed (or the operation 3688 * is done directly on @val) 3689 */ 3690xmlXPathObjectPtr 3691xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 3692 xmlXPathObjectPtr ret; 3693 3694 if (val == NULL) 3695 return(xmlXPathNewBoolean(0)); 3696 if (val->type == XPATH_BOOLEAN) 3697 return(val); 3698 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 3699 xmlXPathFreeObject(val); 3700 return(ret); 3701} 3702 3703/************************************************************************ 3704 * * 3705 * Routines to handle XPath contexts * 3706 * * 3707 ************************************************************************/ 3708 3709/** 3710 * xmlXPathNewContext: 3711 * @doc: the XML document 3712 * 3713 * Create a new xmlXPathContext 3714 * 3715 * Returns the xmlXPathContext just allocated. The caller will need to free it. 3716 */ 3717xmlXPathContextPtr 3718xmlXPathNewContext(xmlDocPtr doc) { 3719 xmlXPathContextPtr ret; 3720 3721 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 3722 if (ret == NULL) { 3723 xmlGenericError(xmlGenericErrorContext, 3724 "xmlXPathNewContext: out of memory\n"); 3725 return(NULL); 3726 } 3727 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 3728 ret->doc = doc; 3729 ret->node = NULL; 3730 3731 ret->varHash = NULL; 3732 3733 ret->nb_types = 0; 3734 ret->max_types = 0; 3735 ret->types = NULL; 3736 3737 ret->funcHash = xmlHashCreate(0); 3738 3739 ret->nb_axis = 0; 3740 ret->max_axis = 0; 3741 ret->axis = NULL; 3742 3743 ret->nsHash = NULL; 3744 ret->user = NULL; 3745 3746 ret->contextSize = -1; 3747 ret->proximityPosition = -1; 3748 3749 xmlXPathRegisterAllFunctions(ret); 3750 3751 return(ret); 3752} 3753 3754/** 3755 * xmlXPathFreeContext: 3756 * @ctxt: the context to free 3757 * 3758 * Free up an xmlXPathContext 3759 */ 3760void 3761xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 3762 xmlXPathRegisteredNsCleanup(ctxt); 3763 xmlXPathRegisteredFuncsCleanup(ctxt); 3764 xmlXPathRegisteredVariablesCleanup(ctxt); 3765 xmlFree(ctxt); 3766} 3767 3768/************************************************************************ 3769 * * 3770 * Routines to handle XPath parser contexts * 3771 * * 3772 ************************************************************************/ 3773 3774#define CHECK_CTXT(ctxt) \ 3775 if (ctxt == NULL) { \ 3776 xmlGenericError(xmlGenericErrorContext, \ 3777 "%s:%d Internal error: ctxt == NULL\n", \ 3778 __FILE__, __LINE__); \ 3779 } \ 3780 3781 3782#define CHECK_CONTEXT(ctxt) \ 3783 if (ctxt == NULL) { \ 3784 xmlGenericError(xmlGenericErrorContext, \ 3785 "%s:%d Internal error: no context\n", \ 3786 __FILE__, __LINE__); \ 3787 } \ 3788 else if (ctxt->doc == NULL) { \ 3789 xmlGenericError(xmlGenericErrorContext, \ 3790 "%s:%d Internal error: no document\n", \ 3791 __FILE__, __LINE__); \ 3792 } \ 3793 else if (ctxt->doc->children == NULL) { \ 3794 xmlGenericError(xmlGenericErrorContext, \ 3795 "%s:%d Internal error: document without root\n", \ 3796 __FILE__, __LINE__); \ 3797 } \ 3798 3799 3800/** 3801 * xmlXPathNewParserContext: 3802 * @str: the XPath expression 3803 * @ctxt: the XPath context 3804 * 3805 * Create a new xmlXPathParserContext 3806 * 3807 * Returns the xmlXPathParserContext just allocated. 3808 */ 3809xmlXPathParserContextPtr 3810xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 3811 xmlXPathParserContextPtr ret; 3812 3813 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 3814 if (ret == NULL) { 3815 xmlGenericError(xmlGenericErrorContext, 3816 "xmlXPathNewParserContext: out of memory\n"); 3817 return(NULL); 3818 } 3819 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 3820 ret->cur = ret->base = str; 3821 ret->context = ctxt; 3822 3823 ret->comp = xmlXPathNewCompExpr(); 3824 if (ret->comp == NULL) { 3825 xmlFree(ret->valueTab); 3826 xmlFree(ret); 3827 return(NULL); 3828 } 3829 3830 return(ret); 3831} 3832 3833/** 3834 * xmlXPathCompParserContext: 3835 * @comp: the XPath compiled expression 3836 * @ctxt: the XPath context 3837 * 3838 * Create a new xmlXPathParserContext when processing a compiled expression 3839 * 3840 * Returns the xmlXPathParserContext just allocated. 3841 */ 3842static xmlXPathParserContextPtr 3843xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 3844 xmlXPathParserContextPtr ret; 3845 3846 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 3847 if (ret == NULL) { 3848 xmlGenericError(xmlGenericErrorContext, 3849 "xmlXPathCompParserContext: out of memory\n"); 3850 return(NULL); 3851 } 3852 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 3853 3854 /* Allocate the value stack */ 3855 ret->valueTab = (xmlXPathObjectPtr *) 3856 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 3857 if (ret->valueTab == NULL) { 3858 xmlFree(ret); 3859 xmlGenericError(xmlGenericErrorContext, 3860 "xmlXPathCompParserContext: out of memory\n"); 3861 return(NULL); 3862 } 3863 ret->valueNr = 0; 3864 ret->valueMax = 10; 3865 ret->value = NULL; 3866 3867 ret->context = ctxt; 3868 ret->comp = comp; 3869 3870 return(ret); 3871} 3872 3873/** 3874 * xmlXPathFreeParserContext: 3875 * @ctxt: the context to free 3876 * 3877 * Free up an xmlXPathParserContext 3878 */ 3879void 3880xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 3881 if (ctxt->valueTab != NULL) { 3882 xmlFree(ctxt->valueTab); 3883 } 3884 if (ctxt->comp) 3885 xmlXPathFreeCompExpr(ctxt->comp); 3886 xmlFree(ctxt); 3887} 3888 3889/************************************************************************ 3890 * * 3891 * The implicit core function library * 3892 * * 3893 ************************************************************************/ 3894 3895/** 3896 * xmlXPathNodeValHash: 3897 * @node: a node pointer 3898 * 3899 * Function computing the beginning of the string value of the node, 3900 * used to speed up comparisons 3901 * 3902 * Returns an int usable as a hash 3903 */ 3904static unsigned int 3905xmlXPathNodeValHash(xmlNodePtr node) { 3906 int len = 2; 3907 const xmlChar * string = NULL; 3908 xmlNodePtr tmp = NULL; 3909 unsigned int ret = 0; 3910 3911 if (node == NULL) 3912 return(0); 3913 3914 if (node->type == XML_DOCUMENT_NODE) { 3915 tmp = xmlDocGetRootElement((xmlDocPtr) node); 3916 if (tmp == NULL) 3917 node = node->children; 3918 else 3919 node = tmp; 3920 3921 if (node == NULL) 3922 return(0); 3923 } 3924 3925 switch (node->type) { 3926 case XML_COMMENT_NODE: 3927 case XML_PI_NODE: 3928 case XML_CDATA_SECTION_NODE: 3929 case XML_TEXT_NODE: 3930 string = node->content; 3931 if (string == NULL) 3932 return(0); 3933 if (string[0] == 0) 3934 return(0); 3935 return(((unsigned int) string[0]) + 3936 (((unsigned int) string[1]) << 8)); 3937 case XML_NAMESPACE_DECL: 3938 string = ((xmlNsPtr)node)->href; 3939 if (string == NULL) 3940 return(0); 3941 if (string[0] == 0) 3942 return(0); 3943 return(((unsigned int) string[0]) + 3944 (((unsigned int) string[1]) << 8)); 3945 case XML_ATTRIBUTE_NODE: 3946 tmp = ((xmlAttrPtr) node)->children; 3947 break; 3948 case XML_ELEMENT_NODE: 3949 tmp = node->children; 3950 break; 3951 default: 3952 return(0); 3953 } 3954 while (tmp != NULL) { 3955 switch (tmp->type) { 3956 case XML_COMMENT_NODE: 3957 case XML_PI_NODE: 3958 case XML_CDATA_SECTION_NODE: 3959 case XML_TEXT_NODE: 3960 string = tmp->content; 3961 break; 3962 case XML_NAMESPACE_DECL: 3963 string = ((xmlNsPtr)tmp)->href; 3964 break; 3965 default: 3966 break; 3967 } 3968 if ((string != NULL) && (string[0] != 0)) { 3969 if (string[0] == 0) 3970 return(0); 3971 if (len == 1) { 3972 return(ret + (((unsigned int) string[0]) << 8)); 3973 } 3974 if (string[1] == 0) { 3975 len = 1; 3976 ret = (unsigned int) string[0]; 3977 } else { 3978 return(((unsigned int) string[0]) + 3979 (((unsigned int) string[1]) << 8)); 3980 } 3981 } 3982 /* 3983 * Skip to next node 3984 */ 3985 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 3986 if (tmp->children->type != XML_ENTITY_DECL) { 3987 tmp = tmp->children; 3988 continue; 3989 } 3990 } 3991 if (tmp == node) 3992 break; 3993 3994 if (tmp->next != NULL) { 3995 tmp = tmp->next; 3996 continue; 3997 } 3998 3999 do { 4000 tmp = tmp->parent; 4001 if (tmp == NULL) 4002 break; 4003 if (tmp == node) { 4004 tmp = NULL; 4005 break; 4006 } 4007 if (tmp->next != NULL) { 4008 tmp = tmp->next; 4009 break; 4010 } 4011 } while (tmp != NULL); 4012 } 4013 return(ret); 4014} 4015 4016/** 4017 * xmlXPathStringHash: 4018 * @string: a string 4019 * 4020 * Function computing the beginning of the string value of the node, 4021 * used to speed up comparisons 4022 * 4023 * Returns an int usable as a hash 4024 */ 4025static unsigned int 4026xmlXPathStringHash(const xmlChar * string) { 4027 if (string == NULL) 4028 return((unsigned int) 0); 4029 if (string[0] == 0) 4030 return(0); 4031 return(((unsigned int) string[0]) + 4032 (((unsigned int) string[1]) << 8)); 4033} 4034 4035/** 4036 * xmlXPathCompareNodeSetFloat: 4037 * @ctxt: the XPath Parser context 4038 * @inf: less than (1) or greater than (0) 4039 * @strict: is the comparison strict 4040 * @arg: the node set 4041 * @f: the value 4042 * 4043 * Implement the compare operation between a nodeset and a number 4044 * @ns < @val (1, 1, ... 4045 * @ns <= @val (1, 0, ... 4046 * @ns > @val (0, 1, ... 4047 * @ns >= @val (0, 0, ... 4048 * 4049 * If one object to be compared is a node-set and the other is a number, 4050 * then the comparison will be true if and only if there is a node in the 4051 * node-set such that the result of performing the comparison on the number 4052 * to be compared and on the result of converting the string-value of that 4053 * node to a number using the number function is true. 4054 * 4055 * Returns 0 or 1 depending on the results of the test. 4056 */ 4057static int 4058xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 4059 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 4060 int i, ret = 0; 4061 xmlNodeSetPtr ns; 4062 xmlChar *str2; 4063 4064 if ((f == NULL) || (arg == NULL) || 4065 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 4066 xmlXPathFreeObject(arg); 4067 xmlXPathFreeObject(f); 4068 return(0); 4069 } 4070 ns = arg->nodesetval; 4071 if (ns != NULL) { 4072 for (i = 0;i < ns->nodeNr;i++) { 4073 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 4074 if (str2 != NULL) { 4075 valuePush(ctxt, 4076 xmlXPathNewString(str2)); 4077 xmlFree(str2); 4078 xmlXPathNumberFunction(ctxt, 1); 4079 valuePush(ctxt, xmlXPathObjectCopy(f)); 4080 ret = xmlXPathCompareValues(ctxt, inf, strict); 4081 if (ret) 4082 break; 4083 } 4084 } 4085 } 4086 xmlXPathFreeObject(arg); 4087 xmlXPathFreeObject(f); 4088 return(ret); 4089} 4090 4091/** 4092 * xmlXPathCompareNodeSetString: 4093 * @ctxt: the XPath Parser context 4094 * @inf: less than (1) or greater than (0) 4095 * @strict: is the comparison strict 4096 * @arg: the node set 4097 * @s: the value 4098 * 4099 * Implement the compare operation between a nodeset and a string 4100 * @ns < @val (1, 1, ... 4101 * @ns <= @val (1, 0, ... 4102 * @ns > @val (0, 1, ... 4103 * @ns >= @val (0, 0, ... 4104 * 4105 * If one object to be compared is a node-set and the other is a string, 4106 * then the comparison will be true if and only if there is a node in 4107 * the node-set such that the result of performing the comparison on the 4108 * string-value of the node and the other string is true. 4109 * 4110 * Returns 0 or 1 depending on the results of the test. 4111 */ 4112static int 4113xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 4114 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 4115 int i, ret = 0; 4116 xmlNodeSetPtr ns; 4117 xmlChar *str2; 4118 4119 if ((s == NULL) || (arg == NULL) || 4120 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 4121 xmlXPathFreeObject(arg); 4122 xmlXPathFreeObject(s); 4123 return(0); 4124 } 4125 ns = arg->nodesetval; 4126 if (ns != NULL) { 4127 for (i = 0;i < ns->nodeNr;i++) { 4128 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 4129 if (str2 != NULL) { 4130 valuePush(ctxt, 4131 xmlXPathNewString(str2)); 4132 xmlFree(str2); 4133 valuePush(ctxt, xmlXPathObjectCopy(s)); 4134 ret = xmlXPathCompareValues(ctxt, inf, strict); 4135 if (ret) 4136 break; 4137 } 4138 } 4139 } 4140 xmlXPathFreeObject(arg); 4141 xmlXPathFreeObject(s); 4142 return(ret); 4143} 4144 4145/** 4146 * xmlXPathCompareNodeSets: 4147 * @inf: less than (1) or greater than (0) 4148 * @strict: is the comparison strict 4149 * @arg1: the first node set object 4150 * @arg2: the second node set object 4151 * 4152 * Implement the compare operation on nodesets: 4153 * 4154 * If both objects to be compared are node-sets, then the comparison 4155 * will be true if and only if there is a node in the first node-set 4156 * and a node in the second node-set such that the result of performing 4157 * the comparison on the string-values of the two nodes is true. 4158 * .... 4159 * When neither object to be compared is a node-set and the operator 4160 * is <=, <, >= or >, then the objects are compared by converting both 4161 * objects to numbers and comparing the numbers according to IEEE 754. 4162 * .... 4163 * The number function converts its argument to a number as follows: 4164 * - a string that consists of optional whitespace followed by an 4165 * optional minus sign followed by a Number followed by whitespace 4166 * is converted to the IEEE 754 number that is nearest (according 4167 * to the IEEE 754 round-to-nearest rule) to the mathematical value 4168 * represented by the string; any other string is converted to NaN 4169 * 4170 * Conclusion all nodes need to be converted first to their string value 4171 * and then the comparison must be done when possible 4172 */ 4173static int 4174xmlXPathCompareNodeSets(int inf, int strict, 4175 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 4176 int i, j, init = 0; 4177 double val1; 4178 double *values2; 4179 int ret = 0; 4180 xmlNodeSetPtr ns1; 4181 xmlNodeSetPtr ns2; 4182 4183 if ((arg1 == NULL) || 4184 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 4185 xmlXPathFreeObject(arg2); 4186 return(0); 4187 } 4188 if ((arg2 == NULL) || 4189 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 4190 xmlXPathFreeObject(arg1); 4191 xmlXPathFreeObject(arg2); 4192 return(0); 4193 } 4194 4195 ns1 = arg1->nodesetval; 4196 ns2 = arg2->nodesetval; 4197 4198 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 4199 xmlXPathFreeObject(arg1); 4200 xmlXPathFreeObject(arg2); 4201 return(0); 4202 } 4203 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 4204 xmlXPathFreeObject(arg1); 4205 xmlXPathFreeObject(arg2); 4206 return(0); 4207 } 4208 4209 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 4210 if (values2 == NULL) { 4211 xmlXPathFreeObject(arg1); 4212 xmlXPathFreeObject(arg2); 4213 return(0); 4214 } 4215 for (i = 0;i < ns1->nodeNr;i++) { 4216 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 4217 if (xmlXPathIsNaN(val1)) 4218 continue; 4219 for (j = 0;j < ns2->nodeNr;j++) { 4220 if (init == 0) { 4221 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 4222 } 4223 if (xmlXPathIsNaN(values2[j])) 4224 continue; 4225 if (inf && strict) 4226 ret = (val1 < values2[j]); 4227 else if (inf && !strict) 4228 ret = (val1 <= values2[j]); 4229 else if (!inf && strict) 4230 ret = (val1 > values2[j]); 4231 else if (!inf && !strict) 4232 ret = (val1 >= values2[j]); 4233 if (ret) 4234 break; 4235 } 4236 if (ret) 4237 break; 4238 init = 1; 4239 } 4240 xmlFree(values2); 4241 xmlXPathFreeObject(arg1); 4242 xmlXPathFreeObject(arg2); 4243 return(ret); 4244} 4245 4246/** 4247 * xmlXPathCompareNodeSetValue: 4248 * @ctxt: the XPath Parser context 4249 * @inf: less than (1) or greater than (0) 4250 * @strict: is the comparison strict 4251 * @arg: the node set 4252 * @val: the value 4253 * 4254 * Implement the compare operation between a nodeset and a value 4255 * @ns < @val (1, 1, ... 4256 * @ns <= @val (1, 0, ... 4257 * @ns > @val (0, 1, ... 4258 * @ns >= @val (0, 0, ... 4259 * 4260 * If one object to be compared is a node-set and the other is a boolean, 4261 * then the comparison will be true if and only if the result of performing 4262 * the comparison on the boolean and on the result of converting 4263 * the node-set to a boolean using the boolean function is true. 4264 * 4265 * Returns 0 or 1 depending on the results of the test. 4266 */ 4267static int 4268xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 4269 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 4270 if ((val == NULL) || (arg == NULL) || 4271 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 4272 return(0); 4273 4274 switch(val->type) { 4275 case XPATH_NUMBER: 4276 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 4277 case XPATH_NODESET: 4278 case XPATH_XSLT_TREE: 4279 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 4280 case XPATH_STRING: 4281 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 4282 case XPATH_BOOLEAN: 4283 valuePush(ctxt, arg); 4284 xmlXPathBooleanFunction(ctxt, 1); 4285 valuePush(ctxt, val); 4286 return(xmlXPathCompareValues(ctxt, inf, strict)); 4287 default: 4288 TODO 4289 } 4290 return(0); 4291} 4292 4293/** 4294 * xmlXPathEqualNodeSetString: 4295 * @arg: the nodeset object argument 4296 * @str: the string to compare to. 4297 * @neq: flag to show whether for '=' (0) or '!=' (1) 4298 * 4299 * Implement the equal operation on XPath objects content: @arg1 == @arg2 4300 * If one object to be compared is a node-set and the other is a string, 4301 * then the comparison will be true if and only if there is a node in 4302 * the node-set such that the result of performing the comparison on the 4303 * string-value of the node and the other string is true. 4304 * 4305 * Returns 0 or 1 depending on the results of the test. 4306 */ 4307static int 4308xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 4309{ 4310 int i; 4311 xmlNodeSetPtr ns; 4312 xmlChar *str2; 4313 unsigned int hash; 4314 4315 if ((str == NULL) || (arg == NULL) || 4316 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 4317 return (0); 4318 ns = arg->nodesetval; 4319 hash = xmlXPathStringHash(str); 4320 if (ns == NULL) 4321 return (0); 4322 if (ns->nodeNr <= 0) { 4323 if (hash == 0) 4324 return(neq ^ 1); 4325 return(neq); 4326 } 4327 for (i = 0; i < ns->nodeNr; i++) { 4328 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 4329 str2 = xmlNodeGetContent(ns->nodeTab[i]); 4330 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 4331 xmlFree(str2); 4332 if (neq) 4333 continue; 4334 return (1); 4335 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 4336 if (neq) 4337 continue; 4338 return (1); 4339 } else if (neq) { 4340 if (str2 != NULL) 4341 xmlFree(str2); 4342 return (1); 4343 } 4344 if (str2 != NULL) 4345 xmlFree(str2); 4346 } else if (neq) 4347 return (1); 4348 } 4349 return (0); 4350} 4351 4352/** 4353 * xmlXPathEqualNodeSetFloat: 4354 * @arg: the nodeset object argument 4355 * @f: the float to compare to 4356 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 4357 * 4358 * Implement the equal operation on XPath objects content: @arg1 == @arg2 4359 * If one object to be compared is a node-set and the other is a number, 4360 * then the comparison will be true if and only if there is a node in 4361 * the node-set such that the result of performing the comparison on the 4362 * number to be compared and on the result of converting the string-value 4363 * of that node to a number using the number function is true. 4364 * 4365 * Returns 0 or 1 depending on the results of the test. 4366 */ 4367static int 4368xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 4369 xmlXPathObjectPtr arg, double f, int neq) { 4370 int i, ret=0; 4371 xmlNodeSetPtr ns; 4372 xmlChar *str2; 4373 xmlXPathObjectPtr val; 4374 double v; 4375 4376 if ((arg == NULL) || 4377 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 4378 return(0); 4379 4380 ns = arg->nodesetval; 4381 if (ns != NULL) { 4382 for (i=0;i<ns->nodeNr;i++) { 4383 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 4384 if (str2 != NULL) { 4385 valuePush(ctxt, xmlXPathNewString(str2)); 4386 xmlFree(str2); 4387 xmlXPathNumberFunction(ctxt, 1); 4388 val = valuePop(ctxt); 4389 v = val->floatval; 4390 xmlXPathFreeObject(val); 4391 if (!xmlXPathIsNaN(v)) { 4392 if ((!neq) && (v==f)) { 4393 ret = 1; 4394 break; 4395 } else if ((neq) && (v!=f)) { 4396 ret = 1; 4397 break; 4398 } 4399 } 4400 } 4401 } 4402 } 4403 4404 return(ret); 4405} 4406 4407 4408/** 4409 * xmlXPathEqualNodeSets: 4410 * @arg1: first nodeset object argument 4411 * @arg2: second nodeset object argument 4412 * @neq: flag to show whether to test '=' (0) or '!=' (1) 4413 * 4414 * Implement the equal / not equal operation on XPath nodesets: 4415 * @arg1 == @arg2 or @arg1 != @arg2 4416 * If both objects to be compared are node-sets, then the comparison 4417 * will be true if and only if there is a node in the first node-set and 4418 * a node in the second node-set such that the result of performing the 4419 * comparison on the string-values of the two nodes is true. 4420 * 4421 * (needless to say, this is a costly operation) 4422 * 4423 * Returns 0 or 1 depending on the results of the test. 4424 */ 4425static int 4426xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 4427 int i, j; 4428 unsigned int *hashs1; 4429 unsigned int *hashs2; 4430 xmlChar **values1; 4431 xmlChar **values2; 4432 int ret = 0; 4433 xmlNodeSetPtr ns1; 4434 xmlNodeSetPtr ns2; 4435 4436 if ((arg1 == NULL) || 4437 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 4438 return(0); 4439 if ((arg2 == NULL) || 4440 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 4441 return(0); 4442 4443 ns1 = arg1->nodesetval; 4444 ns2 = arg2->nodesetval; 4445 4446 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 4447 return(0); 4448 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 4449 return(0); 4450 4451 /* 4452 * for equal, check if there is a node pertaining to both sets 4453 */ 4454 if (neq == 0) 4455 for (i = 0;i < ns1->nodeNr;i++) 4456 for (j = 0;j < ns2->nodeNr;j++) 4457 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 4458 return(1); 4459 4460 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 4461 if (values1 == NULL) 4462 return(0); 4463 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 4464 if (hashs1 == NULL) { 4465 xmlFree(values1); 4466 return(0); 4467 } 4468 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 4469 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 4470 if (values2 == NULL) { 4471 xmlFree(hashs1); 4472 xmlFree(values1); 4473 return(0); 4474 } 4475 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 4476 if (hashs2 == NULL) { 4477 xmlFree(hashs1); 4478 xmlFree(values1); 4479 xmlFree(values2); 4480 return(0); 4481 } 4482 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 4483 for (i = 0;i < ns1->nodeNr;i++) { 4484 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 4485 for (j = 0;j < ns2->nodeNr;j++) { 4486 if (i == 0) 4487 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 4488 if (hashs1[i] != hashs2[j]) { 4489 if (neq) { 4490 ret = 1; 4491 break; 4492 } 4493 } 4494 else { 4495 if (values1[i] == NULL) 4496 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 4497 if (values2[j] == NULL) 4498 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 4499 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 4500 if (ret) 4501 break; 4502 } 4503 } 4504 if (ret) 4505 break; 4506 } 4507 for (i = 0;i < ns1->nodeNr;i++) 4508 if (values1[i] != NULL) 4509 xmlFree(values1[i]); 4510 for (j = 0;j < ns2->nodeNr;j++) 4511 if (values2[j] != NULL) 4512 xmlFree(values2[j]); 4513 xmlFree(values1); 4514 xmlFree(values2); 4515 xmlFree(hashs1); 4516 xmlFree(hashs2); 4517 return(ret); 4518} 4519 4520static int 4521xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 4522 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 4523 int ret = 0; 4524 /* 4525 *At this point we are assured neither arg1 nor arg2 4526 *is a nodeset, so we can just pick the appropriate routine. 4527 */ 4528 switch (arg1->type) { 4529 case XPATH_UNDEFINED: 4530#ifdef DEBUG_EXPR 4531 xmlGenericError(xmlGenericErrorContext, 4532 "Equal: undefined\n"); 4533#endif 4534 break; 4535 case XPATH_BOOLEAN: 4536 switch (arg2->type) { 4537 case XPATH_UNDEFINED: 4538#ifdef DEBUG_EXPR 4539 xmlGenericError(xmlGenericErrorContext, 4540 "Equal: undefined\n"); 4541#endif 4542 break; 4543 case XPATH_BOOLEAN: 4544#ifdef DEBUG_EXPR 4545 xmlGenericError(xmlGenericErrorContext, 4546 "Equal: %d boolean %d \n", 4547 arg1->boolval, arg2->boolval); 4548#endif 4549 ret = (arg1->boolval == arg2->boolval); 4550 break; 4551 case XPATH_NUMBER: 4552 ret = (arg1->boolval == 4553 xmlXPathCastNumberToBoolean(arg2->floatval)); 4554 break; 4555 case XPATH_STRING: 4556 if ((arg2->stringval == NULL) || 4557 (arg2->stringval[0] == 0)) ret = 0; 4558 else 4559 ret = 1; 4560 ret = (arg1->boolval == ret); 4561 break; 4562 case XPATH_USERS: 4563 case XPATH_POINT: 4564 case XPATH_RANGE: 4565 case XPATH_LOCATIONSET: 4566 TODO 4567 break; 4568 case XPATH_NODESET: 4569 case XPATH_XSLT_TREE: 4570 break; 4571 } 4572 break; 4573 case XPATH_NUMBER: 4574 switch (arg2->type) { 4575 case XPATH_UNDEFINED: 4576#ifdef DEBUG_EXPR 4577 xmlGenericError(xmlGenericErrorContext, 4578 "Equal: undefined\n"); 4579#endif 4580 break; 4581 case XPATH_BOOLEAN: 4582 ret = (arg2->boolval== 4583 xmlXPathCastNumberToBoolean(arg1->floatval)); 4584 break; 4585 case XPATH_STRING: 4586 valuePush(ctxt, arg2); 4587 xmlXPathNumberFunction(ctxt, 1); 4588 arg2 = valuePop(ctxt); 4589 /* no break on purpose */ 4590 case XPATH_NUMBER: 4591 /* Hand check NaN and Infinity equalities */ 4592 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 4593 ret = 0; 4594 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 4595 if (xmlXPathIsInf(arg2->floatval) == 1) 4596 ret = 1; 4597 else 4598 ret = 0; 4599 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 4600 if (xmlXPathIsInf(arg2->floatval) == -1) 4601 ret = 1; 4602 else 4603 ret = 0; 4604 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 4605 if (xmlXPathIsInf(arg1->floatval) == 1) 4606 ret = 1; 4607 else 4608 ret = 0; 4609 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 4610 if (xmlXPathIsInf(arg1->floatval) == -1) 4611 ret = 1; 4612 else 4613 ret = 0; 4614 } else { 4615 ret = (arg1->floatval == arg2->floatval); 4616 } 4617 break; 4618 case XPATH_USERS: 4619 case XPATH_POINT: 4620 case XPATH_RANGE: 4621 case XPATH_LOCATIONSET: 4622 TODO 4623 break; 4624 case XPATH_NODESET: 4625 case XPATH_XSLT_TREE: 4626 break; 4627 } 4628 break; 4629 case XPATH_STRING: 4630 switch (arg2->type) { 4631 case XPATH_UNDEFINED: 4632#ifdef DEBUG_EXPR 4633 xmlGenericError(xmlGenericErrorContext, 4634 "Equal: undefined\n"); 4635#endif 4636 break; 4637 case XPATH_BOOLEAN: 4638 if ((arg1->stringval == NULL) || 4639 (arg1->stringval[0] == 0)) ret = 0; 4640 else 4641 ret = 1; 4642 ret = (arg2->boolval == ret); 4643 break; 4644 case XPATH_STRING: 4645 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 4646 break; 4647 case XPATH_NUMBER: 4648 valuePush(ctxt, arg1); 4649 xmlXPathNumberFunction(ctxt, 1); 4650 arg1 = valuePop(ctxt); 4651 /* Hand check NaN and Infinity equalities */ 4652 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 4653 ret = 0; 4654 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 4655 if (xmlXPathIsInf(arg2->floatval) == 1) 4656 ret = 1; 4657 else 4658 ret = 0; 4659 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 4660 if (xmlXPathIsInf(arg2->floatval) == -1) 4661 ret = 1; 4662 else 4663 ret = 0; 4664 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 4665 if (xmlXPathIsInf(arg1->floatval) == 1) 4666 ret = 1; 4667 else 4668 ret = 0; 4669 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 4670 if (xmlXPathIsInf(arg1->floatval) == -1) 4671 ret = 1; 4672 else 4673 ret = 0; 4674 } else { 4675 ret = (arg1->floatval == arg2->floatval); 4676 } 4677 break; 4678 case XPATH_USERS: 4679 case XPATH_POINT: 4680 case XPATH_RANGE: 4681 case XPATH_LOCATIONSET: 4682 TODO 4683 break; 4684 case XPATH_NODESET: 4685 case XPATH_XSLT_TREE: 4686 break; 4687 } 4688 break; 4689 case XPATH_USERS: 4690 case XPATH_POINT: 4691 case XPATH_RANGE: 4692 case XPATH_LOCATIONSET: 4693 TODO 4694 break; 4695 case XPATH_NODESET: 4696 case XPATH_XSLT_TREE: 4697 break; 4698 } 4699 xmlXPathFreeObject(arg1); 4700 xmlXPathFreeObject(arg2); 4701 return(ret); 4702} 4703 4704/** 4705 * xmlXPathEqualValues: 4706 * @ctxt: the XPath Parser context 4707 * 4708 * Implement the equal operation on XPath objects content: @arg1 == @arg2 4709 * 4710 * Returns 0 or 1 depending on the results of the test. 4711 */ 4712int 4713xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 4714 xmlXPathObjectPtr arg1, arg2, argtmp; 4715 int ret = 0; 4716 4717 arg2 = valuePop(ctxt); 4718 arg1 = valuePop(ctxt); 4719 if ((arg1 == NULL) || (arg2 == NULL)) { 4720 if (arg1 != NULL) 4721 xmlXPathFreeObject(arg1); 4722 else 4723 xmlXPathFreeObject(arg2); 4724 XP_ERROR0(XPATH_INVALID_OPERAND); 4725 } 4726 4727 if (arg1 == arg2) { 4728#ifdef DEBUG_EXPR 4729 xmlGenericError(xmlGenericErrorContext, 4730 "Equal: by pointer\n"); 4731#endif 4732 return(1); 4733 } 4734 4735 /* 4736 *If either argument is a nodeset, it's a 'special case' 4737 */ 4738 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 4739 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 4740 /* 4741 *Hack it to assure arg1 is the nodeset 4742 */ 4743 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 4744 argtmp = arg2; 4745 arg2 = arg1; 4746 arg1 = argtmp; 4747 } 4748 switch (arg2->type) { 4749 case XPATH_UNDEFINED: 4750#ifdef DEBUG_EXPR 4751 xmlGenericError(xmlGenericErrorContext, 4752 "Equal: undefined\n"); 4753#endif 4754 break; 4755 case XPATH_NODESET: 4756 case XPATH_XSLT_TREE: 4757 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 4758 break; 4759 case XPATH_BOOLEAN: 4760 if ((arg1->nodesetval == NULL) || 4761 (arg1->nodesetval->nodeNr == 0)) ret = 0; 4762 else 4763 ret = 1; 4764 ret = (ret == arg2->boolval); 4765 break; 4766 case XPATH_NUMBER: 4767 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 4768 break; 4769 case XPATH_STRING: 4770 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 4771 break; 4772 case XPATH_USERS: 4773 case XPATH_POINT: 4774 case XPATH_RANGE: 4775 case XPATH_LOCATIONSET: 4776 TODO 4777 break; 4778 } 4779 xmlXPathFreeObject(arg1); 4780 xmlXPathFreeObject(arg2); 4781 return(ret); 4782 } 4783 4784 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 4785} 4786 4787/** 4788 * xmlXPathNotEqualValues: 4789 * @ctxt: the XPath Parser context 4790 * 4791 * Implement the equal operation on XPath objects content: @arg1 == @arg2 4792 * 4793 * Returns 0 or 1 depending on the results of the test. 4794 */ 4795int 4796xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 4797 xmlXPathObjectPtr arg1, arg2, argtmp; 4798 int ret = 0; 4799 4800 arg2 = valuePop(ctxt); 4801 arg1 = valuePop(ctxt); 4802 if ((arg1 == NULL) || (arg2 == NULL)) { 4803 if (arg1 != NULL) 4804 xmlXPathFreeObject(arg1); 4805 else 4806 xmlXPathFreeObject(arg2); 4807 XP_ERROR0(XPATH_INVALID_OPERAND); 4808 } 4809 4810 if (arg1 == arg2) { 4811#ifdef DEBUG_EXPR 4812 xmlGenericError(xmlGenericErrorContext, 4813 "NotEqual: by pointer\n"); 4814#endif 4815 return(0); 4816 } 4817 4818 /* 4819 *If either argument is a nodeset, it's a 'special case' 4820 */ 4821 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 4822 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 4823 /* 4824 *Hack it to assure arg1 is the nodeset 4825 */ 4826 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 4827 argtmp = arg2; 4828 arg2 = arg1; 4829 arg1 = argtmp; 4830 } 4831 switch (arg2->type) { 4832 case XPATH_UNDEFINED: 4833#ifdef DEBUG_EXPR 4834 xmlGenericError(xmlGenericErrorContext, 4835 "NotEqual: undefined\n"); 4836#endif 4837 break; 4838 case XPATH_NODESET: 4839 case XPATH_XSLT_TREE: 4840 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 4841 break; 4842 case XPATH_BOOLEAN: 4843 if ((arg1->nodesetval == NULL) || 4844 (arg1->nodesetval->nodeNr == 0)) ret = 0; 4845 else 4846 ret = 1; 4847 ret = (ret != arg2->boolval); 4848 break; 4849 case XPATH_NUMBER: 4850 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 4851 break; 4852 case XPATH_STRING: 4853 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 4854 break; 4855 case XPATH_USERS: 4856 case XPATH_POINT: 4857 case XPATH_RANGE: 4858 case XPATH_LOCATIONSET: 4859 TODO 4860 break; 4861 } 4862 xmlXPathFreeObject(arg1); 4863 xmlXPathFreeObject(arg2); 4864 return(ret); 4865 } 4866 4867 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 4868} 4869 4870/** 4871 * xmlXPathCompareValues: 4872 * @ctxt: the XPath Parser context 4873 * @inf: less than (1) or greater than (0) 4874 * @strict: is the comparison strict 4875 * 4876 * Implement the compare operation on XPath objects: 4877 * @arg1 < @arg2 (1, 1, ... 4878 * @arg1 <= @arg2 (1, 0, ... 4879 * @arg1 > @arg2 (0, 1, ... 4880 * @arg1 >= @arg2 (0, 0, ... 4881 * 4882 * When neither object to be compared is a node-set and the operator is 4883 * <=, <, >=, >, then the objects are compared by converted both objects 4884 * to numbers and comparing the numbers according to IEEE 754. The < 4885 * comparison will be true if and only if the first number is less than the 4886 * second number. The <= comparison will be true if and only if the first 4887 * number is less than or equal to the second number. The > comparison 4888 * will be true if and only if the first number is greater than the second 4889 * number. The >= comparison will be true if and only if the first number 4890 * is greater than or equal to the second number. 4891 * 4892 * Returns 1 if the comparison succeeded, 0 if it failed 4893 */ 4894int 4895xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 4896 int ret = 0, arg1i = 0, arg2i = 0; 4897 xmlXPathObjectPtr arg1, arg2; 4898 4899 arg2 = valuePop(ctxt); 4900 arg1 = valuePop(ctxt); 4901 if ((arg1 == NULL) || (arg2 == NULL)) { 4902 if (arg1 != NULL) 4903 xmlXPathFreeObject(arg1); 4904 else 4905 xmlXPathFreeObject(arg2); 4906 XP_ERROR0(XPATH_INVALID_OPERAND); 4907 } 4908 4909 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 4910 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 4911 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 4912 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 4913 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 4914 } else { 4915 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 4916 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 4917 arg1, arg2); 4918 } else { 4919 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 4920 arg2, arg1); 4921 } 4922 } 4923 return(ret); 4924 } 4925 4926 if (arg1->type != XPATH_NUMBER) { 4927 valuePush(ctxt, arg1); 4928 xmlXPathNumberFunction(ctxt, 1); 4929 arg1 = valuePop(ctxt); 4930 } 4931 if (arg1->type != XPATH_NUMBER) { 4932 xmlXPathFreeObject(arg1); 4933 xmlXPathFreeObject(arg2); 4934 XP_ERROR0(XPATH_INVALID_OPERAND); 4935 } 4936 if (arg2->type != XPATH_NUMBER) { 4937 valuePush(ctxt, arg2); 4938 xmlXPathNumberFunction(ctxt, 1); 4939 arg2 = valuePop(ctxt); 4940 } 4941 if (arg2->type != XPATH_NUMBER) { 4942 xmlXPathFreeObject(arg1); 4943 xmlXPathFreeObject(arg2); 4944 XP_ERROR0(XPATH_INVALID_OPERAND); 4945 } 4946 /* 4947 * Add tests for infinity and nan 4948 * => feedback on 3.4 for Inf and NaN 4949 */ 4950 /* Hand check NaN and Infinity comparisons */ 4951 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 4952 ret=0; 4953 } else { 4954 arg1i=xmlXPathIsInf(arg1->floatval); 4955 arg2i=xmlXPathIsInf(arg2->floatval); 4956 if (inf && strict) { 4957 if ((arg1i == -1 && arg2i != -1) || 4958 (arg2i == 1 && arg1i != 1)) { 4959 ret = 1; 4960 } else if (arg1i == 0 && arg2i == 0) { 4961 ret = (arg1->floatval < arg2->floatval); 4962 } else { 4963 ret = 0; 4964 } 4965 } 4966 else if (inf && !strict) { 4967 if (arg1i == -1 || arg2i == 1) { 4968 ret = 1; 4969 } else if (arg1i == 0 && arg2i == 0) { 4970 ret = (arg1->floatval <= arg2->floatval); 4971 } else { 4972 ret = 0; 4973 } 4974 } 4975 else if (!inf && strict) { 4976 if ((arg1i == 1 && arg2i != 1) || 4977 (arg2i == -1 && arg1i != -1)) { 4978 ret = 1; 4979 } else if (arg1i == 0 && arg2i == 0) { 4980 ret = (arg1->floatval > arg2->floatval); 4981 } else { 4982 ret = 0; 4983 } 4984 } 4985 else if (!inf && !strict) { 4986 if (arg1i == 1 || arg2i == -1) { 4987 ret = 1; 4988 } else if (arg1i == 0 && arg2i == 0) { 4989 ret = (arg1->floatval >= arg2->floatval); 4990 } else { 4991 ret = 0; 4992 } 4993 } 4994 } 4995 xmlXPathFreeObject(arg1); 4996 xmlXPathFreeObject(arg2); 4997 return(ret); 4998} 4999 5000/** 5001 * xmlXPathValueFlipSign: 5002 * @ctxt: the XPath Parser context 5003 * 5004 * Implement the unary - operation on an XPath object 5005 * The numeric operators convert their operands to numbers as if 5006 * by calling the number function. 5007 */ 5008void 5009xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 5010 CAST_TO_NUMBER; 5011 CHECK_TYPE(XPATH_NUMBER); 5012 if (xmlXPathIsNaN(ctxt->value->floatval)) 5013 ctxt->value->floatval=xmlXPathNAN; 5014 else if (xmlXPathIsInf(ctxt->value->floatval) == 1) 5015 ctxt->value->floatval=xmlXPathNINF; 5016 else if (xmlXPathIsInf(ctxt->value->floatval) == -1) 5017 ctxt->value->floatval=xmlXPathPINF; 5018 else if (ctxt->value->floatval == 0) { 5019 if (xmlXPathGetSign(ctxt->value->floatval) == 0) 5020 ctxt->value->floatval = xmlXPathNZERO; 5021 else 5022 ctxt->value->floatval = 0; 5023 } 5024 else 5025 ctxt->value->floatval = - ctxt->value->floatval; 5026} 5027 5028/** 5029 * xmlXPathAddValues: 5030 * @ctxt: the XPath Parser context 5031 * 5032 * Implement the add operation on XPath objects: 5033 * The numeric operators convert their operands to numbers as if 5034 * by calling the number function. 5035 */ 5036void 5037xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 5038 xmlXPathObjectPtr arg; 5039 double val; 5040 5041 arg = valuePop(ctxt); 5042 if (arg == NULL) 5043 XP_ERROR(XPATH_INVALID_OPERAND); 5044 val = xmlXPathCastToNumber(arg); 5045 xmlXPathFreeObject(arg); 5046 5047 CAST_TO_NUMBER; 5048 CHECK_TYPE(XPATH_NUMBER); 5049 ctxt->value->floatval += val; 5050} 5051 5052/** 5053 * xmlXPathSubValues: 5054 * @ctxt: the XPath Parser context 5055 * 5056 * Implement the subtraction operation on XPath objects: 5057 * The numeric operators convert their operands to numbers as if 5058 * by calling the number function. 5059 */ 5060void 5061xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 5062 xmlXPathObjectPtr arg; 5063 double val; 5064 5065 arg = valuePop(ctxt); 5066 if (arg == NULL) 5067 XP_ERROR(XPATH_INVALID_OPERAND); 5068 val = xmlXPathCastToNumber(arg); 5069 xmlXPathFreeObject(arg); 5070 5071 CAST_TO_NUMBER; 5072 CHECK_TYPE(XPATH_NUMBER); 5073 ctxt->value->floatval -= val; 5074} 5075 5076/** 5077 * xmlXPathMultValues: 5078 * @ctxt: the XPath Parser context 5079 * 5080 * Implement the multiply operation on XPath objects: 5081 * The numeric operators convert their operands to numbers as if 5082 * by calling the number function. 5083 */ 5084void 5085xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 5086 xmlXPathObjectPtr arg; 5087 double val; 5088 5089 arg = valuePop(ctxt); 5090 if (arg == NULL) 5091 XP_ERROR(XPATH_INVALID_OPERAND); 5092 val = xmlXPathCastToNumber(arg); 5093 xmlXPathFreeObject(arg); 5094 5095 CAST_TO_NUMBER; 5096 CHECK_TYPE(XPATH_NUMBER); 5097 ctxt->value->floatval *= val; 5098} 5099 5100/** 5101 * xmlXPathDivValues: 5102 * @ctxt: the XPath Parser context 5103 * 5104 * Implement the div operation on XPath objects @arg1 / @arg2: 5105 * The numeric operators convert their operands to numbers as if 5106 * by calling the number function. 5107 */ 5108void 5109xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 5110 xmlXPathObjectPtr arg; 5111 double val; 5112 5113 arg = valuePop(ctxt); 5114 if (arg == NULL) 5115 XP_ERROR(XPATH_INVALID_OPERAND); 5116 val = xmlXPathCastToNumber(arg); 5117 xmlXPathFreeObject(arg); 5118 5119 CAST_TO_NUMBER; 5120 CHECK_TYPE(XPATH_NUMBER); 5121 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) 5122 ctxt->value->floatval = xmlXPathNAN; 5123 else if (val == 0 && xmlXPathGetSign(val) != 0) { 5124 if (ctxt->value->floatval == 0) 5125 ctxt->value->floatval = xmlXPathNAN; 5126 else if (ctxt->value->floatval > 0) 5127 ctxt->value->floatval = xmlXPathNINF; 5128 else if (ctxt->value->floatval < 0) 5129 ctxt->value->floatval = xmlXPathPINF; 5130 } 5131 else if (val == 0) { 5132 if (ctxt->value->floatval == 0) 5133 ctxt->value->floatval = xmlXPathNAN; 5134 else if (ctxt->value->floatval > 0) 5135 ctxt->value->floatval = xmlXPathPINF; 5136 else if (ctxt->value->floatval < 0) 5137 ctxt->value->floatval = xmlXPathNINF; 5138 } else 5139 ctxt->value->floatval /= val; 5140} 5141 5142/** 5143 * xmlXPathModValues: 5144 * @ctxt: the XPath Parser context 5145 * 5146 * Implement the mod operation on XPath objects: @arg1 / @arg2 5147 * The numeric operators convert their operands to numbers as if 5148 * by calling the number function. 5149 */ 5150void 5151xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 5152 xmlXPathObjectPtr arg; 5153 double arg1, arg2; 5154 5155 arg = valuePop(ctxt); 5156 if (arg == NULL) 5157 XP_ERROR(XPATH_INVALID_OPERAND); 5158 arg2 = xmlXPathCastToNumber(arg); 5159 xmlXPathFreeObject(arg); 5160 5161 CAST_TO_NUMBER; 5162 CHECK_TYPE(XPATH_NUMBER); 5163 arg1 = ctxt->value->floatval; 5164 if (arg2 == 0) 5165 ctxt->value->floatval = xmlXPathNAN; 5166 else { 5167 ctxt->value->floatval = fmod(arg1, arg2); 5168 } 5169} 5170 5171/************************************************************************ 5172 * * 5173 * The traversal functions * 5174 * * 5175 ************************************************************************/ 5176 5177/* 5178 * A traversal function enumerates nodes along an axis. 5179 * Initially it must be called with NULL, and it indicates 5180 * termination on the axis by returning NULL. 5181 */ 5182typedef xmlNodePtr (*xmlXPathTraversalFunction) 5183 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 5184 5185/** 5186 * xmlXPathNextSelf: 5187 * @ctxt: the XPath Parser context 5188 * @cur: the current node in the traversal 5189 * 5190 * Traversal function for the "self" direction 5191 * The self axis contains just the context node itself 5192 * 5193 * Returns the next element following that axis 5194 */ 5195xmlNodePtr 5196xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5197 if (cur == NULL) 5198 return(ctxt->context->node); 5199 return(NULL); 5200} 5201 5202/** 5203 * xmlXPathNextChild: 5204 * @ctxt: the XPath Parser context 5205 * @cur: the current node in the traversal 5206 * 5207 * Traversal function for the "child" direction 5208 * The child axis contains the children of the context node in document order. 5209 * 5210 * Returns the next element following that axis 5211 */ 5212xmlNodePtr 5213xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5214 if (cur == NULL) { 5215 if (ctxt->context->node == NULL) return(NULL); 5216 switch (ctxt->context->node->type) { 5217 case XML_ELEMENT_NODE: 5218 case XML_TEXT_NODE: 5219 case XML_CDATA_SECTION_NODE: 5220 case XML_ENTITY_REF_NODE: 5221 case XML_ENTITY_NODE: 5222 case XML_PI_NODE: 5223 case XML_COMMENT_NODE: 5224 case XML_NOTATION_NODE: 5225 case XML_DTD_NODE: 5226 return(ctxt->context->node->children); 5227 case XML_DOCUMENT_NODE: 5228 case XML_DOCUMENT_TYPE_NODE: 5229 case XML_DOCUMENT_FRAG_NODE: 5230 case XML_HTML_DOCUMENT_NODE: 5231#ifdef LIBXML_DOCB_ENABLED 5232 case XML_DOCB_DOCUMENT_NODE: 5233#endif 5234 return(((xmlDocPtr) ctxt->context->node)->children); 5235 case XML_ELEMENT_DECL: 5236 case XML_ATTRIBUTE_DECL: 5237 case XML_ENTITY_DECL: 5238 case XML_ATTRIBUTE_NODE: 5239 case XML_NAMESPACE_DECL: 5240 case XML_XINCLUDE_START: 5241 case XML_XINCLUDE_END: 5242 return(NULL); 5243 } 5244 return(NULL); 5245 } 5246 if ((cur->type == XML_DOCUMENT_NODE) || 5247 (cur->type == XML_HTML_DOCUMENT_NODE)) 5248 return(NULL); 5249 return(cur->next); 5250} 5251 5252/** 5253 * xmlXPathNextDescendant: 5254 * @ctxt: the XPath Parser context 5255 * @cur: the current node in the traversal 5256 * 5257 * Traversal function for the "descendant" direction 5258 * the descendant axis contains the descendants of the context node in document 5259 * order; a descendant is a child or a child of a child and so on. 5260 * 5261 * Returns the next element following that axis 5262 */ 5263xmlNodePtr 5264xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5265 if (cur == NULL) { 5266 if (ctxt->context->node == NULL) 5267 return(NULL); 5268 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 5269 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 5270 return(NULL); 5271 5272 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 5273 return(ctxt->context->doc->children); 5274 return(ctxt->context->node->children); 5275 } 5276 5277 if (cur->children != NULL) { 5278 /* 5279 * Do not descend on entities declarations 5280 */ 5281 if (cur->children->type != XML_ENTITY_DECL) { 5282 cur = cur->children; 5283 /* 5284 * Skip DTDs 5285 */ 5286 if (cur->type != XML_DTD_NODE) 5287 return(cur); 5288 } 5289 } 5290 5291 if (cur == ctxt->context->node) return(NULL); 5292 5293 while (cur->next != NULL) { 5294 cur = cur->next; 5295 if ((cur->type != XML_ENTITY_DECL) && 5296 (cur->type != XML_DTD_NODE)) 5297 return(cur); 5298 } 5299 5300 do { 5301 cur = cur->parent; 5302 if (cur == NULL) return(NULL); 5303 if (cur == ctxt->context->node) return(NULL); 5304 if (cur->next != NULL) { 5305 cur = cur->next; 5306 return(cur); 5307 } 5308 } while (cur != NULL); 5309 return(cur); 5310} 5311 5312/** 5313 * xmlXPathNextDescendantOrSelf: 5314 * @ctxt: the XPath Parser context 5315 * @cur: the current node in the traversal 5316 * 5317 * Traversal function for the "descendant-or-self" direction 5318 * the descendant-or-self axis contains the context node and the descendants 5319 * of the context node in document order; thus the context node is the first 5320 * node on the axis, and the first child of the context node is the second node 5321 * on the axis 5322 * 5323 * Returns the next element following that axis 5324 */ 5325xmlNodePtr 5326xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5327 if (cur == NULL) { 5328 if (ctxt->context->node == NULL) 5329 return(NULL); 5330 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 5331 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 5332 return(NULL); 5333 return(ctxt->context->node); 5334 } 5335 5336 return(xmlXPathNextDescendant(ctxt, cur)); 5337} 5338 5339/** 5340 * xmlXPathNextParent: 5341 * @ctxt: the XPath Parser context 5342 * @cur: the current node in the traversal 5343 * 5344 * Traversal function for the "parent" direction 5345 * The parent axis contains the parent of the context node, if there is one. 5346 * 5347 * Returns the next element following that axis 5348 */ 5349xmlNodePtr 5350xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5351 /* 5352 * the parent of an attribute or namespace node is the element 5353 * to which the attribute or namespace node is attached 5354 * Namespace handling !!! 5355 */ 5356 if (cur == NULL) { 5357 if (ctxt->context->node == NULL) return(NULL); 5358 switch (ctxt->context->node->type) { 5359 case XML_ELEMENT_NODE: 5360 case XML_TEXT_NODE: 5361 case XML_CDATA_SECTION_NODE: 5362 case XML_ENTITY_REF_NODE: 5363 case XML_ENTITY_NODE: 5364 case XML_PI_NODE: 5365 case XML_COMMENT_NODE: 5366 case XML_NOTATION_NODE: 5367 case XML_DTD_NODE: 5368 case XML_ELEMENT_DECL: 5369 case XML_ATTRIBUTE_DECL: 5370 case XML_XINCLUDE_START: 5371 case XML_XINCLUDE_END: 5372 case XML_ENTITY_DECL: 5373 if (ctxt->context->node->parent == NULL) 5374 return((xmlNodePtr) ctxt->context->doc); 5375 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 5376 ((ctxt->context->node->parent->name[0] == ' ') || 5377 (xmlStrEqual(ctxt->context->node->parent->name, 5378 BAD_CAST "fake node libxslt")))) 5379 return(NULL); 5380 return(ctxt->context->node->parent); 5381 case XML_ATTRIBUTE_NODE: { 5382 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 5383 5384 return(att->parent); 5385 } 5386 case XML_DOCUMENT_NODE: 5387 case XML_DOCUMENT_TYPE_NODE: 5388 case XML_DOCUMENT_FRAG_NODE: 5389 case XML_HTML_DOCUMENT_NODE: 5390#ifdef LIBXML_DOCB_ENABLED 5391 case XML_DOCB_DOCUMENT_NODE: 5392#endif 5393 return(NULL); 5394 case XML_NAMESPACE_DECL: { 5395 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 5396 5397 if ((ns->next != NULL) && 5398 (ns->next->type != XML_NAMESPACE_DECL)) 5399 return((xmlNodePtr) ns->next); 5400 return(NULL); 5401 } 5402 } 5403 } 5404 return(NULL); 5405} 5406 5407/** 5408 * xmlXPathNextAncestor: 5409 * @ctxt: the XPath Parser context 5410 * @cur: the current node in the traversal 5411 * 5412 * Traversal function for the "ancestor" direction 5413 * the ancestor axis contains the ancestors of the context node; the ancestors 5414 * of the context node consist of the parent of context node and the parent's 5415 * parent and so on; the nodes are ordered in reverse document order; thus the 5416 * parent is the first node on the axis, and the parent's parent is the second 5417 * node on the axis 5418 * 5419 * Returns the next element following that axis 5420 */ 5421xmlNodePtr 5422xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5423 /* 5424 * the parent of an attribute or namespace node is the element 5425 * to which the attribute or namespace node is attached 5426 * !!!!!!!!!!!!! 5427 */ 5428 if (cur == NULL) { 5429 if (ctxt->context->node == NULL) return(NULL); 5430 switch (ctxt->context->node->type) { 5431 case XML_ELEMENT_NODE: 5432 case XML_TEXT_NODE: 5433 case XML_CDATA_SECTION_NODE: 5434 case XML_ENTITY_REF_NODE: 5435 case XML_ENTITY_NODE: 5436 case XML_PI_NODE: 5437 case XML_COMMENT_NODE: 5438 case XML_DTD_NODE: 5439 case XML_ELEMENT_DECL: 5440 case XML_ATTRIBUTE_DECL: 5441 case XML_ENTITY_DECL: 5442 case XML_NOTATION_NODE: 5443 case XML_XINCLUDE_START: 5444 case XML_XINCLUDE_END: 5445 if (ctxt->context->node->parent == NULL) 5446 return((xmlNodePtr) ctxt->context->doc); 5447 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 5448 ((ctxt->context->node->parent->name[0] == ' ') || 5449 (xmlStrEqual(ctxt->context->node->parent->name, 5450 BAD_CAST "fake node libxslt")))) 5451 return(NULL); 5452 return(ctxt->context->node->parent); 5453 case XML_ATTRIBUTE_NODE: { 5454 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 5455 5456 return(tmp->parent); 5457 } 5458 case XML_DOCUMENT_NODE: 5459 case XML_DOCUMENT_TYPE_NODE: 5460 case XML_DOCUMENT_FRAG_NODE: 5461 case XML_HTML_DOCUMENT_NODE: 5462#ifdef LIBXML_DOCB_ENABLED 5463 case XML_DOCB_DOCUMENT_NODE: 5464#endif 5465 return(NULL); 5466 case XML_NAMESPACE_DECL: { 5467 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 5468 5469 if ((ns->next != NULL) && 5470 (ns->next->type != XML_NAMESPACE_DECL)) 5471 return((xmlNodePtr) ns->next); 5472 /* Bad, how did that namespace ended-up there ? */ 5473 return(NULL); 5474 } 5475 } 5476 return(NULL); 5477 } 5478 if (cur == ctxt->context->doc->children) 5479 return((xmlNodePtr) ctxt->context->doc); 5480 if (cur == (xmlNodePtr) ctxt->context->doc) 5481 return(NULL); 5482 switch (cur->type) { 5483 case XML_ELEMENT_NODE: 5484 case XML_TEXT_NODE: 5485 case XML_CDATA_SECTION_NODE: 5486 case XML_ENTITY_REF_NODE: 5487 case XML_ENTITY_NODE: 5488 case XML_PI_NODE: 5489 case XML_COMMENT_NODE: 5490 case XML_NOTATION_NODE: 5491 case XML_DTD_NODE: 5492 case XML_ELEMENT_DECL: 5493 case XML_ATTRIBUTE_DECL: 5494 case XML_ENTITY_DECL: 5495 case XML_XINCLUDE_START: 5496 case XML_XINCLUDE_END: 5497 if (cur->parent == NULL) 5498 return(NULL); 5499 if ((cur->parent->type == XML_ELEMENT_NODE) && 5500 ((cur->parent->name[0] == ' ') || 5501 (xmlStrEqual(cur->parent->name, 5502 BAD_CAST "fake node libxslt")))) 5503 return(NULL); 5504 return(cur->parent); 5505 case XML_ATTRIBUTE_NODE: { 5506 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 5507 5508 return(att->parent); 5509 } 5510 case XML_NAMESPACE_DECL: { 5511 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 5512 5513 if ((ns->next != NULL) && 5514 (ns->next->type != XML_NAMESPACE_DECL)) 5515 return((xmlNodePtr) ns->next); 5516 /* Bad, how did that namespace ended-up there ? */ 5517 return(NULL); 5518 } 5519 case XML_DOCUMENT_NODE: 5520 case XML_DOCUMENT_TYPE_NODE: 5521 case XML_DOCUMENT_FRAG_NODE: 5522 case XML_HTML_DOCUMENT_NODE: 5523#ifdef LIBXML_DOCB_ENABLED 5524 case XML_DOCB_DOCUMENT_NODE: 5525#endif 5526 return(NULL); 5527 } 5528 return(NULL); 5529} 5530 5531/** 5532 * xmlXPathNextAncestorOrSelf: 5533 * @ctxt: the XPath Parser context 5534 * @cur: the current node in the traversal 5535 * 5536 * Traversal function for the "ancestor-or-self" direction 5537 * he ancestor-or-self axis contains the context node and ancestors of 5538 * the context node in reverse document order; thus the context node is 5539 * the first node on the axis, and the context node's parent the second; 5540 * parent here is defined the same as with the parent axis. 5541 * 5542 * Returns the next element following that axis 5543 */ 5544xmlNodePtr 5545xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5546 if (cur == NULL) 5547 return(ctxt->context->node); 5548 return(xmlXPathNextAncestor(ctxt, cur)); 5549} 5550 5551/** 5552 * xmlXPathNextFollowingSibling: 5553 * @ctxt: the XPath Parser context 5554 * @cur: the current node in the traversal 5555 * 5556 * Traversal function for the "following-sibling" direction 5557 * The following-sibling axis contains the following siblings of the context 5558 * node in document order. 5559 * 5560 * Returns the next element following that axis 5561 */ 5562xmlNodePtr 5563xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5564 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 5565 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 5566 return(NULL); 5567 if (cur == (xmlNodePtr) ctxt->context->doc) 5568 return(NULL); 5569 if (cur == NULL) 5570 return(ctxt->context->node->next); 5571 return(cur->next); 5572} 5573 5574/** 5575 * xmlXPathNextPrecedingSibling: 5576 * @ctxt: the XPath Parser context 5577 * @cur: the current node in the traversal 5578 * 5579 * Traversal function for the "preceding-sibling" direction 5580 * The preceding-sibling axis contains the preceding siblings of the context 5581 * node in reverse document order; the first preceding sibling is first on the 5582 * axis; the sibling preceding that node is the second on the axis and so on. 5583 * 5584 * Returns the next element following that axis 5585 */ 5586xmlNodePtr 5587xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5588 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 5589 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 5590 return(NULL); 5591 if (cur == (xmlNodePtr) ctxt->context->doc) 5592 return(NULL); 5593 if (cur == NULL) 5594 return(ctxt->context->node->prev); 5595 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 5596 cur = cur->prev; 5597 if (cur == NULL) 5598 return(ctxt->context->node->prev); 5599 } 5600 return(cur->prev); 5601} 5602 5603/** 5604 * xmlXPathNextFollowing: 5605 * @ctxt: the XPath Parser context 5606 * @cur: the current node in the traversal 5607 * 5608 * Traversal function for the "following" direction 5609 * The following axis contains all nodes in the same document as the context 5610 * node that are after the context node in document order, excluding any 5611 * descendants and excluding attribute nodes and namespace nodes; the nodes 5612 * are ordered in document order 5613 * 5614 * Returns the next element following that axis 5615 */ 5616xmlNodePtr 5617xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5618 if (cur != NULL && cur->children != NULL) 5619 return cur->children ; 5620 if (cur == NULL) cur = ctxt->context->node; 5621 if (cur == NULL) return(NULL) ; /* ERROR */ 5622 if (cur->next != NULL) return(cur->next) ; 5623 do { 5624 cur = cur->parent; 5625 if (cur == NULL) return(NULL); 5626 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 5627 if (cur->next != NULL) return(cur->next); 5628 } while (cur != NULL); 5629 return(cur); 5630} 5631 5632/* 5633 * xmlXPathIsAncestor: 5634 * @ancestor: the ancestor node 5635 * @node: the current node 5636 * 5637 * Check that @ancestor is a @node's ancestor 5638 * 5639 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 5640 */ 5641static int 5642xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 5643 if ((ancestor == NULL) || (node == NULL)) return(0); 5644 /* nodes need to be in the same document */ 5645 if (ancestor->doc != node->doc) return(0); 5646 /* avoid searching if ancestor or node is the root node */ 5647 if (ancestor == (xmlNodePtr) node->doc) return(1); 5648 if (node == (xmlNodePtr) ancestor->doc) return(0); 5649 while (node->parent != NULL) { 5650 if (node->parent == ancestor) 5651 return(1); 5652 node = node->parent; 5653 } 5654 return(0); 5655} 5656 5657/** 5658 * xmlXPathNextPreceding: 5659 * @ctxt: the XPath Parser context 5660 * @cur: the current node in the traversal 5661 * 5662 * Traversal function for the "preceding" direction 5663 * the preceding axis contains all nodes in the same document as the context 5664 * node that are before the context node in document order, excluding any 5665 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 5666 * ordered in reverse document order 5667 * 5668 * Returns the next element following that axis 5669 */ 5670xmlNodePtr 5671xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 5672{ 5673 if (cur == NULL) 5674 cur = ctxt->context->node; 5675 if (cur == NULL) 5676 return (NULL); 5677 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 5678 cur = cur->prev; 5679 do { 5680 if (cur->prev != NULL) { 5681 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 5682 return (cur); 5683 } 5684 5685 cur = cur->parent; 5686 if (cur == NULL) 5687 return (NULL); 5688 if (cur == ctxt->context->doc->children) 5689 return (NULL); 5690 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 5691 return (cur); 5692} 5693 5694/** 5695 * xmlXPathNextPrecedingInternal: 5696 * @ctxt: the XPath Parser context 5697 * @cur: the current node in the traversal 5698 * 5699 * Traversal function for the "preceding" direction 5700 * the preceding axis contains all nodes in the same document as the context 5701 * node that are before the context node in document order, excluding any 5702 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 5703 * ordered in reverse document order 5704 * This is a faster implementation but internal only since it requires a 5705 * state kept in the parser context: ctxt->ancestor. 5706 * 5707 * Returns the next element following that axis 5708 */ 5709static xmlNodePtr 5710xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 5711 xmlNodePtr cur) 5712{ 5713 if (cur == NULL) { 5714 cur = ctxt->context->node; 5715 if (cur == NULL) 5716 return (NULL); 5717 ctxt->ancestor = cur->parent; 5718 } 5719 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 5720 cur = cur->prev; 5721 while (cur->prev == NULL) { 5722 cur = cur->parent; 5723 if (cur == NULL) 5724 return (NULL); 5725 if (cur == ctxt->context->doc->children) 5726 return (NULL); 5727 if (cur != ctxt->ancestor) 5728 return (cur); 5729 ctxt->ancestor = cur->parent; 5730 } 5731 cur = cur->prev; 5732 while (cur->last != NULL) 5733 cur = cur->last; 5734 return (cur); 5735} 5736 5737/** 5738 * xmlXPathNextNamespace: 5739 * @ctxt: the XPath Parser context 5740 * @cur: the current attribute in the traversal 5741 * 5742 * Traversal function for the "namespace" direction 5743 * the namespace axis contains the namespace nodes of the context node; 5744 * the order of nodes on this axis is implementation-defined; the axis will 5745 * be empty unless the context node is an element 5746 * 5747 * We keep the XML namespace node at the end of the list. 5748 * 5749 * Returns the next element following that axis 5750 */ 5751xmlNodePtr 5752xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5753 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 5754 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) { 5755 if (ctxt->context->tmpNsList != NULL) 5756 xmlFree(ctxt->context->tmpNsList); 5757 ctxt->context->tmpNsList = 5758 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 5759 ctxt->context->tmpNsNr = 0; 5760 if (ctxt->context->tmpNsList != NULL) { 5761 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 5762 ctxt->context->tmpNsNr++; 5763 } 5764 } 5765 return((xmlNodePtr) xmlXPathXMLNamespace); 5766 } 5767 if (ctxt->context->tmpNsNr > 0) { 5768 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 5769 } else { 5770 if (ctxt->context->tmpNsList != NULL) 5771 xmlFree(ctxt->context->tmpNsList); 5772 ctxt->context->tmpNsList = NULL; 5773 return(NULL); 5774 } 5775} 5776 5777/** 5778 * xmlXPathNextAttribute: 5779 * @ctxt: the XPath Parser context 5780 * @cur: the current attribute in the traversal 5781 * 5782 * Traversal function for the "attribute" direction 5783 * TODO: support DTD inherited default attributes 5784 * 5785 * Returns the next element following that axis 5786 */ 5787xmlNodePtr 5788xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5789 if (ctxt->context->node == NULL) 5790 return(NULL); 5791 if (ctxt->context->node->type != XML_ELEMENT_NODE) 5792 return(NULL); 5793 if (cur == NULL) { 5794 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 5795 return(NULL); 5796 return((xmlNodePtr)ctxt->context->node->properties); 5797 } 5798 return((xmlNodePtr)cur->next); 5799} 5800 5801/************************************************************************ 5802 * * 5803 * NodeTest Functions * 5804 * * 5805 ************************************************************************/ 5806 5807#define IS_FUNCTION 200 5808 5809 5810/************************************************************************ 5811 * * 5812 * Implicit tree core function library * 5813 * * 5814 ************************************************************************/ 5815 5816/** 5817 * xmlXPathRoot: 5818 * @ctxt: the XPath Parser context 5819 * 5820 * Initialize the context to the root of the document 5821 */ 5822void 5823xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 5824 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 5825 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 5826} 5827 5828/************************************************************************ 5829 * * 5830 * The explicit core function library * 5831 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 5832 * * 5833 ************************************************************************/ 5834 5835 5836/** 5837 * xmlXPathLastFunction: 5838 * @ctxt: the XPath Parser context 5839 * @nargs: the number of arguments 5840 * 5841 * Implement the last() XPath function 5842 * number last() 5843 * The last function returns the number of nodes in the context node list. 5844 */ 5845void 5846xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5847 CHECK_ARITY(0); 5848 if (ctxt->context->contextSize >= 0) { 5849 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize)); 5850#ifdef DEBUG_EXPR 5851 xmlGenericError(xmlGenericErrorContext, 5852 "last() : %d\n", ctxt->context->contextSize); 5853#endif 5854 } else { 5855 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 5856 } 5857} 5858 5859/** 5860 * xmlXPathPositionFunction: 5861 * @ctxt: the XPath Parser context 5862 * @nargs: the number of arguments 5863 * 5864 * Implement the position() XPath function 5865 * number position() 5866 * The position function returns the position of the context node in the 5867 * context node list. The first position is 1, and so the last position 5868 * will be equal to last(). 5869 */ 5870void 5871xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5872 CHECK_ARITY(0); 5873 if (ctxt->context->proximityPosition >= 0) { 5874 valuePush(ctxt, 5875 xmlXPathNewFloat((double) ctxt->context->proximityPosition)); 5876#ifdef DEBUG_EXPR 5877 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 5878 ctxt->context->proximityPosition); 5879#endif 5880 } else { 5881 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 5882 } 5883} 5884 5885/** 5886 * xmlXPathCountFunction: 5887 * @ctxt: the XPath Parser context 5888 * @nargs: the number of arguments 5889 * 5890 * Implement the count() XPath function 5891 * number count(node-set) 5892 */ 5893void 5894xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5895 xmlXPathObjectPtr cur; 5896 5897 CHECK_ARITY(1); 5898 if ((ctxt->value == NULL) || 5899 ((ctxt->value->type != XPATH_NODESET) && 5900 (ctxt->value->type != XPATH_XSLT_TREE))) 5901 XP_ERROR(XPATH_INVALID_TYPE); 5902 cur = valuePop(ctxt); 5903 5904 if ((cur == NULL) || (cur->nodesetval == NULL)) 5905 valuePush(ctxt, xmlXPathNewFloat((double) 0)); 5906 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 5907 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr)); 5908 } else { 5909 if ((cur->nodesetval->nodeNr != 1) || 5910 (cur->nodesetval->nodeTab == NULL)) { 5911 valuePush(ctxt, xmlXPathNewFloat((double) 0)); 5912 } else { 5913 xmlNodePtr tmp; 5914 int i = 0; 5915 5916 tmp = cur->nodesetval->nodeTab[0]; 5917 if (tmp != NULL) { 5918 tmp = tmp->children; 5919 while (tmp != NULL) { 5920 tmp = tmp->next; 5921 i++; 5922 } 5923 } 5924 valuePush(ctxt, xmlXPathNewFloat((double) i)); 5925 } 5926 } 5927 xmlXPathFreeObject(cur); 5928} 5929 5930/** 5931 * xmlXPathGetElementsByIds: 5932 * @doc: the document 5933 * @ids: a whitespace separated list of IDs 5934 * 5935 * Selects elements by their unique ID. 5936 * 5937 * Returns a node-set of selected elements. 5938 */ 5939static xmlNodeSetPtr 5940xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 5941 xmlNodeSetPtr ret; 5942 const xmlChar *cur = ids; 5943 xmlChar *ID; 5944 xmlAttrPtr attr; 5945 xmlNodePtr elem = NULL; 5946 5947 if (ids == NULL) return(NULL); 5948 5949 ret = xmlXPathNodeSetCreate(NULL); 5950 5951 while (IS_BLANK(*cur)) cur++; 5952 while (*cur != 0) { 5953 while ((!IS_BLANK(*cur)) && (*cur != 0)) 5954 cur++; 5955 5956 ID = xmlStrndup(ids, cur - ids); 5957 if (ID != NULL) { 5958 if (xmlValidateNCName(ID, 1) == 0) { 5959 attr = xmlGetID(doc, ID); 5960 if (attr != NULL) { 5961 if (attr->type == XML_ATTRIBUTE_NODE) 5962 elem = attr->parent; 5963 else if (attr->type == XML_ELEMENT_NODE) 5964 elem = (xmlNodePtr) attr; 5965 else 5966 elem = NULL; 5967 if (elem != NULL) 5968 xmlXPathNodeSetAdd(ret, elem); 5969 } 5970 } 5971 xmlFree(ID); 5972 } 5973 5974 while (IS_BLANK(*cur)) cur++; 5975 ids = cur; 5976 } 5977 return(ret); 5978} 5979 5980/** 5981 * xmlXPathIdFunction: 5982 * @ctxt: the XPath Parser context 5983 * @nargs: the number of arguments 5984 * 5985 * Implement the id() XPath function 5986 * node-set id(object) 5987 * The id function selects elements by their unique ID 5988 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 5989 * then the result is the union of the result of applying id to the 5990 * string value of each of the nodes in the argument node-set. When the 5991 * argument to id is of any other type, the argument is converted to a 5992 * string as if by a call to the string function; the string is split 5993 * into a whitespace-separated list of tokens (whitespace is any sequence 5994 * of characters matching the production S); the result is a node-set 5995 * containing the elements in the same document as the context node that 5996 * have a unique ID equal to any of the tokens in the list. 5997 */ 5998void 5999xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6000 xmlChar *tokens; 6001 xmlNodeSetPtr ret; 6002 xmlXPathObjectPtr obj; 6003 6004 CHECK_ARITY(1); 6005 obj = valuePop(ctxt); 6006 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 6007 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 6008 xmlNodeSetPtr ns; 6009 int i; 6010 6011 ret = xmlXPathNodeSetCreate(NULL); 6012 6013 if (obj->nodesetval != NULL) { 6014 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 6015 tokens = 6016 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 6017 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 6018 ret = xmlXPathNodeSetMerge(ret, ns); 6019 xmlXPathFreeNodeSet(ns); 6020 if (tokens != NULL) 6021 xmlFree(tokens); 6022 } 6023 } 6024 6025 xmlXPathFreeObject(obj); 6026 valuePush(ctxt, xmlXPathWrapNodeSet(ret)); 6027 return; 6028 } 6029 obj = xmlXPathConvertString(obj); 6030 6031 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 6032 valuePush(ctxt, xmlXPathWrapNodeSet(ret)); 6033 6034 xmlXPathFreeObject(obj); 6035 return; 6036} 6037 6038/** 6039 * xmlXPathLocalNameFunction: 6040 * @ctxt: the XPath Parser context 6041 * @nargs: the number of arguments 6042 * 6043 * Implement the local-name() XPath function 6044 * string local-name(node-set?) 6045 * The local-name function returns a string containing the local part 6046 * of the name of the node in the argument node-set that is first in 6047 * document order. If the node-set is empty or the first node has no 6048 * name, an empty string is returned. If the argument is omitted it 6049 * defaults to the context node. 6050 */ 6051void 6052xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6053 xmlXPathObjectPtr cur; 6054 6055 if (nargs == 0) { 6056 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 6057 nargs = 1; 6058 } 6059 6060 CHECK_ARITY(1); 6061 if ((ctxt->value == NULL) || 6062 ((ctxt->value->type != XPATH_NODESET) && 6063 (ctxt->value->type != XPATH_XSLT_TREE))) 6064 XP_ERROR(XPATH_INVALID_TYPE); 6065 cur = valuePop(ctxt); 6066 6067 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 6068 valuePush(ctxt, xmlXPathNewCString("")); 6069 } else { 6070 int i = 0; /* Should be first in document order !!!!! */ 6071 switch (cur->nodesetval->nodeTab[i]->type) { 6072 case XML_ELEMENT_NODE: 6073 case XML_ATTRIBUTE_NODE: 6074 case XML_PI_NODE: 6075 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 6076 valuePush(ctxt, xmlXPathNewCString("")); 6077 else 6078 valuePush(ctxt, 6079 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name)); 6080 break; 6081 case XML_NAMESPACE_DECL: 6082 valuePush(ctxt, xmlXPathNewString( 6083 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 6084 break; 6085 default: 6086 valuePush(ctxt, xmlXPathNewCString("")); 6087 } 6088 } 6089 xmlXPathFreeObject(cur); 6090} 6091 6092/** 6093 * xmlXPathNamespaceURIFunction: 6094 * @ctxt: the XPath Parser context 6095 * @nargs: the number of arguments 6096 * 6097 * Implement the namespace-uri() XPath function 6098 * string namespace-uri(node-set?) 6099 * The namespace-uri function returns a string containing the 6100 * namespace URI of the expanded name of the node in the argument 6101 * node-set that is first in document order. If the node-set is empty, 6102 * the first node has no name, or the expanded name has no namespace 6103 * URI, an empty string is returned. If the argument is omitted it 6104 * defaults to the context node. 6105 */ 6106void 6107xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6108 xmlXPathObjectPtr cur; 6109 6110 if (nargs == 0) { 6111 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 6112 nargs = 1; 6113 } 6114 CHECK_ARITY(1); 6115 if ((ctxt->value == NULL) || 6116 ((ctxt->value->type != XPATH_NODESET) && 6117 (ctxt->value->type != XPATH_XSLT_TREE))) 6118 XP_ERROR(XPATH_INVALID_TYPE); 6119 cur = valuePop(ctxt); 6120 6121 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 6122 valuePush(ctxt, xmlXPathNewCString("")); 6123 } else { 6124 int i = 0; /* Should be first in document order !!!!! */ 6125 switch (cur->nodesetval->nodeTab[i]->type) { 6126 case XML_ELEMENT_NODE: 6127 case XML_ATTRIBUTE_NODE: 6128 if (cur->nodesetval->nodeTab[i]->ns == NULL) 6129 valuePush(ctxt, xmlXPathNewCString("")); 6130 else 6131 valuePush(ctxt, xmlXPathNewString( 6132 cur->nodesetval->nodeTab[i]->ns->href)); 6133 break; 6134 default: 6135 valuePush(ctxt, xmlXPathNewCString("")); 6136 } 6137 } 6138 xmlXPathFreeObject(cur); 6139} 6140 6141/** 6142 * xmlXPathNameFunction: 6143 * @ctxt: the XPath Parser context 6144 * @nargs: the number of arguments 6145 * 6146 * Implement the name() XPath function 6147 * string name(node-set?) 6148 * The name function returns a string containing a QName representing 6149 * the name of the node in the argument node-set that is first in document 6150 * order. The QName must represent the name with respect to the namespace 6151 * declarations in effect on the node whose name is being represented. 6152 * Typically, this will be the form in which the name occurred in the XML 6153 * source. This need not be the case if there are namespace declarations 6154 * in effect on the node that associate multiple prefixes with the same 6155 * namespace. However, an implementation may include information about 6156 * the original prefix in its representation of nodes; in this case, an 6157 * implementation can ensure that the returned string is always the same 6158 * as the QName used in the XML source. If the argument it omitted it 6159 * defaults to the context node. 6160 * Libxml keep the original prefix so the "real qualified name" used is 6161 * returned. 6162 */ 6163static void 6164xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 6165{ 6166 xmlXPathObjectPtr cur; 6167 6168 if (nargs == 0) { 6169 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 6170 nargs = 1; 6171 } 6172 6173 CHECK_ARITY(1); 6174 if ((ctxt->value == NULL) || 6175 ((ctxt->value->type != XPATH_NODESET) && 6176 (ctxt->value->type != XPATH_XSLT_TREE))) 6177 XP_ERROR(XPATH_INVALID_TYPE); 6178 cur = valuePop(ctxt); 6179 6180 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 6181 valuePush(ctxt, xmlXPathNewCString("")); 6182 } else { 6183 int i = 0; /* Should be first in document order !!!!! */ 6184 6185 switch (cur->nodesetval->nodeTab[i]->type) { 6186 case XML_ELEMENT_NODE: 6187 case XML_ATTRIBUTE_NODE: 6188 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 6189 valuePush(ctxt, xmlXPathNewCString("")); 6190 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 6191 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 6192 valuePush(ctxt, 6193 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name)); 6194 6195 } else { 6196 xmlChar *fullname; 6197 6198 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 6199 cur->nodesetval->nodeTab[i]->ns->prefix, 6200 NULL, 0); 6201 if (fullname == cur->nodesetval->nodeTab[i]->name) 6202 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 6203 if (fullname == NULL) { 6204 XP_ERROR(XPATH_MEMORY_ERROR); 6205 } 6206 valuePush(ctxt, xmlXPathWrapString(fullname)); 6207 } 6208 break; 6209 default: 6210 valuePush(ctxt, 6211 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i])); 6212 xmlXPathLocalNameFunction(ctxt, 1); 6213 } 6214 } 6215 xmlXPathFreeObject(cur); 6216} 6217 6218 6219/** 6220 * xmlXPathStringFunction: 6221 * @ctxt: the XPath Parser context 6222 * @nargs: the number of arguments 6223 * 6224 * Implement the string() XPath function 6225 * string string(object?) 6226 * he string function converts an object to a string as follows: 6227 * - A node-set is converted to a string by returning the value of 6228 * the node in the node-set that is first in document order. 6229 * If the node-set is empty, an empty string is returned. 6230 * - A number is converted to a string as follows 6231 * + NaN is converted to the string NaN 6232 * + positive zero is converted to the string 0 6233 * + negative zero is converted to the string 0 6234 * + positive infinity is converted to the string Infinity 6235 * + negative infinity is converted to the string -Infinity 6236 * + if the number is an integer, the number is represented in 6237 * decimal form as a Number with no decimal point and no leading 6238 * zeros, preceded by a minus sign (-) if the number is negative 6239 * + otherwise, the number is represented in decimal form as a 6240 * Number including a decimal point with at least one digit 6241 * before the decimal point and at least one digit after the 6242 * decimal point, preceded by a minus sign (-) if the number 6243 * is negative; there must be no leading zeros before the decimal 6244 * point apart possibly from the one required digit immediately 6245 * before the decimal point; beyond the one required digit 6246 * after the decimal point there must be as many, but only as 6247 * many, more digits as are needed to uniquely distinguish the 6248 * number from all other IEEE 754 numeric values. 6249 * - The boolean false value is converted to the string false. 6250 * The boolean true value is converted to the string true. 6251 * 6252 * If the argument is omitted, it defaults to a node-set with the 6253 * context node as its only member. 6254 */ 6255void 6256xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6257 xmlXPathObjectPtr cur; 6258 6259 if (nargs == 0) { 6260 valuePush(ctxt, 6261 xmlXPathWrapString( 6262 xmlXPathCastNodeToString(ctxt->context->node))); 6263 return; 6264 } 6265 6266 CHECK_ARITY(1); 6267 cur = valuePop(ctxt); 6268 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 6269 cur = xmlXPathConvertString(cur); 6270 valuePush(ctxt, cur); 6271} 6272 6273/** 6274 * xmlXPathStringLengthFunction: 6275 * @ctxt: the XPath Parser context 6276 * @nargs: the number of arguments 6277 * 6278 * Implement the string-length() XPath function 6279 * number string-length(string?) 6280 * The string-length returns the number of characters in the string 6281 * (see [3.6 Strings]). If the argument is omitted, it defaults to 6282 * the context node converted to a string, in other words the value 6283 * of the context node. 6284 */ 6285void 6286xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6287 xmlXPathObjectPtr cur; 6288 6289 if (nargs == 0) { 6290 if (ctxt->context->node == NULL) { 6291 valuePush(ctxt, xmlXPathNewFloat(0)); 6292 } else { 6293 xmlChar *content; 6294 6295 content = xmlXPathCastNodeToString(ctxt->context->node); 6296 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content))); 6297 xmlFree(content); 6298 } 6299 return; 6300 } 6301 CHECK_ARITY(1); 6302 CAST_TO_STRING; 6303 CHECK_TYPE(XPATH_STRING); 6304 cur = valuePop(ctxt); 6305 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval))); 6306 xmlXPathFreeObject(cur); 6307} 6308 6309/** 6310 * xmlXPathConcatFunction: 6311 * @ctxt: the XPath Parser context 6312 * @nargs: the number of arguments 6313 * 6314 * Implement the concat() XPath function 6315 * string concat(string, string, string*) 6316 * The concat function returns the concatenation of its arguments. 6317 */ 6318void 6319xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6320 xmlXPathObjectPtr cur, newobj; 6321 xmlChar *tmp; 6322 6323 if (nargs < 2) { 6324 CHECK_ARITY(2); 6325 } 6326 6327 CAST_TO_STRING; 6328 cur = valuePop(ctxt); 6329 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 6330 xmlXPathFreeObject(cur); 6331 return; 6332 } 6333 nargs--; 6334 6335 while (nargs > 0) { 6336 CAST_TO_STRING; 6337 newobj = valuePop(ctxt); 6338 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 6339 xmlXPathFreeObject(newobj); 6340 xmlXPathFreeObject(cur); 6341 XP_ERROR(XPATH_INVALID_TYPE); 6342 } 6343 tmp = xmlStrcat(newobj->stringval, cur->stringval); 6344 newobj->stringval = cur->stringval; 6345 cur->stringval = tmp; 6346 6347 xmlXPathFreeObject(newobj); 6348 nargs--; 6349 } 6350 valuePush(ctxt, cur); 6351} 6352 6353/** 6354 * xmlXPathContainsFunction: 6355 * @ctxt: the XPath Parser context 6356 * @nargs: the number of arguments 6357 * 6358 * Implement the contains() XPath function 6359 * boolean contains(string, string) 6360 * The contains function returns true if the first argument string 6361 * contains the second argument string, and otherwise returns false. 6362 */ 6363void 6364xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6365 xmlXPathObjectPtr hay, needle; 6366 6367 CHECK_ARITY(2); 6368 CAST_TO_STRING; 6369 CHECK_TYPE(XPATH_STRING); 6370 needle = valuePop(ctxt); 6371 CAST_TO_STRING; 6372 hay = valuePop(ctxt); 6373 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 6374 xmlXPathFreeObject(hay); 6375 xmlXPathFreeObject(needle); 6376 XP_ERROR(XPATH_INVALID_TYPE); 6377 } 6378 if (xmlStrstr(hay->stringval, needle->stringval)) 6379 valuePush(ctxt, xmlXPathNewBoolean(1)); 6380 else 6381 valuePush(ctxt, xmlXPathNewBoolean(0)); 6382 xmlXPathFreeObject(hay); 6383 xmlXPathFreeObject(needle); 6384} 6385 6386/** 6387 * xmlXPathStartsWithFunction: 6388 * @ctxt: the XPath Parser context 6389 * @nargs: the number of arguments 6390 * 6391 * Implement the starts-with() XPath function 6392 * boolean starts-with(string, string) 6393 * The starts-with function returns true if the first argument string 6394 * starts with the second argument string, and otherwise returns false. 6395 */ 6396void 6397xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6398 xmlXPathObjectPtr hay, needle; 6399 int n; 6400 6401 CHECK_ARITY(2); 6402 CAST_TO_STRING; 6403 CHECK_TYPE(XPATH_STRING); 6404 needle = valuePop(ctxt); 6405 CAST_TO_STRING; 6406 hay = valuePop(ctxt); 6407 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 6408 xmlXPathFreeObject(hay); 6409 xmlXPathFreeObject(needle); 6410 XP_ERROR(XPATH_INVALID_TYPE); 6411 } 6412 n = xmlStrlen(needle->stringval); 6413 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 6414 valuePush(ctxt, xmlXPathNewBoolean(0)); 6415 else 6416 valuePush(ctxt, xmlXPathNewBoolean(1)); 6417 xmlXPathFreeObject(hay); 6418 xmlXPathFreeObject(needle); 6419} 6420 6421/** 6422 * xmlXPathSubstringFunction: 6423 * @ctxt: the XPath Parser context 6424 * @nargs: the number of arguments 6425 * 6426 * Implement the substring() XPath function 6427 * string substring(string, number, number?) 6428 * The substring function returns the substring of the first argument 6429 * starting at the position specified in the second argument with 6430 * length specified in the third argument. For example, 6431 * substring("12345",2,3) returns "234". If the third argument is not 6432 * specified, it returns the substring starting at the position specified 6433 * in the second argument and continuing to the end of the string. For 6434 * example, substring("12345",2) returns "2345". More precisely, each 6435 * character in the string (see [3.6 Strings]) is considered to have a 6436 * numeric position: the position of the first character is 1, the position 6437 * of the second character is 2 and so on. The returned substring contains 6438 * those characters for which the position of the character is greater than 6439 * or equal to the second argument and, if the third argument is specified, 6440 * less than the sum of the second and third arguments; the comparisons 6441 * and addition used for the above follow the standard IEEE 754 rules. Thus: 6442 * - substring("12345", 1.5, 2.6) returns "234" 6443 * - substring("12345", 0, 3) returns "12" 6444 * - substring("12345", 0 div 0, 3) returns "" 6445 * - substring("12345", 1, 0 div 0) returns "" 6446 * - substring("12345", -42, 1 div 0) returns "12345" 6447 * - substring("12345", -1 div 0, 1 div 0) returns "" 6448 */ 6449void 6450xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6451 xmlXPathObjectPtr str, start, len; 6452 double le=0, in; 6453 int i, l, m; 6454 xmlChar *ret; 6455 6456 if (nargs < 2) { 6457 CHECK_ARITY(2); 6458 } 6459 if (nargs > 3) { 6460 CHECK_ARITY(3); 6461 } 6462 /* 6463 * take care of possible last (position) argument 6464 */ 6465 if (nargs == 3) { 6466 CAST_TO_NUMBER; 6467 CHECK_TYPE(XPATH_NUMBER); 6468 len = valuePop(ctxt); 6469 le = len->floatval; 6470 xmlXPathFreeObject(len); 6471 } 6472 6473 CAST_TO_NUMBER; 6474 CHECK_TYPE(XPATH_NUMBER); 6475 start = valuePop(ctxt); 6476 in = start->floatval; 6477 xmlXPathFreeObject(start); 6478 CAST_TO_STRING; 6479 CHECK_TYPE(XPATH_STRING); 6480 str = valuePop(ctxt); 6481 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 6482 6483 /* 6484 * If last pos not present, calculate last position 6485 */ 6486 if (nargs != 3) { 6487 le = (double)m; 6488 if (in < 1.0) 6489 in = 1.0; 6490 } 6491 6492 /* Need to check for the special cases where either 6493 * the index is NaN, the length is NaN, or both 6494 * arguments are infinity (relying on Inf + -Inf = NaN) 6495 */ 6496 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) { 6497 /* 6498 * To meet the requirements of the spec, the arguments 6499 * must be converted to integer format before 6500 * initial index calculations are done 6501 * 6502 * First we go to integer form, rounding up 6503 * and checking for special cases 6504 */ 6505 i = (int) in; 6506 if (((double)i)+0.5 <= in) i++; 6507 6508 if (xmlXPathIsInf(le) == 1) { 6509 l = m; 6510 if (i < 1) 6511 i = 1; 6512 } 6513 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 6514 l = 0; 6515 else { 6516 l = (int) le; 6517 if (((double)l)+0.5 <= le) l++; 6518 } 6519 6520 /* Now we normalize inidices */ 6521 i -= 1; 6522 l += i; 6523 if (i < 0) 6524 i = 0; 6525 if (l > m) 6526 l = m; 6527 6528 /* number of chars to copy */ 6529 l -= i; 6530 6531 ret = xmlUTF8Strsub(str->stringval, i, l); 6532 } 6533 else { 6534 ret = NULL; 6535 } 6536 6537 if (ret == NULL) 6538 valuePush(ctxt, xmlXPathNewCString("")); 6539 else { 6540 valuePush(ctxt, xmlXPathNewString(ret)); 6541 xmlFree(ret); 6542 } 6543 6544 xmlXPathFreeObject(str); 6545} 6546 6547/** 6548 * xmlXPathSubstringBeforeFunction: 6549 * @ctxt: the XPath Parser context 6550 * @nargs: the number of arguments 6551 * 6552 * Implement the substring-before() XPath function 6553 * string substring-before(string, string) 6554 * The substring-before function returns the substring of the first 6555 * argument string that precedes the first occurrence of the second 6556 * argument string in the first argument string, or the empty string 6557 * if the first argument string does not contain the second argument 6558 * string. For example, substring-before("1999/04/01","/") returns 1999. 6559 */ 6560void 6561xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6562 xmlXPathObjectPtr str; 6563 xmlXPathObjectPtr find; 6564 xmlBufferPtr target; 6565 const xmlChar *point; 6566 int offset; 6567 6568 CHECK_ARITY(2); 6569 CAST_TO_STRING; 6570 find = valuePop(ctxt); 6571 CAST_TO_STRING; 6572 str = valuePop(ctxt); 6573 6574 target = xmlBufferCreate(); 6575 if (target) { 6576 point = xmlStrstr(str->stringval, find->stringval); 6577 if (point) { 6578 offset = (int)(point - str->stringval); 6579 xmlBufferAdd(target, str->stringval, offset); 6580 } 6581 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); 6582 xmlBufferFree(target); 6583 } 6584 6585 xmlXPathFreeObject(str); 6586 xmlXPathFreeObject(find); 6587} 6588 6589/** 6590 * xmlXPathSubstringAfterFunction: 6591 * @ctxt: the XPath Parser context 6592 * @nargs: the number of arguments 6593 * 6594 * Implement the substring-after() XPath function 6595 * string substring-after(string, string) 6596 * The substring-after function returns the substring of the first 6597 * argument string that follows the first occurrence of the second 6598 * argument string in the first argument string, or the empty stringi 6599 * if the first argument string does not contain the second argument 6600 * string. For example, substring-after("1999/04/01","/") returns 04/01, 6601 * and substring-after("1999/04/01","19") returns 99/04/01. 6602 */ 6603void 6604xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6605 xmlXPathObjectPtr str; 6606 xmlXPathObjectPtr find; 6607 xmlBufferPtr target; 6608 const xmlChar *point; 6609 int offset; 6610 6611 CHECK_ARITY(2); 6612 CAST_TO_STRING; 6613 find = valuePop(ctxt); 6614 CAST_TO_STRING; 6615 str = valuePop(ctxt); 6616 6617 target = xmlBufferCreate(); 6618 if (target) { 6619 point = xmlStrstr(str->stringval, find->stringval); 6620 if (point) { 6621 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 6622 xmlBufferAdd(target, &str->stringval[offset], 6623 xmlStrlen(str->stringval) - offset); 6624 } 6625 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); 6626 xmlBufferFree(target); 6627 } 6628 6629 xmlXPathFreeObject(str); 6630 xmlXPathFreeObject(find); 6631} 6632 6633/** 6634 * xmlXPathNormalizeFunction: 6635 * @ctxt: the XPath Parser context 6636 * @nargs: the number of arguments 6637 * 6638 * Implement the normalize-space() XPath function 6639 * string normalize-space(string?) 6640 * The normalize-space function returns the argument string with white 6641 * space normalized by stripping leading and trailing whitespace 6642 * and replacing sequences of whitespace characters by a single 6643 * space. Whitespace characters are the same allowed by the S production 6644 * in XML. If the argument is omitted, it defaults to the context 6645 * node converted to a string, in other words the value of the context node. 6646 */ 6647void 6648xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6649 xmlXPathObjectPtr obj = NULL; 6650 xmlChar *source = NULL; 6651 xmlBufferPtr target; 6652 xmlChar blank; 6653 6654 if (nargs == 0) { 6655 /* Use current context node */ 6656 valuePush(ctxt, 6657 xmlXPathWrapString( 6658 xmlXPathCastNodeToString(ctxt->context->node))); 6659 nargs = 1; 6660 } 6661 6662 CHECK_ARITY(1); 6663 CAST_TO_STRING; 6664 CHECK_TYPE(XPATH_STRING); 6665 obj = valuePop(ctxt); 6666 source = obj->stringval; 6667 6668 target = xmlBufferCreate(); 6669 if (target && source) { 6670 6671 /* Skip leading whitespaces */ 6672 while (IS_BLANK(*source)) 6673 source++; 6674 6675 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 6676 blank = 0; 6677 while (*source) { 6678 if (IS_BLANK(*source)) { 6679 blank = 0x20; 6680 } else { 6681 if (blank) { 6682 xmlBufferAdd(target, &blank, 1); 6683 blank = 0; 6684 } 6685 xmlBufferAdd(target, source, 1); 6686 } 6687 source++; 6688 } 6689 6690 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); 6691 xmlBufferFree(target); 6692 } 6693 xmlXPathFreeObject(obj); 6694} 6695 6696/** 6697 * xmlXPathTranslateFunction: 6698 * @ctxt: the XPath Parser context 6699 * @nargs: the number of arguments 6700 * 6701 * Implement the translate() XPath function 6702 * string translate(string, string, string) 6703 * The translate function returns the first argument string with 6704 * occurrences of characters in the second argument string replaced 6705 * by the character at the corresponding position in the third argument 6706 * string. For example, translate("bar","abc","ABC") returns the string 6707 * BAr. If there is a character in the second argument string with no 6708 * character at a corresponding position in the third argument string 6709 * (because the second argument string is longer than the third argument 6710 * string), then occurrences of that character in the first argument 6711 * string are removed. For example, translate("--aaa--","abc-","ABC") 6712 * returns "AAA". If a character occurs more than once in second 6713 * argument string, then the first occurrence determines the replacement 6714 * character. If the third argument string is longer than the second 6715 * argument string, then excess characters are ignored. 6716 */ 6717void 6718xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6719 xmlXPathObjectPtr str; 6720 xmlXPathObjectPtr from; 6721 xmlXPathObjectPtr to; 6722 xmlBufferPtr target; 6723 int offset, max; 6724 xmlChar ch; 6725 xmlChar *point; 6726 xmlChar *cptr; 6727 6728 CHECK_ARITY(3); 6729 6730 CAST_TO_STRING; 6731 to = valuePop(ctxt); 6732 CAST_TO_STRING; 6733 from = valuePop(ctxt); 6734 CAST_TO_STRING; 6735 str = valuePop(ctxt); 6736 6737 target = xmlBufferCreate(); 6738 if (target) { 6739 max = xmlUTF8Strlen(to->stringval); 6740 for (cptr = str->stringval; (ch=*cptr); ) { 6741 offset = xmlUTF8Strloc(from->stringval, cptr); 6742 if (offset >= 0) { 6743 if (offset < max) { 6744 point = xmlUTF8Strpos(to->stringval, offset); 6745 if (point) 6746 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1)); 6747 } 6748 } else 6749 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 6750 6751 /* Step to next character in input */ 6752 cptr++; 6753 if ( ch & 0x80 ) { 6754 /* if not simple ascii, verify proper format */ 6755 if ( (ch & 0xc0) != 0xc0 ) { 6756 xmlGenericError(xmlGenericErrorContext, 6757 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 6758 break; 6759 } 6760 /* then skip over remaining bytes for this char */ 6761 while ( (ch <<= 1) & 0x80 ) 6762 if ( (*cptr++ & 0xc0) != 0x80 ) { 6763 xmlGenericError(xmlGenericErrorContext, 6764 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 6765 break; 6766 } 6767 if (ch & 0x80) /* must have had error encountered */ 6768 break; 6769 } 6770 } 6771 } 6772 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); 6773 xmlBufferFree(target); 6774 xmlXPathFreeObject(str); 6775 xmlXPathFreeObject(from); 6776 xmlXPathFreeObject(to); 6777} 6778 6779/** 6780 * xmlXPathBooleanFunction: 6781 * @ctxt: the XPath Parser context 6782 * @nargs: the number of arguments 6783 * 6784 * Implement the boolean() XPath function 6785 * boolean boolean(object) 6786 * he boolean function converts its argument to a boolean as follows: 6787 * - a number is true if and only if it is neither positive or 6788 * negative zero nor NaN 6789 * - a node-set is true if and only if it is non-empty 6790 * - a string is true if and only if its length is non-zero 6791 */ 6792void 6793xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6794 xmlXPathObjectPtr cur; 6795 6796 CHECK_ARITY(1); 6797 cur = valuePop(ctxt); 6798 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 6799 cur = xmlXPathConvertBoolean(cur); 6800 valuePush(ctxt, cur); 6801} 6802 6803/** 6804 * xmlXPathNotFunction: 6805 * @ctxt: the XPath Parser context 6806 * @nargs: the number of arguments 6807 * 6808 * Implement the not() XPath function 6809 * boolean not(boolean) 6810 * The not function returns true if its argument is false, 6811 * and false otherwise. 6812 */ 6813void 6814xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6815 CHECK_ARITY(1); 6816 CAST_TO_BOOLEAN; 6817 CHECK_TYPE(XPATH_BOOLEAN); 6818 ctxt->value->boolval = ! ctxt->value->boolval; 6819} 6820 6821/** 6822 * xmlXPathTrueFunction: 6823 * @ctxt: the XPath Parser context 6824 * @nargs: the number of arguments 6825 * 6826 * Implement the true() XPath function 6827 * boolean true() 6828 */ 6829void 6830xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6831 CHECK_ARITY(0); 6832 valuePush(ctxt, xmlXPathNewBoolean(1)); 6833} 6834 6835/** 6836 * xmlXPathFalseFunction: 6837 * @ctxt: the XPath Parser context 6838 * @nargs: the number of arguments 6839 * 6840 * Implement the false() XPath function 6841 * boolean false() 6842 */ 6843void 6844xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6845 CHECK_ARITY(0); 6846 valuePush(ctxt, xmlXPathNewBoolean(0)); 6847} 6848 6849/** 6850 * xmlXPathLangFunction: 6851 * @ctxt: the XPath Parser context 6852 * @nargs: the number of arguments 6853 * 6854 * Implement the lang() XPath function 6855 * boolean lang(string) 6856 * The lang function returns true or false depending on whether the 6857 * language of the context node as specified by xml:lang attributes 6858 * is the same as or is a sublanguage of the language specified by 6859 * the argument string. The language of the context node is determined 6860 * by the value of the xml:lang attribute on the context node, or, if 6861 * the context node has no xml:lang attribute, by the value of the 6862 * xml:lang attribute on the nearest ancestor of the context node that 6863 * has an xml:lang attribute. If there is no such attribute, then lang 6864 * returns false. If there is such an attribute, then lang returns 6865 * true if the attribute value is equal to the argument ignoring case, 6866 * or if there is some suffix starting with - such that the attribute 6867 * value is equal to the argument ignoring that suffix of the attribute 6868 * value and ignoring case. 6869 */ 6870void 6871xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6872 xmlXPathObjectPtr val; 6873 const xmlChar *theLang; 6874 const xmlChar *lang; 6875 int ret = 0; 6876 int i; 6877 6878 CHECK_ARITY(1); 6879 CAST_TO_STRING; 6880 CHECK_TYPE(XPATH_STRING); 6881 val = valuePop(ctxt); 6882 lang = val->stringval; 6883 theLang = xmlNodeGetLang(ctxt->context->node); 6884 if ((theLang != NULL) && (lang != NULL)) { 6885 for (i = 0;lang[i] != 0;i++) 6886 if (toupper(lang[i]) != toupper(theLang[i])) 6887 goto not_equal; 6888 ret = 1; 6889 } 6890not_equal: 6891 xmlXPathFreeObject(val); 6892 valuePush(ctxt, xmlXPathNewBoolean(ret)); 6893} 6894 6895/** 6896 * xmlXPathNumberFunction: 6897 * @ctxt: the XPath Parser context 6898 * @nargs: the number of arguments 6899 * 6900 * Implement the number() XPath function 6901 * number number(object?) 6902 */ 6903void 6904xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6905 xmlXPathObjectPtr cur; 6906 double res; 6907 6908 if (nargs == 0) { 6909 if (ctxt->context->node == NULL) { 6910 valuePush(ctxt, xmlXPathNewFloat(0.0)); 6911 } else { 6912 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 6913 6914 res = xmlXPathStringEvalNumber(content); 6915 valuePush(ctxt, xmlXPathNewFloat(res)); 6916 xmlFree(content); 6917 } 6918 return; 6919 } 6920 6921 CHECK_ARITY(1); 6922 cur = valuePop(ctxt); 6923 cur = xmlXPathConvertNumber(cur); 6924 valuePush(ctxt, cur); 6925} 6926 6927/** 6928 * xmlXPathSumFunction: 6929 * @ctxt: the XPath Parser context 6930 * @nargs: the number of arguments 6931 * 6932 * Implement the sum() XPath function 6933 * number sum(node-set) 6934 * The sum function returns the sum of the values of the nodes in 6935 * the argument node-set. 6936 */ 6937void 6938xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6939 xmlXPathObjectPtr cur; 6940 int i; 6941 double res = 0.0; 6942 6943 CHECK_ARITY(1); 6944 if ((ctxt->value == NULL) || 6945 ((ctxt->value->type != XPATH_NODESET) && 6946 (ctxt->value->type != XPATH_XSLT_TREE))) 6947 XP_ERROR(XPATH_INVALID_TYPE); 6948 cur = valuePop(ctxt); 6949 6950 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 6951 valuePush(ctxt, xmlXPathNewFloat(0.0)); 6952 } else { 6953 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 6954 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 6955 } 6956 valuePush(ctxt, xmlXPathNewFloat(res)); 6957 } 6958 xmlXPathFreeObject(cur); 6959} 6960 6961/** 6962 * xmlXPathFloorFunction: 6963 * @ctxt: the XPath Parser context 6964 * @nargs: the number of arguments 6965 * 6966 * Implement the floor() XPath function 6967 * number floor(number) 6968 * The floor function returns the largest (closest to positive infinity) 6969 * number that is not greater than the argument and that is an integer. 6970 */ 6971void 6972xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6973 double f; 6974 6975 CHECK_ARITY(1); 6976 CAST_TO_NUMBER; 6977 CHECK_TYPE(XPATH_NUMBER); 6978 6979 f = (double)((int) ctxt->value->floatval); 6980 if (f != ctxt->value->floatval) { 6981 if (ctxt->value->floatval > 0) 6982 ctxt->value->floatval = f; 6983 else 6984 ctxt->value->floatval = f - 1; 6985 } 6986} 6987 6988/** 6989 * xmlXPathCeilingFunction: 6990 * @ctxt: the XPath Parser context 6991 * @nargs: the number of arguments 6992 * 6993 * Implement the ceiling() XPath function 6994 * number ceiling(number) 6995 * The ceiling function returns the smallest (closest to negative infinity) 6996 * number that is not less than the argument and that is an integer. 6997 */ 6998void 6999xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 7000 double f; 7001 7002 CHECK_ARITY(1); 7003 CAST_TO_NUMBER; 7004 CHECK_TYPE(XPATH_NUMBER); 7005 7006#if 0 7007 ctxt->value->floatval = ceil(ctxt->value->floatval); 7008#else 7009 f = (double)((int) ctxt->value->floatval); 7010 if (f != ctxt->value->floatval) { 7011 if (ctxt->value->floatval > 0) 7012 ctxt->value->floatval = f + 1; 7013 else { 7014 if (ctxt->value->floatval < 0 && f == 0) 7015 ctxt->value->floatval = xmlXPathNZERO; 7016 else 7017 ctxt->value->floatval = f; 7018 } 7019 7020 } 7021#endif 7022} 7023 7024/** 7025 * xmlXPathRoundFunction: 7026 * @ctxt: the XPath Parser context 7027 * @nargs: the number of arguments 7028 * 7029 * Implement the round() XPath function 7030 * number round(number) 7031 * The round function returns the number that is closest to the 7032 * argument and that is an integer. If there are two such numbers, 7033 * then the one that is even is returned. 7034 */ 7035void 7036xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 7037 double f; 7038 7039 CHECK_ARITY(1); 7040 CAST_TO_NUMBER; 7041 CHECK_TYPE(XPATH_NUMBER); 7042 7043 if ((xmlXPathIsNaN(ctxt->value->floatval)) || 7044 (xmlXPathIsInf(ctxt->value->floatval) == 1) || 7045 (xmlXPathIsInf(ctxt->value->floatval) == -1) || 7046 (ctxt->value->floatval == 0.0)) 7047 return; 7048 7049 f = (double)((int) ctxt->value->floatval); 7050 if (ctxt->value->floatval < 0) { 7051 if (ctxt->value->floatval < f - 0.5) 7052 ctxt->value->floatval = f - 1; 7053 else 7054 ctxt->value->floatval = f; 7055 if (ctxt->value->floatval == 0) 7056 ctxt->value->floatval = xmlXPathNZERO; 7057 } else { 7058 if (ctxt->value->floatval < f + 0.5) 7059 ctxt->value->floatval = f; 7060 else 7061 ctxt->value->floatval = f + 1; 7062 } 7063} 7064 7065/************************************************************************ 7066 * * 7067 * The Parser * 7068 * * 7069 ************************************************************************/ 7070 7071/* 7072 * a couple of forward declarations since we use a recursive call based 7073 * implementation. 7074 */ 7075static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt); 7076static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 7077static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 7078static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 7079static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 7080 int qualified); 7081 7082/** 7083 * xmlXPathCurrentChar: 7084 * @ctxt: the XPath parser context 7085 * @cur: pointer to the beginning of the char 7086 * @len: pointer to the length of the char read 7087 * 7088 * The current char value, if using UTF-8 this may actually span multiple 7089 * bytes in the input buffer. 7090 * 7091 * Returns the current char value and its length 7092 */ 7093 7094static int 7095xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 7096 unsigned char c; 7097 unsigned int val; 7098 const xmlChar *cur; 7099 7100 if (ctxt == NULL) 7101 return(0); 7102 cur = ctxt->cur; 7103 7104 /* 7105 * We are supposed to handle UTF8, check it's valid 7106 * From rfc2044: encoding of the Unicode values on UTF-8: 7107 * 7108 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 7109 * 0000 0000-0000 007F 0xxxxxxx 7110 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 7111 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 7112 * 7113 * Check for the 0x110000 limit too 7114 */ 7115 c = *cur; 7116 if (c & 0x80) { 7117 if ((cur[1] & 0xc0) != 0x80) 7118 goto encoding_error; 7119 if ((c & 0xe0) == 0xe0) { 7120 7121 if ((cur[2] & 0xc0) != 0x80) 7122 goto encoding_error; 7123 if ((c & 0xf0) == 0xf0) { 7124 if (((c & 0xf8) != 0xf0) || 7125 ((cur[3] & 0xc0) != 0x80)) 7126 goto encoding_error; 7127 /* 4-byte code */ 7128 *len = 4; 7129 val = (cur[0] & 0x7) << 18; 7130 val |= (cur[1] & 0x3f) << 12; 7131 val |= (cur[2] & 0x3f) << 6; 7132 val |= cur[3] & 0x3f; 7133 } else { 7134 /* 3-byte code */ 7135 *len = 3; 7136 val = (cur[0] & 0xf) << 12; 7137 val |= (cur[1] & 0x3f) << 6; 7138 val |= cur[2] & 0x3f; 7139 } 7140 } else { 7141 /* 2-byte code */ 7142 *len = 2; 7143 val = (cur[0] & 0x1f) << 6; 7144 val |= cur[1] & 0x3f; 7145 } 7146 if (!IS_CHAR(val)) { 7147 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 7148 } 7149 return(val); 7150 } else { 7151 /* 1-byte code */ 7152 *len = 1; 7153 return((int) *cur); 7154 } 7155encoding_error: 7156 /* 7157 * If we detect an UTF8 error that probably mean that the 7158 * input encoding didn't get properly advertized in the 7159 * declaration header. Report the error and switch the encoding 7160 * to ISO-Latin-1 (if you don't like this policy, just declare the 7161 * encoding !) 7162 */ 7163 *len = 0; 7164 XP_ERROR0(XPATH_ENCODING_ERROR); 7165} 7166 7167/** 7168 * xmlXPathParseNCName: 7169 * @ctxt: the XPath Parser context 7170 * 7171 * parse an XML namespace non qualified name. 7172 * 7173 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 7174 * 7175 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 7176 * CombiningChar | Extender 7177 * 7178 * Returns the namespace name or NULL 7179 */ 7180 7181xmlChar * 7182xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 7183 const xmlChar *in; 7184 xmlChar *ret; 7185 int count = 0; 7186 7187 /* 7188 * Accelerator for simple ASCII names 7189 */ 7190 in = ctxt->cur; 7191 if (((*in >= 0x61) && (*in <= 0x7A)) || 7192 ((*in >= 0x41) && (*in <= 0x5A)) || 7193 (*in == '_')) { 7194 in++; 7195 while (((*in >= 0x61) && (*in <= 0x7A)) || 7196 ((*in >= 0x41) && (*in <= 0x5A)) || 7197 ((*in >= 0x30) && (*in <= 0x39)) || 7198 (*in == '_') || (*in == '.') || 7199 (*in == '-')) 7200 in++; 7201 if ((*in == ' ') || (*in == '>') || (*in == '/') || 7202 (*in == '[') || (*in == ']') || (*in == ':') || 7203 (*in == '@') || (*in == '*')) { 7204 count = in - ctxt->cur; 7205 if (count == 0) 7206 return(NULL); 7207 ret = xmlStrndup(ctxt->cur, count); 7208 ctxt->cur = in; 7209 return(ret); 7210 } 7211 } 7212 return(xmlXPathParseNameComplex(ctxt, 0)); 7213} 7214 7215 7216/** 7217 * xmlXPathParseQName: 7218 * @ctxt: the XPath Parser context 7219 * @prefix: a xmlChar ** 7220 * 7221 * parse an XML qualified name 7222 * 7223 * [NS 5] QName ::= (Prefix ':')? LocalPart 7224 * 7225 * [NS 6] Prefix ::= NCName 7226 * 7227 * [NS 7] LocalPart ::= NCName 7228 * 7229 * Returns the function returns the local part, and prefix is updated 7230 * to get the Prefix if any. 7231 */ 7232 7233static xmlChar * 7234xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 7235 xmlChar *ret = NULL; 7236 7237 *prefix = NULL; 7238 ret = xmlXPathParseNCName(ctxt); 7239 if (CUR == ':') { 7240 *prefix = ret; 7241 NEXT; 7242 ret = xmlXPathParseNCName(ctxt); 7243 } 7244 return(ret); 7245} 7246 7247/** 7248 * xmlXPathParseName: 7249 * @ctxt: the XPath Parser context 7250 * 7251 * parse an XML name 7252 * 7253 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 7254 * CombiningChar | Extender 7255 * 7256 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 7257 * 7258 * Returns the namespace name or NULL 7259 */ 7260 7261xmlChar * 7262xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 7263 const xmlChar *in; 7264 xmlChar *ret; 7265 int count = 0; 7266 7267 /* 7268 * Accelerator for simple ASCII names 7269 */ 7270 in = ctxt->cur; 7271 if (((*in >= 0x61) && (*in <= 0x7A)) || 7272 ((*in >= 0x41) && (*in <= 0x5A)) || 7273 (*in == '_') || (*in == ':')) { 7274 in++; 7275 while (((*in >= 0x61) && (*in <= 0x7A)) || 7276 ((*in >= 0x41) && (*in <= 0x5A)) || 7277 ((*in >= 0x30) && (*in <= 0x39)) || 7278 (*in == '_') || (*in == '-') || 7279 (*in == ':') || (*in == '.')) 7280 in++; 7281 if ((*in > 0) && (*in < 0x80)) { 7282 count = in - ctxt->cur; 7283 ret = xmlStrndup(ctxt->cur, count); 7284 ctxt->cur = in; 7285 return(ret); 7286 } 7287 } 7288 return(xmlXPathParseNameComplex(ctxt, 1)); 7289} 7290 7291static xmlChar * 7292xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 7293 xmlChar buf[XML_MAX_NAMELEN + 5]; 7294 int len = 0, l; 7295 int c; 7296 7297 /* 7298 * Handler for more complex cases 7299 */ 7300 c = CUR_CHAR(l); 7301 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 7302 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 7303 (c == '*') || /* accelerators */ 7304 (!IS_LETTER(c) && (c != '_') && 7305 ((qualified) && (c != ':')))) { 7306 return(NULL); 7307 } 7308 7309 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 7310 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 7311 (c == '.') || (c == '-') || 7312 (c == '_') || ((qualified) && (c == ':')) || 7313 (IS_COMBINING(c)) || 7314 (IS_EXTENDER(c)))) { 7315 COPY_BUF(l,buf,len,c); 7316 NEXTL(l); 7317 c = CUR_CHAR(l); 7318 if (len >= XML_MAX_NAMELEN) { 7319 /* 7320 * Okay someone managed to make a huge name, so he's ready to pay 7321 * for the processing speed. 7322 */ 7323 xmlChar *buffer; 7324 int max = len * 2; 7325 7326 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 7327 if (buffer == NULL) { 7328 XP_ERROR0(XPATH_MEMORY_ERROR); 7329 } 7330 memcpy(buffer, buf, len); 7331 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 7332 (c == '.') || (c == '-') || 7333 (c == '_') || ((qualified) && (c == ':')) || 7334 (IS_COMBINING(c)) || 7335 (IS_EXTENDER(c))) { 7336 if (len + 10 > max) { 7337 max *= 2; 7338 buffer = (xmlChar *) xmlRealloc(buffer, 7339 max * sizeof(xmlChar)); 7340 if (buffer == NULL) { 7341 XP_ERROR0(XPATH_MEMORY_ERROR); 7342 } 7343 } 7344 COPY_BUF(l,buffer,len,c); 7345 NEXTL(l); 7346 c = CUR_CHAR(l); 7347 } 7348 buffer[len] = 0; 7349 return(buffer); 7350 } 7351 } 7352 if (len == 0) 7353 return(NULL); 7354 return(xmlStrndup(buf, len)); 7355} 7356 7357#define MAX_FRAC 20 7358 7359static double my_pow10[MAX_FRAC] = { 7360 1.0, 10.0, 100.0, 1000.0, 10000.0, 7361 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 7362 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 7363 100000000000000.0, 7364 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 7365 1000000000000000000.0, 10000000000000000000.0 7366}; 7367 7368/** 7369 * xmlXPathStringEvalNumber: 7370 * @str: A string to scan 7371 * 7372 * [30a] Float ::= Number ('e' Digits?)? 7373 * 7374 * [30] Number ::= Digits ('.' Digits?)? 7375 * | '.' Digits 7376 * [31] Digits ::= [0-9]+ 7377 * 7378 * Compile a Number in the string 7379 * In complement of the Number expression, this function also handles 7380 * negative values : '-' Number. 7381 * 7382 * Returns the double value. 7383 */ 7384double 7385xmlXPathStringEvalNumber(const xmlChar *str) { 7386 const xmlChar *cur = str; 7387 double ret; 7388 int ok = 0; 7389 int isneg = 0; 7390 int exponent = 0; 7391 int is_exponent_negative = 0; 7392#ifdef __GNUC__ 7393 unsigned long tmp = 0; 7394 double temp; 7395#endif 7396 if (cur == NULL) return(0); 7397 while (IS_BLANK(*cur)) cur++; 7398 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 7399 return(xmlXPathNAN); 7400 } 7401 if (*cur == '-') { 7402 isneg = 1; 7403 cur++; 7404 } 7405 7406#ifdef __GNUC__ 7407 /* 7408 * tmp/temp is a workaround against a gcc compiler bug 7409 * http://veillard.com/gcc.bug 7410 */ 7411 ret = 0; 7412 while ((*cur >= '0') && (*cur <= '9')) { 7413 ret = ret * 10; 7414 tmp = (*cur - '0'); 7415 ok = 1; 7416 cur++; 7417 temp = (double) tmp; 7418 ret = ret + temp; 7419 } 7420#else 7421 ret = 0; 7422 while ((*cur >= '0') && (*cur <= '9')) { 7423 ret = ret * 10 + (*cur - '0'); 7424 ok = 1; 7425 cur++; 7426 } 7427#endif 7428 7429 if (*cur == '.') { 7430 int v, frac = 0; 7431 double fraction = 0; 7432 7433 cur++; 7434 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 7435 return(xmlXPathNAN); 7436 } 7437 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { 7438 v = (*cur - '0'); 7439 fraction = fraction * 10 + v; 7440 frac = frac + 1; 7441 cur++; 7442 } 7443 fraction /= my_pow10[frac]; 7444 ret = ret + fraction; 7445 while ((*cur >= '0') && (*cur <= '9')) 7446 cur++; 7447 } 7448 if ((*cur == 'e') || (*cur == 'E')) { 7449 cur++; 7450 if (*cur == '-') { 7451 is_exponent_negative = 1; 7452 cur++; 7453 } 7454 while ((*cur >= '0') && (*cur <= '9')) { 7455 exponent = exponent * 10 + (*cur - '0'); 7456 cur++; 7457 } 7458 } 7459 while (IS_BLANK(*cur)) cur++; 7460 if (*cur != 0) return(xmlXPathNAN); 7461 if (isneg) ret = -ret; 7462 if (is_exponent_negative) exponent = -exponent; 7463 ret *= pow(10.0, (double)exponent); 7464 return(ret); 7465} 7466 7467/** 7468 * xmlXPathCompNumber: 7469 * @ctxt: the XPath Parser context 7470 * 7471 * [30] Number ::= Digits ('.' Digits?)? 7472 * | '.' Digits 7473 * [31] Digits ::= [0-9]+ 7474 * 7475 * Compile a Number, then push it on the stack 7476 * 7477 */ 7478static void 7479xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 7480{ 7481 double ret = 0.0; 7482 double mult = 1; 7483 int ok = 0; 7484 int exponent = 0; 7485 int is_exponent_negative = 0; 7486#ifdef __GNUC__ 7487 unsigned long tmp = 0; 7488 double temp; 7489#endif 7490 7491 CHECK_ERROR; 7492 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 7493 XP_ERROR(XPATH_NUMBER_ERROR); 7494 } 7495#ifdef __GNUC__ 7496 /* 7497 * tmp/temp is a workaround against a gcc compiler bug 7498 * http://veillard.com/gcc.bug 7499 */ 7500 ret = 0; 7501 while ((CUR >= '0') && (CUR <= '9')) { 7502 ret = ret * 10; 7503 tmp = (CUR - '0'); 7504 ok = 1; 7505 NEXT; 7506 temp = (double) tmp; 7507 ret = ret + temp; 7508 } 7509#else 7510 ret = 0; 7511 while ((CUR >= '0') && (CUR <= '9')) { 7512 ret = ret * 10 + (CUR - '0'); 7513 ok = 1; 7514 NEXT; 7515 } 7516#endif 7517 if (CUR == '.') { 7518 NEXT; 7519 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 7520 XP_ERROR(XPATH_NUMBER_ERROR); 7521 } 7522 while ((CUR >= '0') && (CUR <= '9')) { 7523 mult /= 10; 7524 ret = ret + (CUR - '0') * mult; 7525 NEXT; 7526 } 7527 } 7528 if ((CUR == 'e') || (CUR == 'E')) { 7529 NEXT; 7530 if (CUR == '-') { 7531 is_exponent_negative = 1; 7532 NEXT; 7533 } 7534 while ((CUR >= '0') && (CUR <= '9')) { 7535 exponent = exponent * 10 + (CUR - '0'); 7536 NEXT; 7537 } 7538 if (is_exponent_negative) 7539 exponent = -exponent; 7540 ret *= pow(10.0, (double) exponent); 7541 } 7542 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 7543 xmlXPathNewFloat(ret), NULL); 7544} 7545 7546/** 7547 * xmlXPathParseLiteral: 7548 * @ctxt: the XPath Parser context 7549 * 7550 * Parse a Literal 7551 * 7552 * [29] Literal ::= '"' [^"]* '"' 7553 * | "'" [^']* "'" 7554 * 7555 * Returns the value found or NULL in case of error 7556 */ 7557static xmlChar * 7558xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 7559 const xmlChar *q; 7560 xmlChar *ret = NULL; 7561 7562 if (CUR == '"') { 7563 NEXT; 7564 q = CUR_PTR; 7565 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"')) 7566 NEXT; 7567 if (!IS_CHAR((unsigned int) CUR)) { 7568 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR); 7569 } else { 7570 ret = xmlStrndup(q, CUR_PTR - q); 7571 NEXT; 7572 } 7573 } else if (CUR == '\'') { 7574 NEXT; 7575 q = CUR_PTR; 7576 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\'')) 7577 NEXT; 7578 if (!IS_CHAR((unsigned int) CUR)) { 7579 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR); 7580 } else { 7581 ret = xmlStrndup(q, CUR_PTR - q); 7582 NEXT; 7583 } 7584 } else { 7585 XP_ERROR0(XPATH_START_LITERAL_ERROR); 7586 } 7587 return(ret); 7588} 7589 7590/** 7591 * xmlXPathCompLiteral: 7592 * @ctxt: the XPath Parser context 7593 * 7594 * Parse a Literal and push it on the stack. 7595 * 7596 * [29] Literal ::= '"' [^"]* '"' 7597 * | "'" [^']* "'" 7598 * 7599 * TODO: xmlXPathCompLiteral memory allocation could be improved. 7600 */ 7601static void 7602xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 7603 const xmlChar *q; 7604 xmlChar *ret = NULL; 7605 7606 if (CUR == '"') { 7607 NEXT; 7608 q = CUR_PTR; 7609 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"')) 7610 NEXT; 7611 if (!IS_CHAR((unsigned int) CUR)) { 7612 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 7613 } else { 7614 ret = xmlStrndup(q, CUR_PTR - q); 7615 NEXT; 7616 } 7617 } else if (CUR == '\'') { 7618 NEXT; 7619 q = CUR_PTR; 7620 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\'')) 7621 NEXT; 7622 if (!IS_CHAR((unsigned int) CUR)) { 7623 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 7624 } else { 7625 ret = xmlStrndup(q, CUR_PTR - q); 7626 NEXT; 7627 } 7628 } else { 7629 XP_ERROR(XPATH_START_LITERAL_ERROR); 7630 } 7631 if (ret == NULL) return; 7632 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 7633 xmlXPathNewString(ret), NULL); 7634 xmlFree(ret); 7635} 7636 7637/** 7638 * xmlXPathCompVariableReference: 7639 * @ctxt: the XPath Parser context 7640 * 7641 * Parse a VariableReference, evaluate it and push it on the stack. 7642 * 7643 * The variable bindings consist of a mapping from variable names 7644 * to variable values. The value of a variable is an object, which 7645 * of any of the types that are possible for the value of an expression, 7646 * and may also be of additional types not specified here. 7647 * 7648 * Early evaluation is possible since: 7649 * The variable bindings [...] used to evaluate a subexpression are 7650 * always the same as those used to evaluate the containing expression. 7651 * 7652 * [36] VariableReference ::= '$' QName 7653 */ 7654static void 7655xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 7656 xmlChar *name; 7657 xmlChar *prefix; 7658 7659 SKIP_BLANKS; 7660 if (CUR != '$') { 7661 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 7662 } 7663 NEXT; 7664 name = xmlXPathParseQName(ctxt, &prefix); 7665 if (name == NULL) { 7666 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 7667 } 7668 ctxt->comp->last = -1; 7669 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 7670 name, prefix); 7671 SKIP_BLANKS; 7672} 7673 7674/** 7675 * xmlXPathIsNodeType: 7676 * @name: a name string 7677 * 7678 * Is the name given a NodeType one. 7679 * 7680 * [38] NodeType ::= 'comment' 7681 * | 'text' 7682 * | 'processing-instruction' 7683 * | 'node' 7684 * 7685 * Returns 1 if true 0 otherwise 7686 */ 7687int 7688xmlXPathIsNodeType(const xmlChar *name) { 7689 if (name == NULL) 7690 return(0); 7691 7692 if (xmlStrEqual(name, BAD_CAST "node")) 7693 return(1); 7694 if (xmlStrEqual(name, BAD_CAST "text")) 7695 return(1); 7696 if (xmlStrEqual(name, BAD_CAST "comment")) 7697 return(1); 7698 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 7699 return(1); 7700 return(0); 7701} 7702 7703/** 7704 * xmlXPathCompFunctionCall: 7705 * @ctxt: the XPath Parser context 7706 * 7707 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 7708 * [17] Argument ::= Expr 7709 * 7710 * Compile a function call, the evaluation of all arguments are 7711 * pushed on the stack 7712 */ 7713static void 7714xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 7715 xmlChar *name; 7716 xmlChar *prefix; 7717 int nbargs = 0; 7718 7719 name = xmlXPathParseQName(ctxt, &prefix); 7720 if (name == NULL) { 7721 XP_ERROR(XPATH_EXPR_ERROR); 7722 } 7723 SKIP_BLANKS; 7724#ifdef DEBUG_EXPR 7725 if (prefix == NULL) 7726 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 7727 name); 7728 else 7729 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 7730 prefix, name); 7731#endif 7732 7733 if (CUR != '(') { 7734 XP_ERROR(XPATH_EXPR_ERROR); 7735 } 7736 NEXT; 7737 SKIP_BLANKS; 7738 7739 ctxt->comp->last = -1; 7740 if (CUR != ')') { 7741 while (CUR != 0) { 7742 int op1 = ctxt->comp->last; 7743 ctxt->comp->last = -1; 7744 xmlXPathCompileExpr(ctxt); 7745 CHECK_ERROR; 7746 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 7747 nbargs++; 7748 if (CUR == ')') break; 7749 if (CUR != ',') { 7750 XP_ERROR(XPATH_EXPR_ERROR); 7751 } 7752 NEXT; 7753 SKIP_BLANKS; 7754 } 7755 } 7756 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 7757 name, prefix); 7758 NEXT; 7759 SKIP_BLANKS; 7760} 7761 7762/** 7763 * xmlXPathCompPrimaryExpr: 7764 * @ctxt: the XPath Parser context 7765 * 7766 * [15] PrimaryExpr ::= VariableReference 7767 * | '(' Expr ')' 7768 * | Literal 7769 * | Number 7770 * | FunctionCall 7771 * 7772 * Compile a primary expression. 7773 */ 7774static void 7775xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 7776 SKIP_BLANKS; 7777 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 7778 else if (CUR == '(') { 7779 NEXT; 7780 SKIP_BLANKS; 7781 xmlXPathCompileExpr(ctxt); 7782 CHECK_ERROR; 7783 if (CUR != ')') { 7784 XP_ERROR(XPATH_EXPR_ERROR); 7785 } 7786 NEXT; 7787 SKIP_BLANKS; 7788 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) { 7789 xmlXPathCompNumber(ctxt); 7790 } else if ((CUR == '\'') || (CUR == '"')) { 7791 xmlXPathCompLiteral(ctxt); 7792 } else { 7793 xmlXPathCompFunctionCall(ctxt); 7794 } 7795 SKIP_BLANKS; 7796} 7797 7798/** 7799 * xmlXPathCompFilterExpr: 7800 * @ctxt: the XPath Parser context 7801 * 7802 * [20] FilterExpr ::= PrimaryExpr 7803 * | FilterExpr Predicate 7804 * 7805 * Compile a filter expression. 7806 * Square brackets are used to filter expressions in the same way that 7807 * they are used in location paths. It is an error if the expression to 7808 * be filtered does not evaluate to a node-set. The context node list 7809 * used for evaluating the expression in square brackets is the node-set 7810 * to be filtered listed in document order. 7811 */ 7812 7813static void 7814xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 7815 xmlXPathCompPrimaryExpr(ctxt); 7816 CHECK_ERROR; 7817 SKIP_BLANKS; 7818 7819 while (CUR == '[') { 7820 xmlXPathCompPredicate(ctxt, 1); 7821 SKIP_BLANKS; 7822 } 7823 7824 7825} 7826 7827/** 7828 * xmlXPathScanName: 7829 * @ctxt: the XPath Parser context 7830 * 7831 * Trickery: parse an XML name but without consuming the input flow 7832 * Needed to avoid insanity in the parser state. 7833 * 7834 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 7835 * CombiningChar | Extender 7836 * 7837 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 7838 * 7839 * [6] Names ::= Name (S Name)* 7840 * 7841 * Returns the Name parsed or NULL 7842 */ 7843 7844static xmlChar * 7845xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 7846 xmlChar buf[XML_MAX_NAMELEN]; 7847 int len = 0; 7848 7849 SKIP_BLANKS; 7850 if (!IS_LETTER(CUR) && (CUR != '_') && 7851 (CUR != ':')) { 7852 return(NULL); 7853 } 7854 7855 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) || 7856 (NXT(len) == '.') || (NXT(len) == '-') || 7857 (NXT(len) == '_') || (NXT(len) == ':') || 7858 (IS_COMBINING(NXT(len))) || 7859 (IS_EXTENDER(NXT(len)))) { 7860 buf[len] = NXT(len); 7861 len++; 7862 if (len >= XML_MAX_NAMELEN) { 7863 xmlGenericError(xmlGenericErrorContext, 7864 "xmlScanName: reached XML_MAX_NAMELEN limit\n"); 7865 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) || 7866 (NXT(len) == '.') || (NXT(len) == '-') || 7867 (NXT(len) == '_') || (NXT(len) == ':') || 7868 (IS_COMBINING(NXT(len))) || 7869 (IS_EXTENDER(NXT(len)))) 7870 len++; 7871 break; 7872 } 7873 } 7874 return(xmlStrndup(buf, len)); 7875} 7876 7877/** 7878 * xmlXPathCompPathExpr: 7879 * @ctxt: the XPath Parser context 7880 * 7881 * [19] PathExpr ::= LocationPath 7882 * | FilterExpr 7883 * | FilterExpr '/' RelativeLocationPath 7884 * | FilterExpr '//' RelativeLocationPath 7885 * 7886 * Compile a path expression. 7887 * The / operator and // operators combine an arbitrary expression 7888 * and a relative location path. It is an error if the expression 7889 * does not evaluate to a node-set. 7890 * The / operator does composition in the same way as when / is 7891 * used in a location path. As in location paths, // is short for 7892 * /descendant-or-self::node()/. 7893 */ 7894 7895static void 7896xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 7897 int lc = 1; /* Should we branch to LocationPath ? */ 7898 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 7899 7900 SKIP_BLANKS; 7901 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) || 7902 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) { 7903 lc = 0; 7904 } else if (CUR == '*') { 7905 /* relative or absolute location path */ 7906 lc = 1; 7907 } else if (CUR == '/') { 7908 /* relative or absolute location path */ 7909 lc = 1; 7910 } else if (CUR == '@') { 7911 /* relative abbreviated attribute location path */ 7912 lc = 1; 7913 } else if (CUR == '.') { 7914 /* relative abbreviated attribute location path */ 7915 lc = 1; 7916 } else { 7917 /* 7918 * Problem is finding if we have a name here whether it's: 7919 * - a nodetype 7920 * - a function call in which case it's followed by '(' 7921 * - an axis in which case it's followed by ':' 7922 * - a element name 7923 * We do an a priori analysis here rather than having to 7924 * maintain parsed token content through the recursive function 7925 * calls. This looks uglier but makes the code quite easier to 7926 * read/write/debug. 7927 */ 7928 SKIP_BLANKS; 7929 name = xmlXPathScanName(ctxt); 7930 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 7931#ifdef DEBUG_STEP 7932 xmlGenericError(xmlGenericErrorContext, 7933 "PathExpr: Axis\n"); 7934#endif 7935 lc = 1; 7936 xmlFree(name); 7937 } else if (name != NULL) { 7938 int len =xmlStrlen(name); 7939 7940 7941 while (NXT(len) != 0) { 7942 if (NXT(len) == '/') { 7943 /* element name */ 7944#ifdef DEBUG_STEP 7945 xmlGenericError(xmlGenericErrorContext, 7946 "PathExpr: AbbrRelLocation\n"); 7947#endif 7948 lc = 1; 7949 break; 7950 } else if (IS_BLANK(NXT(len))) { 7951 /* ignore blanks */ 7952 ; 7953 } else if (NXT(len) == ':') { 7954#ifdef DEBUG_STEP 7955 xmlGenericError(xmlGenericErrorContext, 7956 "PathExpr: AbbrRelLocation\n"); 7957#endif 7958 lc = 1; 7959 break; 7960 } else if ((NXT(len) == '(')) { 7961 /* Note Type or Function */ 7962 if (xmlXPathIsNodeType(name)) { 7963#ifdef DEBUG_STEP 7964 xmlGenericError(xmlGenericErrorContext, 7965 "PathExpr: Type search\n"); 7966#endif 7967 lc = 1; 7968 } else { 7969#ifdef DEBUG_STEP 7970 xmlGenericError(xmlGenericErrorContext, 7971 "PathExpr: function call\n"); 7972#endif 7973 lc = 0; 7974 } 7975 break; 7976 } else if ((NXT(len) == '[')) { 7977 /* element name */ 7978#ifdef DEBUG_STEP 7979 xmlGenericError(xmlGenericErrorContext, 7980 "PathExpr: AbbrRelLocation\n"); 7981#endif 7982 lc = 1; 7983 break; 7984 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 7985 (NXT(len) == '=')) { 7986 lc = 1; 7987 break; 7988 } else { 7989 lc = 1; 7990 break; 7991 } 7992 len++; 7993 } 7994 if (NXT(len) == 0) { 7995#ifdef DEBUG_STEP 7996 xmlGenericError(xmlGenericErrorContext, 7997 "PathExpr: AbbrRelLocation\n"); 7998#endif 7999 /* element name */ 8000 lc = 1; 8001 } 8002 xmlFree(name); 8003 } else { 8004 /* make sure all cases are covered explicitely */ 8005 XP_ERROR(XPATH_EXPR_ERROR); 8006 } 8007 } 8008 8009 if (lc) { 8010 if (CUR == '/') { 8011 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 8012 } else { 8013 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 8014 } 8015 xmlXPathCompLocationPath(ctxt); 8016 } else { 8017 xmlXPathCompFilterExpr(ctxt); 8018 CHECK_ERROR; 8019 if ((CUR == '/') && (NXT(1) == '/')) { 8020 SKIP(2); 8021 SKIP_BLANKS; 8022 8023 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 8024 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 8025 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 8026 8027 xmlXPathCompRelativeLocationPath(ctxt); 8028 } else if (CUR == '/') { 8029 xmlXPathCompRelativeLocationPath(ctxt); 8030 } 8031 } 8032 SKIP_BLANKS; 8033} 8034 8035/** 8036 * xmlXPathCompUnionExpr: 8037 * @ctxt: the XPath Parser context 8038 * 8039 * [18] UnionExpr ::= PathExpr 8040 * | UnionExpr '|' PathExpr 8041 * 8042 * Compile an union expression. 8043 */ 8044 8045static void 8046xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 8047 xmlXPathCompPathExpr(ctxt); 8048 CHECK_ERROR; 8049 SKIP_BLANKS; 8050 while (CUR == '|') { 8051 int op1 = ctxt->comp->last; 8052 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 8053 8054 NEXT; 8055 SKIP_BLANKS; 8056 xmlXPathCompPathExpr(ctxt); 8057 8058 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 8059 8060 SKIP_BLANKS; 8061 } 8062} 8063 8064/** 8065 * xmlXPathCompUnaryExpr: 8066 * @ctxt: the XPath Parser context 8067 * 8068 * [27] UnaryExpr ::= UnionExpr 8069 * | '-' UnaryExpr 8070 * 8071 * Compile an unary expression. 8072 */ 8073 8074static void 8075xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 8076 int minus = 0; 8077 int found = 0; 8078 8079 SKIP_BLANKS; 8080 while (CUR == '-') { 8081 minus = 1 - minus; 8082 found = 1; 8083 NEXT; 8084 SKIP_BLANKS; 8085 } 8086 8087 xmlXPathCompUnionExpr(ctxt); 8088 CHECK_ERROR; 8089 if (found) { 8090 if (minus) 8091 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 8092 else 8093 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 8094 } 8095} 8096 8097/** 8098 * xmlXPathCompMultiplicativeExpr: 8099 * @ctxt: the XPath Parser context 8100 * 8101 * [26] MultiplicativeExpr ::= UnaryExpr 8102 * | MultiplicativeExpr MultiplyOperator UnaryExpr 8103 * | MultiplicativeExpr 'div' UnaryExpr 8104 * | MultiplicativeExpr 'mod' UnaryExpr 8105 * [34] MultiplyOperator ::= '*' 8106 * 8107 * Compile an Additive expression. 8108 */ 8109 8110static void 8111xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 8112 xmlXPathCompUnaryExpr(ctxt); 8113 CHECK_ERROR; 8114 SKIP_BLANKS; 8115 while ((CUR == '*') || 8116 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 8117 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 8118 int op = -1; 8119 int op1 = ctxt->comp->last; 8120 8121 if (CUR == '*') { 8122 op = 0; 8123 NEXT; 8124 } else if (CUR == 'd') { 8125 op = 1; 8126 SKIP(3); 8127 } else if (CUR == 'm') { 8128 op = 2; 8129 SKIP(3); 8130 } 8131 SKIP_BLANKS; 8132 xmlXPathCompUnaryExpr(ctxt); 8133 CHECK_ERROR; 8134 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 8135 SKIP_BLANKS; 8136 } 8137} 8138 8139/** 8140 * xmlXPathCompAdditiveExpr: 8141 * @ctxt: the XPath Parser context 8142 * 8143 * [25] AdditiveExpr ::= MultiplicativeExpr 8144 * | AdditiveExpr '+' MultiplicativeExpr 8145 * | AdditiveExpr '-' MultiplicativeExpr 8146 * 8147 * Compile an Additive expression. 8148 */ 8149 8150static void 8151xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 8152 8153 xmlXPathCompMultiplicativeExpr(ctxt); 8154 CHECK_ERROR; 8155 SKIP_BLANKS; 8156 while ((CUR == '+') || (CUR == '-')) { 8157 int plus; 8158 int op1 = ctxt->comp->last; 8159 8160 if (CUR == '+') plus = 1; 8161 else plus = 0; 8162 NEXT; 8163 SKIP_BLANKS; 8164 xmlXPathCompMultiplicativeExpr(ctxt); 8165 CHECK_ERROR; 8166 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 8167 SKIP_BLANKS; 8168 } 8169} 8170 8171/** 8172 * xmlXPathCompRelationalExpr: 8173 * @ctxt: the XPath Parser context 8174 * 8175 * [24] RelationalExpr ::= AdditiveExpr 8176 * | RelationalExpr '<' AdditiveExpr 8177 * | RelationalExpr '>' AdditiveExpr 8178 * | RelationalExpr '<=' AdditiveExpr 8179 * | RelationalExpr '>=' AdditiveExpr 8180 * 8181 * A <= B > C is allowed ? Answer from James, yes with 8182 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 8183 * which is basically what got implemented. 8184 * 8185 * Compile a Relational expression, then push the result 8186 * on the stack 8187 */ 8188 8189static void 8190xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 8191 xmlXPathCompAdditiveExpr(ctxt); 8192 CHECK_ERROR; 8193 SKIP_BLANKS; 8194 while ((CUR == '<') || 8195 (CUR == '>') || 8196 ((CUR == '<') && (NXT(1) == '=')) || 8197 ((CUR == '>') && (NXT(1) == '='))) { 8198 int inf, strict; 8199 int op1 = ctxt->comp->last; 8200 8201 if (CUR == '<') inf = 1; 8202 else inf = 0; 8203 if (NXT(1) == '=') strict = 0; 8204 else strict = 1; 8205 NEXT; 8206 if (!strict) NEXT; 8207 SKIP_BLANKS; 8208 xmlXPathCompAdditiveExpr(ctxt); 8209 CHECK_ERROR; 8210 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 8211 SKIP_BLANKS; 8212 } 8213} 8214 8215/** 8216 * xmlXPathCompEqualityExpr: 8217 * @ctxt: the XPath Parser context 8218 * 8219 * [23] EqualityExpr ::= RelationalExpr 8220 * | EqualityExpr '=' RelationalExpr 8221 * | EqualityExpr '!=' RelationalExpr 8222 * 8223 * A != B != C is allowed ? Answer from James, yes with 8224 * (RelationalExpr = RelationalExpr) = RelationalExpr 8225 * (RelationalExpr != RelationalExpr) != RelationalExpr 8226 * which is basically what got implemented. 8227 * 8228 * Compile an Equality expression. 8229 * 8230 */ 8231static void 8232xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 8233 xmlXPathCompRelationalExpr(ctxt); 8234 CHECK_ERROR; 8235 SKIP_BLANKS; 8236 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 8237 int eq; 8238 int op1 = ctxt->comp->last; 8239 8240 if (CUR == '=') eq = 1; 8241 else eq = 0; 8242 NEXT; 8243 if (!eq) NEXT; 8244 SKIP_BLANKS; 8245 xmlXPathCompRelationalExpr(ctxt); 8246 CHECK_ERROR; 8247 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 8248 SKIP_BLANKS; 8249 } 8250} 8251 8252/** 8253 * xmlXPathCompAndExpr: 8254 * @ctxt: the XPath Parser context 8255 * 8256 * [22] AndExpr ::= EqualityExpr 8257 * | AndExpr 'and' EqualityExpr 8258 * 8259 * Compile an AND expression. 8260 * 8261 */ 8262static void 8263xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 8264 xmlXPathCompEqualityExpr(ctxt); 8265 CHECK_ERROR; 8266 SKIP_BLANKS; 8267 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 8268 int op1 = ctxt->comp->last; 8269 SKIP(3); 8270 SKIP_BLANKS; 8271 xmlXPathCompEqualityExpr(ctxt); 8272 CHECK_ERROR; 8273 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 8274 SKIP_BLANKS; 8275 } 8276} 8277 8278/** 8279 * xmlXPathCompileExpr: 8280 * @ctxt: the XPath Parser context 8281 * 8282 * [14] Expr ::= OrExpr 8283 * [21] OrExpr ::= AndExpr 8284 * | OrExpr 'or' AndExpr 8285 * 8286 * Parse and compile an expression 8287 */ 8288static void 8289xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) { 8290 xmlXPathCompAndExpr(ctxt); 8291 CHECK_ERROR; 8292 SKIP_BLANKS; 8293 while ((CUR == 'o') && (NXT(1) == 'r')) { 8294 int op1 = ctxt->comp->last; 8295 SKIP(2); 8296 SKIP_BLANKS; 8297 xmlXPathCompAndExpr(ctxt); 8298 CHECK_ERROR; 8299 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 8300 op1 = ctxt->comp->nbStep; 8301 SKIP_BLANKS; 8302 } 8303 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) { 8304 /* more ops could be optimized too */ 8305 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 8306 } 8307} 8308 8309/** 8310 * xmlXPathCompPredicate: 8311 * @ctxt: the XPath Parser context 8312 * @filter: act as a filter 8313 * 8314 * [8] Predicate ::= '[' PredicateExpr ']' 8315 * [9] PredicateExpr ::= Expr 8316 * 8317 * Compile a predicate expression 8318 */ 8319static void 8320xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 8321 int op1 = ctxt->comp->last; 8322 8323 SKIP_BLANKS; 8324 if (CUR != '[') { 8325 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 8326 } 8327 NEXT; 8328 SKIP_BLANKS; 8329 8330 ctxt->comp->last = -1; 8331 xmlXPathCompileExpr(ctxt); 8332 CHECK_ERROR; 8333 8334 if (CUR != ']') { 8335 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 8336 } 8337 8338 if (filter) 8339 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 8340 else 8341 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 8342 8343 NEXT; 8344 SKIP_BLANKS; 8345} 8346 8347/** 8348 * xmlXPathCompNodeTest: 8349 * @ctxt: the XPath Parser context 8350 * @test: pointer to a xmlXPathTestVal 8351 * @type: pointer to a xmlXPathTypeVal 8352 * @prefix: placeholder for a possible name prefix 8353 * 8354 * [7] NodeTest ::= NameTest 8355 * | NodeType '(' ')' 8356 * | 'processing-instruction' '(' Literal ')' 8357 * 8358 * [37] NameTest ::= '*' 8359 * | NCName ':' '*' 8360 * | QName 8361 * [38] NodeType ::= 'comment' 8362 * | 'text' 8363 * | 'processing-instruction' 8364 * | 'node' 8365 * 8366 * Returns the name found and update @test, @type and @prefix appropriately 8367 */ 8368static xmlChar * 8369xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 8370 xmlXPathTypeVal *type, const xmlChar **prefix, 8371 xmlChar *name) { 8372 int blanks; 8373 8374 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 8375 STRANGE; 8376 return(NULL); 8377 } 8378 *type = (xmlXPathTypeVal) 0; 8379 *test = (xmlXPathTestVal) 0; 8380 *prefix = NULL; 8381 SKIP_BLANKS; 8382 8383 if ((name == NULL) && (CUR == '*')) { 8384 /* 8385 * All elements 8386 */ 8387 NEXT; 8388 *test = NODE_TEST_ALL; 8389 return(NULL); 8390 } 8391 8392 if (name == NULL) 8393 name = xmlXPathParseNCName(ctxt); 8394 if (name == NULL) { 8395 XP_ERROR0(XPATH_EXPR_ERROR); 8396 } 8397 8398 blanks = IS_BLANK(CUR); 8399 SKIP_BLANKS; 8400 if (CUR == '(') { 8401 NEXT; 8402 /* 8403 * NodeType or PI search 8404 */ 8405 if (xmlStrEqual(name, BAD_CAST "comment")) 8406 *type = NODE_TYPE_COMMENT; 8407 else if (xmlStrEqual(name, BAD_CAST "node")) 8408 *type = NODE_TYPE_NODE; 8409 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 8410 *type = NODE_TYPE_PI; 8411 else if (xmlStrEqual(name, BAD_CAST "text")) 8412 *type = NODE_TYPE_TEXT; 8413 else { 8414 if (name != NULL) 8415 xmlFree(name); 8416 XP_ERROR0(XPATH_EXPR_ERROR); 8417 } 8418 8419 *test = NODE_TEST_TYPE; 8420 8421 SKIP_BLANKS; 8422 if (*type == NODE_TYPE_PI) { 8423 /* 8424 * Specific case: search a PI by name. 8425 */ 8426 if (name != NULL) 8427 xmlFree(name); 8428 name = NULL; 8429 if (CUR != ')') { 8430 name = xmlXPathParseLiteral(ctxt); 8431 CHECK_ERROR 0; 8432 *test = NODE_TEST_PI; 8433 SKIP_BLANKS; 8434 } 8435 } 8436 if (CUR != ')') { 8437 if (name != NULL) 8438 xmlFree(name); 8439 XP_ERROR0(XPATH_UNCLOSED_ERROR); 8440 } 8441 NEXT; 8442 return(name); 8443 } 8444 *test = NODE_TEST_NAME; 8445 if ((!blanks) && (CUR == ':')) { 8446 NEXT; 8447 8448 /* 8449 * Since currently the parser context don't have a 8450 * namespace list associated: 8451 * The namespace name for this prefix can be computed 8452 * only at evaluation time. The compilation is done 8453 * outside of any context. 8454 */ 8455#if 0 8456 *prefix = xmlXPathNsLookup(ctxt->context, name); 8457 if (name != NULL) 8458 xmlFree(name); 8459 if (*prefix == NULL) { 8460 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 8461 } 8462#else 8463 *prefix = name; 8464#endif 8465 8466 if (CUR == '*') { 8467 /* 8468 * All elements 8469 */ 8470 NEXT; 8471 *test = NODE_TEST_ALL; 8472 return(NULL); 8473 } 8474 8475 name = xmlXPathParseNCName(ctxt); 8476 if (name == NULL) { 8477 XP_ERROR0(XPATH_EXPR_ERROR); 8478 } 8479 } 8480 return(name); 8481} 8482 8483/** 8484 * xmlXPathIsAxisName: 8485 * @name: a preparsed name token 8486 * 8487 * [6] AxisName ::= 'ancestor' 8488 * | 'ancestor-or-self' 8489 * | 'attribute' 8490 * | 'child' 8491 * | 'descendant' 8492 * | 'descendant-or-self' 8493 * | 'following' 8494 * | 'following-sibling' 8495 * | 'namespace' 8496 * | 'parent' 8497 * | 'preceding' 8498 * | 'preceding-sibling' 8499 * | 'self' 8500 * 8501 * Returns the axis or 0 8502 */ 8503static xmlXPathAxisVal 8504xmlXPathIsAxisName(const xmlChar *name) { 8505 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 8506 switch (name[0]) { 8507 case 'a': 8508 if (xmlStrEqual(name, BAD_CAST "ancestor")) 8509 ret = AXIS_ANCESTOR; 8510 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 8511 ret = AXIS_ANCESTOR_OR_SELF; 8512 if (xmlStrEqual(name, BAD_CAST "attribute")) 8513 ret = AXIS_ATTRIBUTE; 8514 break; 8515 case 'c': 8516 if (xmlStrEqual(name, BAD_CAST "child")) 8517 ret = AXIS_CHILD; 8518 break; 8519 case 'd': 8520 if (xmlStrEqual(name, BAD_CAST "descendant")) 8521 ret = AXIS_DESCENDANT; 8522 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 8523 ret = AXIS_DESCENDANT_OR_SELF; 8524 break; 8525 case 'f': 8526 if (xmlStrEqual(name, BAD_CAST "following")) 8527 ret = AXIS_FOLLOWING; 8528 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 8529 ret = AXIS_FOLLOWING_SIBLING; 8530 break; 8531 case 'n': 8532 if (xmlStrEqual(name, BAD_CAST "namespace")) 8533 ret = AXIS_NAMESPACE; 8534 break; 8535 case 'p': 8536 if (xmlStrEqual(name, BAD_CAST "parent")) 8537 ret = AXIS_PARENT; 8538 if (xmlStrEqual(name, BAD_CAST "preceding")) 8539 ret = AXIS_PRECEDING; 8540 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 8541 ret = AXIS_PRECEDING_SIBLING; 8542 break; 8543 case 's': 8544 if (xmlStrEqual(name, BAD_CAST "self")) 8545 ret = AXIS_SELF; 8546 break; 8547 } 8548 return(ret); 8549} 8550 8551/** 8552 * xmlXPathCompStep: 8553 * @ctxt: the XPath Parser context 8554 * 8555 * [4] Step ::= AxisSpecifier NodeTest Predicate* 8556 * | AbbreviatedStep 8557 * 8558 * [12] AbbreviatedStep ::= '.' | '..' 8559 * 8560 * [5] AxisSpecifier ::= AxisName '::' 8561 * | AbbreviatedAxisSpecifier 8562 * 8563 * [13] AbbreviatedAxisSpecifier ::= '@'? 8564 * 8565 * Modified for XPtr range support as: 8566 * 8567 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 8568 * | AbbreviatedStep 8569 * | 'range-to' '(' Expr ')' Predicate* 8570 * 8571 * Compile one step in a Location Path 8572 * A location step of . is short for self::node(). This is 8573 * particularly useful in conjunction with //. For example, the 8574 * location path .//para is short for 8575 * self::node()/descendant-or-self::node()/child::para 8576 * and so will select all para descendant elements of the context 8577 * node. 8578 * Similarly, a location step of .. is short for parent::node(). 8579 * For example, ../title is short for parent::node()/child::title 8580 * and so will select the title children of the parent of the context 8581 * node. 8582 */ 8583static void 8584xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 8585#ifdef LIBXML_XPTR_ENABLED 8586 int rangeto = 0; 8587 int op2 = -1; 8588#endif 8589 8590 SKIP_BLANKS; 8591 if ((CUR == '.') && (NXT(1) == '.')) { 8592 SKIP(2); 8593 SKIP_BLANKS; 8594 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 8595 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 8596 } else if (CUR == '.') { 8597 NEXT; 8598 SKIP_BLANKS; 8599 } else { 8600 xmlChar *name = NULL; 8601 const xmlChar *prefix = NULL; 8602 xmlXPathTestVal test; 8603 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 8604 xmlXPathTypeVal type; 8605 int op1; 8606 8607 /* 8608 * The modification needed for XPointer change to the production 8609 */ 8610#ifdef LIBXML_XPTR_ENABLED 8611 if (ctxt->xptr) { 8612 name = xmlXPathParseNCName(ctxt); 8613 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 8614 op2 = ctxt->comp->last; 8615 xmlFree(name); 8616 SKIP_BLANKS; 8617 if (CUR != '(') { 8618 XP_ERROR(XPATH_EXPR_ERROR); 8619 } 8620 NEXT; 8621 SKIP_BLANKS; 8622 8623 xmlXPathCompileExpr(ctxt); 8624 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 8625 CHECK_ERROR; 8626 8627 SKIP_BLANKS; 8628 if (CUR != ')') { 8629 XP_ERROR(XPATH_EXPR_ERROR); 8630 } 8631 NEXT; 8632 rangeto = 1; 8633 goto eval_predicates; 8634 } 8635 } 8636#endif 8637 if (CUR == '*') { 8638 axis = AXIS_CHILD; 8639 } else { 8640 if (name == NULL) 8641 name = xmlXPathParseNCName(ctxt); 8642 if (name != NULL) { 8643 axis = xmlXPathIsAxisName(name); 8644 if (axis != 0) { 8645 SKIP_BLANKS; 8646 if ((CUR == ':') && (NXT(1) == ':')) { 8647 SKIP(2); 8648 xmlFree(name); 8649 name = NULL; 8650 } else { 8651 /* an element name can conflict with an axis one :-\ */ 8652 axis = AXIS_CHILD; 8653 } 8654 } else { 8655 axis = AXIS_CHILD; 8656 } 8657 } else if (CUR == '@') { 8658 NEXT; 8659 axis = AXIS_ATTRIBUTE; 8660 } else { 8661 axis = AXIS_CHILD; 8662 } 8663 } 8664 8665 CHECK_ERROR; 8666 8667 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 8668 if (test == 0) 8669 return; 8670 8671#ifdef DEBUG_STEP 8672 xmlGenericError(xmlGenericErrorContext, 8673 "Basis : computing new set\n"); 8674#endif 8675 8676#ifdef DEBUG_STEP 8677 xmlGenericError(xmlGenericErrorContext, "Basis : "); 8678 if (ctxt->value == NULL) 8679 xmlGenericError(xmlGenericErrorContext, "no value\n"); 8680 else if (ctxt->value->nodesetval == NULL) 8681 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 8682 else 8683 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 8684#endif 8685 8686eval_predicates: 8687 op1 = ctxt->comp->last; 8688 ctxt->comp->last = -1; 8689 8690 SKIP_BLANKS; 8691 while (CUR == '[') { 8692 xmlXPathCompPredicate(ctxt, 0); 8693 } 8694 8695#ifdef LIBXML_XPTR_ENABLED 8696 if (rangeto) { 8697 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 8698 } else 8699#endif 8700 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 8701 test, type, (void *)prefix, (void *)name); 8702 8703 } 8704#ifdef DEBUG_STEP 8705 xmlGenericError(xmlGenericErrorContext, "Step : "); 8706 if (ctxt->value == NULL) 8707 xmlGenericError(xmlGenericErrorContext, "no value\n"); 8708 else if (ctxt->value->nodesetval == NULL) 8709 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 8710 else 8711 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 8712 ctxt->value->nodesetval); 8713#endif 8714} 8715 8716/** 8717 * xmlXPathCompRelativeLocationPath: 8718 * @ctxt: the XPath Parser context 8719 * 8720 * [3] RelativeLocationPath ::= Step 8721 * | RelativeLocationPath '/' Step 8722 * | AbbreviatedRelativeLocationPath 8723 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 8724 * 8725 * Compile a relative location path. 8726 */ 8727static void 8728xmlXPathCompRelativeLocationPath 8729(xmlXPathParserContextPtr ctxt) { 8730 SKIP_BLANKS; 8731 if ((CUR == '/') && (NXT(1) == '/')) { 8732 SKIP(2); 8733 SKIP_BLANKS; 8734 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 8735 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 8736 } else if (CUR == '/') { 8737 NEXT; 8738 SKIP_BLANKS; 8739 } 8740 xmlXPathCompStep(ctxt); 8741 SKIP_BLANKS; 8742 while (CUR == '/') { 8743 if ((CUR == '/') && (NXT(1) == '/')) { 8744 SKIP(2); 8745 SKIP_BLANKS; 8746 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 8747 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 8748 xmlXPathCompStep(ctxt); 8749 } else if (CUR == '/') { 8750 NEXT; 8751 SKIP_BLANKS; 8752 xmlXPathCompStep(ctxt); 8753 } 8754 SKIP_BLANKS; 8755 } 8756} 8757 8758/** 8759 * xmlXPathCompLocationPath: 8760 * @ctxt: the XPath Parser context 8761 * 8762 * [1] LocationPath ::= RelativeLocationPath 8763 * | AbsoluteLocationPath 8764 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 8765 * | AbbreviatedAbsoluteLocationPath 8766 * [10] AbbreviatedAbsoluteLocationPath ::= 8767 * '//' RelativeLocationPath 8768 * 8769 * Compile a location path 8770 * 8771 * // is short for /descendant-or-self::node()/. For example, 8772 * //para is short for /descendant-or-self::node()/child::para and 8773 * so will select any para element in the document (even a para element 8774 * that is a document element will be selected by //para since the 8775 * document element node is a child of the root node); div//para is 8776 * short for div/descendant-or-self::node()/child::para and so will 8777 * select all para descendants of div children. 8778 */ 8779static void 8780xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 8781 SKIP_BLANKS; 8782 if (CUR != '/') { 8783 xmlXPathCompRelativeLocationPath(ctxt); 8784 } else { 8785 while (CUR == '/') { 8786 if ((CUR == '/') && (NXT(1) == '/')) { 8787 SKIP(2); 8788 SKIP_BLANKS; 8789 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 8790 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 8791 xmlXPathCompRelativeLocationPath(ctxt); 8792 } else if (CUR == '/') { 8793 NEXT; 8794 SKIP_BLANKS; 8795 if ((CUR != 0 ) && 8796 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 8797 (CUR == '@') || (CUR == '*'))) 8798 xmlXPathCompRelativeLocationPath(ctxt); 8799 } 8800 } 8801 } 8802} 8803 8804/************************************************************************ 8805 * * 8806 * XPath precompiled expression evaluation * 8807 * * 8808 ************************************************************************/ 8809 8810static int 8811xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 8812 8813/** 8814 * xmlXPathNodeCollectAndTest: 8815 * @ctxt: the XPath Parser context 8816 * @op: the XPath precompiled step operation 8817 * @first: pointer to the first element in document order 8818 * @last: pointer to the last element in document order 8819 * 8820 * This is the function implementing a step: based on the current list 8821 * of nodes, it builds up a new list, looking at all nodes under that 8822 * axis and selecting them it also do the predicate filtering 8823 * 8824 * Pushes the new NodeSet resulting from the search. 8825 * 8826 * Returns the number of node traversed 8827 */ 8828static int 8829xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 8830 xmlXPathStepOpPtr op, 8831 xmlNodePtr * first, xmlNodePtr * last) 8832{ 8833 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 8834 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 8835 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 8836 const xmlChar *prefix = op->value4; 8837 const xmlChar *name = op->value5; 8838 const xmlChar *URI = NULL; 8839 8840#ifdef DEBUG_STEP 8841 int n = 0; 8842#endif 8843 int i, t = 0; 8844 xmlNodeSetPtr ret, list; 8845 xmlXPathTraversalFunction next = NULL; 8846 void (*addNode) (xmlNodeSetPtr, xmlNodePtr); 8847 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr); 8848 xmlNodePtr cur = NULL; 8849 xmlXPathObjectPtr obj; 8850 xmlNodeSetPtr nodelist; 8851 xmlNodePtr tmp; 8852 8853 CHECK_TYPE0(XPATH_NODESET); 8854 obj = valuePop(ctxt); 8855 addNode = xmlXPathNodeSetAdd; 8856 mergeNodeSet = xmlXPathNodeSetMerge; 8857 if (prefix != NULL) { 8858 URI = xmlXPathNsLookup(ctxt->context, prefix); 8859 if (URI == NULL) 8860 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 8861 } 8862#ifdef DEBUG_STEP 8863 xmlGenericError(xmlGenericErrorContext, "new step : "); 8864#endif 8865 switch (axis) { 8866 case AXIS_ANCESTOR: 8867#ifdef DEBUG_STEP 8868 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 8869#endif 8870 first = NULL; 8871 next = xmlXPathNextAncestor; 8872 break; 8873 case AXIS_ANCESTOR_OR_SELF: 8874#ifdef DEBUG_STEP 8875 xmlGenericError(xmlGenericErrorContext, 8876 "axis 'ancestors-or-self' "); 8877#endif 8878 first = NULL; 8879 next = xmlXPathNextAncestorOrSelf; 8880 break; 8881 case AXIS_ATTRIBUTE: 8882#ifdef DEBUG_STEP 8883 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 8884#endif 8885 first = NULL; 8886 last = NULL; 8887 next = xmlXPathNextAttribute; 8888 mergeNodeSet = xmlXPathNodeSetMergeUnique; 8889 break; 8890 case AXIS_CHILD: 8891#ifdef DEBUG_STEP 8892 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 8893#endif 8894 last = NULL; 8895 next = xmlXPathNextChild; 8896 mergeNodeSet = xmlXPathNodeSetMergeUnique; 8897 break; 8898 case AXIS_DESCENDANT: 8899#ifdef DEBUG_STEP 8900 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 8901#endif 8902 last = NULL; 8903 next = xmlXPathNextDescendant; 8904 break; 8905 case AXIS_DESCENDANT_OR_SELF: 8906#ifdef DEBUG_STEP 8907 xmlGenericError(xmlGenericErrorContext, 8908 "axis 'descendant-or-self' "); 8909#endif 8910 last = NULL; 8911 next = xmlXPathNextDescendantOrSelf; 8912 break; 8913 case AXIS_FOLLOWING: 8914#ifdef DEBUG_STEP 8915 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 8916#endif 8917 last = NULL; 8918 next = xmlXPathNextFollowing; 8919 break; 8920 case AXIS_FOLLOWING_SIBLING: 8921#ifdef DEBUG_STEP 8922 xmlGenericError(xmlGenericErrorContext, 8923 "axis 'following-siblings' "); 8924#endif 8925 last = NULL; 8926 next = xmlXPathNextFollowingSibling; 8927 break; 8928 case AXIS_NAMESPACE: 8929#ifdef DEBUG_STEP 8930 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 8931#endif 8932 first = NULL; 8933 last = NULL; 8934 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 8935 mergeNodeSet = xmlXPathNodeSetMergeUnique; 8936 break; 8937 case AXIS_PARENT: 8938#ifdef DEBUG_STEP 8939 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 8940#endif 8941 first = NULL; 8942 next = xmlXPathNextParent; 8943 break; 8944 case AXIS_PRECEDING: 8945#ifdef DEBUG_STEP 8946 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 8947#endif 8948 first = NULL; 8949 next = xmlXPathNextPrecedingInternal; 8950 break; 8951 case AXIS_PRECEDING_SIBLING: 8952#ifdef DEBUG_STEP 8953 xmlGenericError(xmlGenericErrorContext, 8954 "axis 'preceding-sibling' "); 8955#endif 8956 first = NULL; 8957 next = xmlXPathNextPrecedingSibling; 8958 break; 8959 case AXIS_SELF: 8960#ifdef DEBUG_STEP 8961 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 8962#endif 8963 first = NULL; 8964 last = NULL; 8965 next = xmlXPathNextSelf; 8966 mergeNodeSet = xmlXPathNodeSetMergeUnique; 8967 break; 8968 } 8969 if (next == NULL) 8970 return(0); 8971 8972 nodelist = obj->nodesetval; 8973 if (nodelist == NULL) { 8974 xmlXPathFreeObject(obj); 8975 valuePush(ctxt, xmlXPathWrapNodeSet(NULL)); 8976 return(0); 8977 } 8978 addNode = xmlXPathNodeSetAddUnique; 8979 ret = NULL; 8980#ifdef DEBUG_STEP 8981 xmlGenericError(xmlGenericErrorContext, 8982 " context contains %d nodes\n", nodelist->nodeNr); 8983 switch (test) { 8984 case NODE_TEST_NONE: 8985 xmlGenericError(xmlGenericErrorContext, 8986 " searching for none !!!\n"); 8987 break; 8988 case NODE_TEST_TYPE: 8989 xmlGenericError(xmlGenericErrorContext, 8990 " searching for type %d\n", type); 8991 break; 8992 case NODE_TEST_PI: 8993 xmlGenericError(xmlGenericErrorContext, 8994 " searching for PI !!!\n"); 8995 break; 8996 case NODE_TEST_ALL: 8997 xmlGenericError(xmlGenericErrorContext, 8998 " searching for *\n"); 8999 break; 9000 case NODE_TEST_NS: 9001 xmlGenericError(xmlGenericErrorContext, 9002 " searching for namespace %s\n", 9003 prefix); 9004 break; 9005 case NODE_TEST_NAME: 9006 xmlGenericError(xmlGenericErrorContext, 9007 " searching for name %s\n", name); 9008 if (prefix != NULL) 9009 xmlGenericError(xmlGenericErrorContext, 9010 " with namespace %s\n", prefix); 9011 break; 9012 } 9013 xmlGenericError(xmlGenericErrorContext, "Testing : "); 9014#endif 9015 /* 9016 * 2.3 Node Tests 9017 * - For the attribute axis, the principal node type is attribute. 9018 * - For the namespace axis, the principal node type is namespace. 9019 * - For other axes, the principal node type is element. 9020 * 9021 * A node test * is true for any node of the 9022 * principal node type. For example, child::* will 9023 * select all element children of the context node 9024 */ 9025 tmp = ctxt->context->node; 9026 for (i = 0; i < nodelist->nodeNr; i++) { 9027 ctxt->context->node = nodelist->nodeTab[i]; 9028 9029 cur = NULL; 9030 list = xmlXPathNodeSetCreate(NULL); 9031 do { 9032 cur = next(ctxt, cur); 9033 if (cur == NULL) 9034 break; 9035 if ((first != NULL) && (*first == cur)) 9036 break; 9037 if (((t % 256) == 0) && 9038 (first != NULL) && (*first != NULL) && 9039 (xmlXPathCmpNodes(*first, cur) >= 0)) 9040 break; 9041 if ((last != NULL) && (*last == cur)) 9042 break; 9043 if (((t % 256) == 0) && 9044 (last != NULL) && (*last != NULL) && 9045 (xmlXPathCmpNodes(cur, *last) >= 0)) 9046 break; 9047 t++; 9048#ifdef DEBUG_STEP 9049 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 9050#endif 9051 switch (test) { 9052 case NODE_TEST_NONE: 9053 ctxt->context->node = tmp; 9054 STRANGE return(t); 9055 case NODE_TEST_TYPE: 9056 if ((cur->type == type) || 9057 ((type == NODE_TYPE_NODE) && 9058 ((cur->type == XML_DOCUMENT_NODE) || 9059 (cur->type == XML_HTML_DOCUMENT_NODE) || 9060 (cur->type == XML_ELEMENT_NODE) || 9061 (cur->type == XML_NAMESPACE_DECL) || 9062 (cur->type == XML_ATTRIBUTE_NODE) || 9063 (cur->type == XML_PI_NODE) || 9064 (cur->type == XML_COMMENT_NODE) || 9065 (cur->type == XML_CDATA_SECTION_NODE) || 9066 (cur->type == XML_TEXT_NODE))) || 9067 ((type == NODE_TYPE_TEXT) && 9068 (cur->type == XML_CDATA_SECTION_NODE))) { 9069#ifdef DEBUG_STEP 9070 n++; 9071#endif 9072 addNode(list, cur); 9073 } 9074 break; 9075 case NODE_TEST_PI: 9076 if (cur->type == XML_PI_NODE) { 9077 if ((name != NULL) && 9078 (!xmlStrEqual(name, cur->name))) 9079 break; 9080#ifdef DEBUG_STEP 9081 n++; 9082#endif 9083 addNode(list, cur); 9084 } 9085 break; 9086 case NODE_TEST_ALL: 9087 if (axis == AXIS_ATTRIBUTE) { 9088 if (cur->type == XML_ATTRIBUTE_NODE) { 9089#ifdef DEBUG_STEP 9090 n++; 9091#endif 9092 addNode(list, cur); 9093 } 9094 } else if (axis == AXIS_NAMESPACE) { 9095 if (cur->type == XML_NAMESPACE_DECL) { 9096#ifdef DEBUG_STEP 9097 n++; 9098#endif 9099 xmlXPathNodeSetAddNs(list, ctxt->context->node, 9100 (xmlNsPtr) cur); 9101 } 9102 } else { 9103 if (cur->type == XML_ELEMENT_NODE) { 9104 if (prefix == NULL) { 9105#ifdef DEBUG_STEP 9106 n++; 9107#endif 9108 addNode(list, cur); 9109 } else if ((cur->ns != NULL) && 9110 (xmlStrEqual(URI, cur->ns->href))) { 9111#ifdef DEBUG_STEP 9112 n++; 9113#endif 9114 addNode(list, cur); 9115 } 9116 } 9117 } 9118 break; 9119 case NODE_TEST_NS:{ 9120 TODO; 9121 break; 9122 } 9123 case NODE_TEST_NAME: 9124 switch (cur->type) { 9125 case XML_ELEMENT_NODE: 9126 if (xmlStrEqual(name, cur->name)) { 9127 if (prefix == NULL) { 9128 if (cur->ns == NULL) { 9129#ifdef DEBUG_STEP 9130 n++; 9131#endif 9132 addNode(list, cur); 9133 } 9134 } else { 9135 if ((cur->ns != NULL) && 9136 (xmlStrEqual(URI, 9137 cur->ns->href))) { 9138#ifdef DEBUG_STEP 9139 n++; 9140#endif 9141 addNode(list, cur); 9142 } 9143 } 9144 } 9145 break; 9146 case XML_ATTRIBUTE_NODE:{ 9147 xmlAttrPtr attr = (xmlAttrPtr) cur; 9148 9149 if (xmlStrEqual(name, attr->name)) { 9150 if (prefix == NULL) { 9151 if ((attr->ns == NULL) || 9152 (attr->ns->prefix == NULL)) { 9153#ifdef DEBUG_STEP 9154 n++; 9155#endif 9156 addNode(list, 9157 (xmlNodePtr) attr); 9158 } 9159 } else { 9160 if ((attr->ns != NULL) && 9161 (xmlStrEqual(URI, 9162 attr->ns-> 9163 href))) { 9164#ifdef DEBUG_STEP 9165 n++; 9166#endif 9167 addNode(list, 9168 (xmlNodePtr) attr); 9169 } 9170 } 9171 } 9172 break; 9173 } 9174 case XML_NAMESPACE_DECL: 9175 if (cur->type == XML_NAMESPACE_DECL) { 9176 xmlNsPtr ns = (xmlNsPtr) cur; 9177 9178 if ((ns->prefix != NULL) && (name != NULL) 9179 && (xmlStrEqual(ns->prefix, name))) { 9180#ifdef DEBUG_STEP 9181 n++; 9182#endif 9183 xmlXPathNodeSetAddNs(list, 9184 ctxt->context->node, (xmlNsPtr) cur); 9185 } 9186 } 9187 break; 9188 default: 9189 break; 9190 } 9191 break; 9192 break; 9193 } 9194 } while (cur != NULL); 9195 9196 /* 9197 * If there is some predicate filtering do it now 9198 */ 9199 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) { 9200 xmlXPathObjectPtr obj2; 9201 9202 valuePush(ctxt, xmlXPathWrapNodeSet(list)); 9203 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]); 9204 CHECK_TYPE0(XPATH_NODESET); 9205 obj2 = valuePop(ctxt); 9206 list = obj2->nodesetval; 9207 obj2->nodesetval = NULL; 9208 xmlXPathFreeObject(obj2); 9209 } 9210 if (ret == NULL) { 9211 ret = list; 9212 } else { 9213 ret = mergeNodeSet(ret, list); 9214 xmlXPathFreeNodeSet(list); 9215 } 9216 } 9217 ctxt->context->node = tmp; 9218#ifdef DEBUG_STEP 9219 xmlGenericError(xmlGenericErrorContext, 9220 "\nExamined %d nodes, found %d nodes at that step\n", 9221 t, n); 9222#endif 9223 valuePush(ctxt, xmlXPathWrapNodeSet(ret)); 9224 if ((obj->boolval) && (obj->user != NULL)) { 9225 ctxt->value->boolval = 1; 9226 ctxt->value->user = obj->user; 9227 obj->user = NULL; 9228 obj->boolval = 0; 9229 } 9230 xmlXPathFreeObject(obj); 9231 return(t); 9232} 9233 9234/** 9235 * xmlXPathNodeCollectAndTestNth: 9236 * @ctxt: the XPath Parser context 9237 * @op: the XPath precompiled step operation 9238 * @indx: the index to collect 9239 * @first: pointer to the first element in document order 9240 * @last: pointer to the last element in document order 9241 * 9242 * This is the function implementing a step: based on the current list 9243 * of nodes, it builds up a new list, looking at all nodes under that 9244 * axis and selecting them it also do the predicate filtering 9245 * 9246 * Pushes the new NodeSet resulting from the search. 9247 * Returns the number of node traversed 9248 */ 9249static int 9250xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt, 9251 xmlXPathStepOpPtr op, int indx, 9252 xmlNodePtr * first, xmlNodePtr * last) 9253{ 9254 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 9255 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 9256 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 9257 const xmlChar *prefix = op->value4; 9258 const xmlChar *name = op->value5; 9259 const xmlChar *URI = NULL; 9260 int n = 0, t = 0; 9261 9262 int i; 9263 xmlNodeSetPtr list; 9264 xmlXPathTraversalFunction next = NULL; 9265 void (*addNode) (xmlNodeSetPtr, xmlNodePtr); 9266 xmlNodePtr cur = NULL; 9267 xmlXPathObjectPtr obj; 9268 xmlNodeSetPtr nodelist; 9269 xmlNodePtr tmp; 9270 9271 CHECK_TYPE0(XPATH_NODESET); 9272 obj = valuePop(ctxt); 9273 addNode = xmlXPathNodeSetAdd; 9274 if (prefix != NULL) { 9275 URI = xmlXPathNsLookup(ctxt->context, prefix); 9276 if (URI == NULL) 9277 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 9278 } 9279#ifdef DEBUG_STEP_NTH 9280 xmlGenericError(xmlGenericErrorContext, "new step : "); 9281 if (first != NULL) { 9282 if (*first != NULL) 9283 xmlGenericError(xmlGenericErrorContext, "first = %s ", 9284 (*first)->name); 9285 else 9286 xmlGenericError(xmlGenericErrorContext, "first = NULL "); 9287 } 9288 if (last != NULL) { 9289 if (*last != NULL) 9290 xmlGenericError(xmlGenericErrorContext, "last = %s ", 9291 (*last)->name); 9292 else 9293 xmlGenericError(xmlGenericErrorContext, "last = NULL "); 9294 } 9295#endif 9296 switch (axis) { 9297 case AXIS_ANCESTOR: 9298#ifdef DEBUG_STEP_NTH 9299 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 9300#endif 9301 first = NULL; 9302 next = xmlXPathNextAncestor; 9303 break; 9304 case AXIS_ANCESTOR_OR_SELF: 9305#ifdef DEBUG_STEP_NTH 9306 xmlGenericError(xmlGenericErrorContext, 9307 "axis 'ancestors-or-self' "); 9308#endif 9309 first = NULL; 9310 next = xmlXPathNextAncestorOrSelf; 9311 break; 9312 case AXIS_ATTRIBUTE: 9313#ifdef DEBUG_STEP_NTH 9314 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 9315#endif 9316 first = NULL; 9317 last = NULL; 9318 next = xmlXPathNextAttribute; 9319 break; 9320 case AXIS_CHILD: 9321#ifdef DEBUG_STEP_NTH 9322 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 9323#endif 9324 last = NULL; 9325 next = xmlXPathNextChild; 9326 break; 9327 case AXIS_DESCENDANT: 9328#ifdef DEBUG_STEP_NTH 9329 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 9330#endif 9331 last = NULL; 9332 next = xmlXPathNextDescendant; 9333 break; 9334 case AXIS_DESCENDANT_OR_SELF: 9335#ifdef DEBUG_STEP_NTH 9336 xmlGenericError(xmlGenericErrorContext, 9337 "axis 'descendant-or-self' "); 9338#endif 9339 last = NULL; 9340 next = xmlXPathNextDescendantOrSelf; 9341 break; 9342 case AXIS_FOLLOWING: 9343#ifdef DEBUG_STEP_NTH 9344 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 9345#endif 9346 last = NULL; 9347 next = xmlXPathNextFollowing; 9348 break; 9349 case AXIS_FOLLOWING_SIBLING: 9350#ifdef DEBUG_STEP_NTH 9351 xmlGenericError(xmlGenericErrorContext, 9352 "axis 'following-siblings' "); 9353#endif 9354 last = NULL; 9355 next = xmlXPathNextFollowingSibling; 9356 break; 9357 case AXIS_NAMESPACE: 9358#ifdef DEBUG_STEP_NTH 9359 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 9360#endif 9361 last = NULL; 9362 first = NULL; 9363 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 9364 break; 9365 case AXIS_PARENT: 9366#ifdef DEBUG_STEP_NTH 9367 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 9368#endif 9369 first = NULL; 9370 next = xmlXPathNextParent; 9371 break; 9372 case AXIS_PRECEDING: 9373#ifdef DEBUG_STEP_NTH 9374 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 9375#endif 9376 first = NULL; 9377 next = xmlXPathNextPrecedingInternal; 9378 break; 9379 case AXIS_PRECEDING_SIBLING: 9380#ifdef DEBUG_STEP_NTH 9381 xmlGenericError(xmlGenericErrorContext, 9382 "axis 'preceding-sibling' "); 9383#endif 9384 first = NULL; 9385 next = xmlXPathNextPrecedingSibling; 9386 break; 9387 case AXIS_SELF: 9388#ifdef DEBUG_STEP_NTH 9389 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 9390#endif 9391 first = NULL; 9392 last = NULL; 9393 next = xmlXPathNextSelf; 9394 break; 9395 } 9396 if (next == NULL) 9397 return(0); 9398 9399 nodelist = obj->nodesetval; 9400 if (nodelist == NULL) { 9401 xmlXPathFreeObject(obj); 9402 valuePush(ctxt, xmlXPathWrapNodeSet(NULL)); 9403 return(0); 9404 } 9405 addNode = xmlXPathNodeSetAddUnique; 9406#ifdef DEBUG_STEP_NTH 9407 xmlGenericError(xmlGenericErrorContext, 9408 " context contains %d nodes\n", nodelist->nodeNr); 9409 switch (test) { 9410 case NODE_TEST_NONE: 9411 xmlGenericError(xmlGenericErrorContext, 9412 " searching for none !!!\n"); 9413 break; 9414 case NODE_TEST_TYPE: 9415 xmlGenericError(xmlGenericErrorContext, 9416 " searching for type %d\n", type); 9417 break; 9418 case NODE_TEST_PI: 9419 xmlGenericError(xmlGenericErrorContext, 9420 " searching for PI !!!\n"); 9421 break; 9422 case NODE_TEST_ALL: 9423 xmlGenericError(xmlGenericErrorContext, 9424 " searching for *\n"); 9425 break; 9426 case NODE_TEST_NS: 9427 xmlGenericError(xmlGenericErrorContext, 9428 " searching for namespace %s\n", 9429 prefix); 9430 break; 9431 case NODE_TEST_NAME: 9432 xmlGenericError(xmlGenericErrorContext, 9433 " searching for name %s\n", name); 9434 if (prefix != NULL) 9435 xmlGenericError(xmlGenericErrorContext, 9436 " with namespace %s\n", prefix); 9437 break; 9438 } 9439 xmlGenericError(xmlGenericErrorContext, "Testing : "); 9440#endif 9441 /* 9442 * 2.3 Node Tests 9443 * - For the attribute axis, the principal node type is attribute. 9444 * - For the namespace axis, the principal node type is namespace. 9445 * - For other axes, the principal node type is element. 9446 * 9447 * A node test * is true for any node of the 9448 * principal node type. For example, child::* will 9449 * select all element children of the context node 9450 */ 9451 tmp = ctxt->context->node; 9452 list = xmlXPathNodeSetCreate(NULL); 9453 for (i = 0; i < nodelist->nodeNr; i++) { 9454 ctxt->context->node = nodelist->nodeTab[i]; 9455 9456 cur = NULL; 9457 n = 0; 9458 do { 9459 cur = next(ctxt, cur); 9460 if (cur == NULL) 9461 break; 9462 if ((first != NULL) && (*first == cur)) 9463 break; 9464 if (((t % 256) == 0) && 9465 (first != NULL) && (*first != NULL) && 9466 (xmlXPathCmpNodes(*first, cur) >= 0)) 9467 break; 9468 if ((last != NULL) && (*last == cur)) 9469 break; 9470 if (((t % 256) == 0) && 9471 (last != NULL) && (*last != NULL) && 9472 (xmlXPathCmpNodes(cur, *last) >= 0)) 9473 break; 9474 t++; 9475 switch (test) { 9476 case NODE_TEST_NONE: 9477 ctxt->context->node = tmp; 9478 STRANGE return(0); 9479 case NODE_TEST_TYPE: 9480 if ((cur->type == type) || 9481 ((type == NODE_TYPE_NODE) && 9482 ((cur->type == XML_DOCUMENT_NODE) || 9483 (cur->type == XML_HTML_DOCUMENT_NODE) || 9484 (cur->type == XML_ELEMENT_NODE) || 9485 (cur->type == XML_PI_NODE) || 9486 (cur->type == XML_COMMENT_NODE) || 9487 (cur->type == XML_CDATA_SECTION_NODE) || 9488 (cur->type == XML_TEXT_NODE))) || 9489 ((type == NODE_TYPE_TEXT) && 9490 (cur->type == XML_CDATA_SECTION_NODE))) { 9491 n++; 9492 if (n == indx) 9493 addNode(list, cur); 9494 } 9495 break; 9496 case NODE_TEST_PI: 9497 if (cur->type == XML_PI_NODE) { 9498 if ((name != NULL) && 9499 (!xmlStrEqual(name, cur->name))) 9500 break; 9501 n++; 9502 if (n == indx) 9503 addNode(list, cur); 9504 } 9505 break; 9506 case NODE_TEST_ALL: 9507 if (axis == AXIS_ATTRIBUTE) { 9508 if (cur->type == XML_ATTRIBUTE_NODE) { 9509 n++; 9510 if (n == indx) 9511 addNode(list, cur); 9512 } 9513 } else if (axis == AXIS_NAMESPACE) { 9514 if (cur->type == XML_NAMESPACE_DECL) { 9515 n++; 9516 if (n == indx) 9517 xmlXPathNodeSetAddNs(list, ctxt->context->node, 9518 (xmlNsPtr) cur); 9519 } 9520 } else { 9521 if (cur->type == XML_ELEMENT_NODE) { 9522 if (prefix == NULL) { 9523 n++; 9524 if (n == indx) 9525 addNode(list, cur); 9526 } else if ((cur->ns != NULL) && 9527 (xmlStrEqual(URI, cur->ns->href))) { 9528 n++; 9529 if (n == indx) 9530 addNode(list, cur); 9531 } 9532 } 9533 } 9534 break; 9535 case NODE_TEST_NS:{ 9536 TODO; 9537 break; 9538 } 9539 case NODE_TEST_NAME: 9540 switch (cur->type) { 9541 case XML_ELEMENT_NODE: 9542 if (xmlStrEqual(name, cur->name)) { 9543 if (prefix == NULL) { 9544 if (cur->ns == NULL) { 9545 n++; 9546 if (n == indx) 9547 addNode(list, cur); 9548 } 9549 } else { 9550 if ((cur->ns != NULL) && 9551 (xmlStrEqual(URI, 9552 cur->ns->href))) { 9553 n++; 9554 if (n == indx) 9555 addNode(list, cur); 9556 } 9557 } 9558 } 9559 break; 9560 case XML_ATTRIBUTE_NODE:{ 9561 xmlAttrPtr attr = (xmlAttrPtr) cur; 9562 9563 if (xmlStrEqual(name, attr->name)) { 9564 if (prefix == NULL) { 9565 if ((attr->ns == NULL) || 9566 (attr->ns->prefix == NULL)) { 9567 n++; 9568 if (n == indx) 9569 addNode(list, cur); 9570 } 9571 } else { 9572 if ((attr->ns != NULL) && 9573 (xmlStrEqual(URI, 9574 attr->ns-> 9575 href))) { 9576 n++; 9577 if (n == indx) 9578 addNode(list, cur); 9579 } 9580 } 9581 } 9582 break; 9583 } 9584 case XML_NAMESPACE_DECL: 9585 if (cur->type == XML_NAMESPACE_DECL) { 9586 xmlNsPtr ns = (xmlNsPtr) cur; 9587 9588 if ((ns->prefix != NULL) && (name != NULL) 9589 && (xmlStrEqual(ns->prefix, name))) { 9590 n++; 9591 if (n == indx) 9592 xmlXPathNodeSetAddNs(list, 9593 ctxt->context->node, (xmlNsPtr) cur); 9594 } 9595 } 9596 break; 9597 default: 9598 break; 9599 } 9600 break; 9601 break; 9602 } 9603 } while (n < indx); 9604 } 9605 ctxt->context->node = tmp; 9606#ifdef DEBUG_STEP_NTH 9607 xmlGenericError(xmlGenericErrorContext, 9608 "\nExamined %d nodes, found %d nodes at that step\n", 9609 t, list->nodeNr); 9610#endif 9611 valuePush(ctxt, xmlXPathWrapNodeSet(list)); 9612 if ((obj->boolval) && (obj->user != NULL)) { 9613 ctxt->value->boolval = 1; 9614 ctxt->value->user = obj->user; 9615 obj->user = NULL; 9616 obj->boolval = 0; 9617 } 9618 xmlXPathFreeObject(obj); 9619 return(t); 9620} 9621 9622/** 9623 * xmlXPathCompOpEvalFirst: 9624 * @ctxt: the XPath parser context with the compiled expression 9625 * @op: an XPath compiled operation 9626 * @first: the first elem found so far 9627 * 9628 * Evaluate the Precompiled XPath operation searching only the first 9629 * element in document order 9630 * 9631 * Returns the number of examined objects. 9632 */ 9633static int 9634xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 9635 xmlXPathStepOpPtr op, xmlNodePtr * first) 9636{ 9637 int total = 0, cur; 9638 xmlXPathCompExprPtr comp; 9639 xmlXPathObjectPtr arg1, arg2; 9640 9641 CHECK_ERROR0; 9642 comp = ctxt->comp; 9643 switch (op->op) { 9644 case XPATH_OP_END: 9645 return (0); 9646 case XPATH_OP_UNION: 9647 total = 9648 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 9649 first); 9650 CHECK_ERROR0; 9651 if ((ctxt->value != NULL) 9652 && (ctxt->value->type == XPATH_NODESET) 9653 && (ctxt->value->nodesetval != NULL) 9654 && (ctxt->value->nodesetval->nodeNr >= 1)) { 9655 /* 9656 * limit tree traversing to first node in the result 9657 */ 9658 xmlXPathNodeSetSort(ctxt->value->nodesetval); 9659 *first = ctxt->value->nodesetval->nodeTab[0]; 9660 } 9661 cur = 9662 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 9663 first); 9664 CHECK_ERROR0; 9665 CHECK_TYPE0(XPATH_NODESET); 9666 arg2 = valuePop(ctxt); 9667 9668 CHECK_TYPE0(XPATH_NODESET); 9669 arg1 = valuePop(ctxt); 9670 9671 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 9672 arg2->nodesetval); 9673 valuePush(ctxt, arg1); 9674 xmlXPathFreeObject(arg2); 9675 /* optimizer */ 9676 if (total > cur) 9677 xmlXPathCompSwap(op); 9678 return (total + cur); 9679 case XPATH_OP_ROOT: 9680 xmlXPathRoot(ctxt); 9681 return (0); 9682 case XPATH_OP_NODE: 9683 if (op->ch1 != -1) 9684 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9685 CHECK_ERROR0; 9686 if (op->ch2 != -1) 9687 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9688 CHECK_ERROR0; 9689 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 9690 return (total); 9691 case XPATH_OP_RESET: 9692 if (op->ch1 != -1) 9693 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9694 CHECK_ERROR0; 9695 if (op->ch2 != -1) 9696 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9697 CHECK_ERROR0; 9698 ctxt->context->node = NULL; 9699 return (total); 9700 case XPATH_OP_COLLECT:{ 9701 if (op->ch1 == -1) 9702 return (total); 9703 9704 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9705 CHECK_ERROR0; 9706 9707 /* 9708 * Optimization for [n] selection where n is a number 9709 */ 9710 if ((op->ch2 != -1) && 9711 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && 9712 (comp->steps[op->ch2].ch1 == -1) && 9713 (comp->steps[op->ch2].ch2 != -1) && 9714 (comp->steps[comp->steps[op->ch2].ch2].op == 9715 XPATH_OP_VALUE)) { 9716 xmlXPathObjectPtr val; 9717 9718 val = comp->steps[comp->steps[op->ch2].ch2].value4; 9719 if ((val != NULL) && (val->type == XPATH_NUMBER)) { 9720 int indx = (int) val->floatval; 9721 9722 if (val->floatval == (float) indx) { 9723 xmlXPathNodeCollectAndTestNth(ctxt, op, indx, 9724 first, NULL); 9725 return (total); 9726 } 9727 } 9728 } 9729 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL); 9730 return (total); 9731 } 9732 case XPATH_OP_VALUE: 9733 valuePush(ctxt, 9734 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4)); 9735 return (0); 9736 case XPATH_OP_SORT: 9737 if (op->ch1 != -1) 9738 total += 9739 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 9740 first); 9741 CHECK_ERROR0; 9742 if ((ctxt->value != NULL) 9743 && (ctxt->value->type == XPATH_NODESET) 9744 && (ctxt->value->nodesetval != NULL)) 9745 xmlXPathNodeSetSort(ctxt->value->nodesetval); 9746 return (total); 9747 default: 9748 return (xmlXPathCompOpEval(ctxt, op)); 9749 } 9750} 9751 9752/** 9753 * xmlXPathCompOpEvalLast: 9754 * @ctxt: the XPath parser context with the compiled expression 9755 * @op: an XPath compiled operation 9756 * @last: the last elem found so far 9757 * 9758 * Evaluate the Precompiled XPath operation searching only the last 9759 * element in document order 9760 * 9761 * Returns the number of node traversed 9762 */ 9763static int 9764xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 9765 xmlNodePtr * last) 9766{ 9767 int total = 0, cur; 9768 xmlXPathCompExprPtr comp; 9769 xmlXPathObjectPtr arg1, arg2; 9770 9771 CHECK_ERROR0; 9772 comp = ctxt->comp; 9773 switch (op->op) { 9774 case XPATH_OP_END: 9775 return (0); 9776 case XPATH_OP_UNION: 9777 total = 9778 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 9779 CHECK_ERROR0; 9780 if ((ctxt->value != NULL) 9781 && (ctxt->value->type == XPATH_NODESET) 9782 && (ctxt->value->nodesetval != NULL) 9783 && (ctxt->value->nodesetval->nodeNr >= 1)) { 9784 /* 9785 * limit tree traversing to first node in the result 9786 */ 9787 xmlXPathNodeSetSort(ctxt->value->nodesetval); 9788 *last = 9789 ctxt->value->nodesetval->nodeTab[ctxt->value-> 9790 nodesetval->nodeNr - 9791 1]; 9792 } 9793 cur = 9794 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 9795 CHECK_ERROR0; 9796 if ((ctxt->value != NULL) 9797 && (ctxt->value->type == XPATH_NODESET) 9798 && (ctxt->value->nodesetval != NULL) 9799 && (ctxt->value->nodesetval->nodeNr >= 1)) { 9800 } 9801 CHECK_TYPE0(XPATH_NODESET); 9802 arg2 = valuePop(ctxt); 9803 9804 CHECK_TYPE0(XPATH_NODESET); 9805 arg1 = valuePop(ctxt); 9806 9807 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 9808 arg2->nodesetval); 9809 valuePush(ctxt, arg1); 9810 xmlXPathFreeObject(arg2); 9811 /* optimizer */ 9812 if (total > cur) 9813 xmlXPathCompSwap(op); 9814 return (total + cur); 9815 case XPATH_OP_ROOT: 9816 xmlXPathRoot(ctxt); 9817 return (0); 9818 case XPATH_OP_NODE: 9819 if (op->ch1 != -1) 9820 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9821 CHECK_ERROR0; 9822 if (op->ch2 != -1) 9823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9824 CHECK_ERROR0; 9825 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 9826 return (total); 9827 case XPATH_OP_RESET: 9828 if (op->ch1 != -1) 9829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9830 CHECK_ERROR0; 9831 if (op->ch2 != -1) 9832 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9833 CHECK_ERROR0; 9834 ctxt->context->node = NULL; 9835 return (total); 9836 case XPATH_OP_COLLECT:{ 9837 if (op->ch1 == -1) 9838 return (0); 9839 9840 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9841 CHECK_ERROR0; 9842 9843 /* 9844 * Optimization for [n] selection where n is a number 9845 */ 9846 if ((op->ch2 != -1) && 9847 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && 9848 (comp->steps[op->ch2].ch1 == -1) && 9849 (comp->steps[op->ch2].ch2 != -1) && 9850 (comp->steps[comp->steps[op->ch2].ch2].op == 9851 XPATH_OP_VALUE)) { 9852 xmlXPathObjectPtr val; 9853 9854 val = comp->steps[comp->steps[op->ch2].ch2].value4; 9855 if ((val != NULL) && (val->type == XPATH_NUMBER)) { 9856 int indx = (int) val->floatval; 9857 9858 if (val->floatval == (float) indx) { 9859 total += 9860 xmlXPathNodeCollectAndTestNth(ctxt, op, 9861 indx, NULL, 9862 last); 9863 return (total); 9864 } 9865 } 9866 } 9867 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last); 9868 return (total); 9869 } 9870 case XPATH_OP_VALUE: 9871 valuePush(ctxt, 9872 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4)); 9873 return (0); 9874 case XPATH_OP_SORT: 9875 if (op->ch1 != -1) 9876 total += 9877 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 9878 last); 9879 CHECK_ERROR0; 9880 if ((ctxt->value != NULL) 9881 && (ctxt->value->type == XPATH_NODESET) 9882 && (ctxt->value->nodesetval != NULL)) 9883 xmlXPathNodeSetSort(ctxt->value->nodesetval); 9884 return (total); 9885 default: 9886 return (xmlXPathCompOpEval(ctxt, op)); 9887 } 9888} 9889 9890/** 9891 * xmlXPathCompOpEval: 9892 * @ctxt: the XPath parser context with the compiled expression 9893 * @op: an XPath compiled operation 9894 * 9895 * Evaluate the Precompiled XPath operation 9896 * Returns the number of node traversed 9897 */ 9898static int 9899xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 9900{ 9901 int total = 0; 9902 int equal, ret; 9903 xmlXPathCompExprPtr comp; 9904 xmlXPathObjectPtr arg1, arg2; 9905 xmlNodePtr bak; 9906 xmlDocPtr bakd; 9907 int pp; 9908 int cs; 9909 9910 CHECK_ERROR0; 9911 comp = ctxt->comp; 9912 switch (op->op) { 9913 case XPATH_OP_END: 9914 return (0); 9915 case XPATH_OP_AND: 9916 bakd = ctxt->context->doc; 9917 bak = ctxt->context->node; 9918 pp = ctxt->context->proximityPosition; 9919 cs = ctxt->context->contextSize; 9920 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9921 CHECK_ERROR0; 9922 xmlXPathBooleanFunction(ctxt, 1); 9923 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 9924 return (total); 9925 arg2 = valuePop(ctxt); 9926 ctxt->context->doc = bakd; 9927 ctxt->context->node = bak; 9928 ctxt->context->proximityPosition = pp; 9929 ctxt->context->contextSize = cs; 9930 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9931 if (ctxt->error) { 9932 xmlXPathFreeObject(arg2); 9933 return(0); 9934 } 9935 xmlXPathBooleanFunction(ctxt, 1); 9936 arg1 = valuePop(ctxt); 9937 arg1->boolval &= arg2->boolval; 9938 valuePush(ctxt, arg1); 9939 xmlXPathFreeObject(arg2); 9940 return (total); 9941 case XPATH_OP_OR: 9942 bakd = ctxt->context->doc; 9943 bak = ctxt->context->node; 9944 pp = ctxt->context->proximityPosition; 9945 cs = ctxt->context->contextSize; 9946 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9947 CHECK_ERROR0; 9948 xmlXPathBooleanFunction(ctxt, 1); 9949 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 9950 return (total); 9951 arg2 = valuePop(ctxt); 9952 ctxt->context->doc = bakd; 9953 ctxt->context->node = bak; 9954 ctxt->context->proximityPosition = pp; 9955 ctxt->context->contextSize = cs; 9956 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9957 if (ctxt->error) { 9958 xmlXPathFreeObject(arg2); 9959 return(0); 9960 } 9961 xmlXPathBooleanFunction(ctxt, 1); 9962 arg1 = valuePop(ctxt); 9963 arg1->boolval |= arg2->boolval; 9964 valuePush(ctxt, arg1); 9965 xmlXPathFreeObject(arg2); 9966 return (total); 9967 case XPATH_OP_EQUAL: 9968 bakd = ctxt->context->doc; 9969 bak = ctxt->context->node; 9970 pp = ctxt->context->proximityPosition; 9971 cs = ctxt->context->contextSize; 9972 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9973 CHECK_ERROR0; 9974 ctxt->context->doc = bakd; 9975 ctxt->context->node = bak; 9976 ctxt->context->proximityPosition = pp; 9977 ctxt->context->contextSize = cs; 9978 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9979 CHECK_ERROR0; 9980 if (op->value) 9981 equal = xmlXPathEqualValues(ctxt); 9982 else 9983 equal = xmlXPathNotEqualValues(ctxt); 9984 valuePush(ctxt, xmlXPathNewBoolean(equal)); 9985 return (total); 9986 case XPATH_OP_CMP: 9987 bakd = ctxt->context->doc; 9988 bak = ctxt->context->node; 9989 pp = ctxt->context->proximityPosition; 9990 cs = ctxt->context->contextSize; 9991 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9992 CHECK_ERROR0; 9993 ctxt->context->doc = bakd; 9994 ctxt->context->node = bak; 9995 ctxt->context->proximityPosition = pp; 9996 ctxt->context->contextSize = cs; 9997 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9998 CHECK_ERROR0; 9999 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 10000 valuePush(ctxt, xmlXPathNewBoolean(ret)); 10001 return (total); 10002 case XPATH_OP_PLUS: 10003 bakd = ctxt->context->doc; 10004 bak = ctxt->context->node; 10005 pp = ctxt->context->proximityPosition; 10006 cs = ctxt->context->contextSize; 10007 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10008 CHECK_ERROR0; 10009 if (op->ch2 != -1) { 10010 ctxt->context->doc = bakd; 10011 ctxt->context->node = bak; 10012 ctxt->context->proximityPosition = pp; 10013 ctxt->context->contextSize = cs; 10014 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 10015 } 10016 CHECK_ERROR0; 10017 if (op->value == 0) 10018 xmlXPathSubValues(ctxt); 10019 else if (op->value == 1) 10020 xmlXPathAddValues(ctxt); 10021 else if (op->value == 2) 10022 xmlXPathValueFlipSign(ctxt); 10023 else if (op->value == 3) { 10024 CAST_TO_NUMBER; 10025 CHECK_TYPE0(XPATH_NUMBER); 10026 } 10027 return (total); 10028 case XPATH_OP_MULT: 10029 bakd = ctxt->context->doc; 10030 bak = ctxt->context->node; 10031 pp = ctxt->context->proximityPosition; 10032 cs = ctxt->context->contextSize; 10033 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10034 CHECK_ERROR0; 10035 ctxt->context->doc = bakd; 10036 ctxt->context->node = bak; 10037 ctxt->context->proximityPosition = pp; 10038 ctxt->context->contextSize = cs; 10039 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 10040 CHECK_ERROR0; 10041 if (op->value == 0) 10042 xmlXPathMultValues(ctxt); 10043 else if (op->value == 1) 10044 xmlXPathDivValues(ctxt); 10045 else if (op->value == 2) 10046 xmlXPathModValues(ctxt); 10047 return (total); 10048 case XPATH_OP_UNION: 10049 bakd = ctxt->context->doc; 10050 bak = ctxt->context->node; 10051 pp = ctxt->context->proximityPosition; 10052 cs = ctxt->context->contextSize; 10053 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10054 CHECK_ERROR0; 10055 ctxt->context->doc = bakd; 10056 ctxt->context->node = bak; 10057 ctxt->context->proximityPosition = pp; 10058 ctxt->context->contextSize = cs; 10059 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 10060 CHECK_ERROR0; 10061 CHECK_TYPE0(XPATH_NODESET); 10062 arg2 = valuePop(ctxt); 10063 10064 CHECK_TYPE0(XPATH_NODESET); 10065 arg1 = valuePop(ctxt); 10066 10067 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 10068 arg2->nodesetval); 10069 valuePush(ctxt, arg1); 10070 xmlXPathFreeObject(arg2); 10071 return (total); 10072 case XPATH_OP_ROOT: 10073 xmlXPathRoot(ctxt); 10074 return (total); 10075 case XPATH_OP_NODE: 10076 if (op->ch1 != -1) 10077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10078 CHECK_ERROR0; 10079 if (op->ch2 != -1) 10080 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 10081 CHECK_ERROR0; 10082 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 10083 return (total); 10084 case XPATH_OP_RESET: 10085 if (op->ch1 != -1) 10086 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10087 CHECK_ERROR0; 10088 if (op->ch2 != -1) 10089 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 10090 CHECK_ERROR0; 10091 ctxt->context->node = NULL; 10092 return (total); 10093 case XPATH_OP_COLLECT:{ 10094 if (op->ch1 == -1) 10095 return (total); 10096 10097 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10098 CHECK_ERROR0; 10099 10100 /* 10101 * Optimization for [n] selection where n is a number 10102 */ 10103 if ((op->ch2 != -1) && 10104 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && 10105 (comp->steps[op->ch2].ch1 == -1) && 10106 (comp->steps[op->ch2].ch2 != -1) && 10107 (comp->steps[comp->steps[op->ch2].ch2].op == 10108 XPATH_OP_VALUE)) { 10109 xmlXPathObjectPtr val; 10110 10111 val = comp->steps[comp->steps[op->ch2].ch2].value4; 10112 if ((val != NULL) && (val->type == XPATH_NUMBER)) { 10113 int indx = (int) val->floatval; 10114 10115 if (val->floatval == (float) indx) { 10116 total += 10117 xmlXPathNodeCollectAndTestNth(ctxt, op, 10118 indx, NULL, 10119 NULL); 10120 return (total); 10121 } 10122 } 10123 } 10124 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL); 10125 return (total); 10126 } 10127 case XPATH_OP_VALUE: 10128 valuePush(ctxt, 10129 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4)); 10130 return (total); 10131 case XPATH_OP_VARIABLE:{ 10132 xmlXPathObjectPtr val; 10133 10134 if (op->ch1 != -1) 10135 total += 10136 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10137 if (op->value5 == NULL) { 10138 val = xmlXPathVariableLookup(ctxt->context, op->value4); 10139 if (val == NULL) { 10140 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 10141 return(0); 10142 } 10143 valuePush(ctxt, val); 10144 } else { 10145 const xmlChar *URI; 10146 10147 URI = xmlXPathNsLookup(ctxt->context, op->value5); 10148 if (URI == NULL) { 10149 xmlGenericError(xmlGenericErrorContext, 10150 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 10151 op->value4, op->value5); 10152 return (total); 10153 } 10154 val = xmlXPathVariableLookupNS(ctxt->context, 10155 op->value4, URI); 10156 if (val == NULL) { 10157 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 10158 return(0); 10159 } 10160 valuePush(ctxt, val); 10161 } 10162 return (total); 10163 } 10164 case XPATH_OP_FUNCTION:{ 10165 xmlXPathFunction func; 10166 const xmlChar *oldFunc, *oldFuncURI; 10167 int i; 10168 10169 if (op->ch1 != -1) 10170 total += 10171 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10172 if (ctxt->valueNr < op->value) { 10173 xmlGenericError(xmlGenericErrorContext, 10174 "xmlXPathCompOpEval: parameter error\n"); 10175 ctxt->error = XPATH_INVALID_OPERAND; 10176 return (total); 10177 } 10178 for (i = 0; i < op->value; i++) 10179 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 10180 xmlGenericError(xmlGenericErrorContext, 10181 "xmlXPathCompOpEval: parameter error\n"); 10182 ctxt->error = XPATH_INVALID_OPERAND; 10183 return (total); 10184 } 10185 if (op->cache != NULL) 10186 func = (xmlXPathFunction) op->cache; 10187 else { 10188 const xmlChar *URI = NULL; 10189 10190 if (op->value5 == NULL) 10191 func = 10192 xmlXPathFunctionLookup(ctxt->context, 10193 op->value4); 10194 else { 10195 URI = xmlXPathNsLookup(ctxt->context, op->value5); 10196 if (URI == NULL) { 10197 xmlGenericError(xmlGenericErrorContext, 10198 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 10199 op->value4, op->value5); 10200 return (total); 10201 } 10202 func = xmlXPathFunctionLookupNS(ctxt->context, 10203 op->value4, URI); 10204 } 10205 if (func == NULL) { 10206 xmlGenericError(xmlGenericErrorContext, 10207 "xmlXPathCompOpEval: function %s not found\n", 10208 op->value4); 10209 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 10210 } 10211 op->cache = (void *) func; 10212 op->cacheURI = (void *) URI; 10213 } 10214 oldFunc = ctxt->context->function; 10215 oldFuncURI = ctxt->context->functionURI; 10216 ctxt->context->function = op->value4; 10217 ctxt->context->functionURI = op->cacheURI; 10218 func(ctxt, op->value); 10219 ctxt->context->function = oldFunc; 10220 ctxt->context->functionURI = oldFuncURI; 10221 return (total); 10222 } 10223 case XPATH_OP_ARG: 10224 bakd = ctxt->context->doc; 10225 bak = ctxt->context->node; 10226 if (op->ch1 != -1) 10227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10228 ctxt->context->doc = bakd; 10229 ctxt->context->node = bak; 10230 CHECK_ERROR0; 10231 if (op->ch2 != -1) 10232 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 10233 ctxt->context->doc = bakd; 10234 ctxt->context->node = bak; 10235 CHECK_ERROR0; 10236 return (total); 10237 case XPATH_OP_PREDICATE: 10238 case XPATH_OP_FILTER:{ 10239 xmlXPathObjectPtr res; 10240 xmlXPathObjectPtr obj, tmp; 10241 xmlNodeSetPtr newset = NULL; 10242 xmlNodeSetPtr oldset; 10243 xmlNodePtr oldnode; 10244 int i; 10245 10246 /* 10247 * Optimization for ()[1] selection i.e. the first elem 10248 */ 10249 if ((op->ch1 != -1) && (op->ch2 != -1) && 10250 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 10251 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { 10252 xmlXPathObjectPtr val; 10253 10254 val = comp->steps[op->ch2].value4; 10255 if ((val != NULL) && (val->type == XPATH_NUMBER) && 10256 (val->floatval == 1.0)) { 10257 xmlNodePtr first = NULL; 10258 10259 total += 10260 xmlXPathCompOpEvalFirst(ctxt, 10261 &comp->steps[op->ch1], 10262 &first); 10263 CHECK_ERROR0; 10264 /* 10265 * The nodeset should be in document order, 10266 * Keep only the first value 10267 */ 10268 if ((ctxt->value != NULL) && 10269 (ctxt->value->type == XPATH_NODESET) && 10270 (ctxt->value->nodesetval != NULL) && 10271 (ctxt->value->nodesetval->nodeNr > 1)) 10272 ctxt->value->nodesetval->nodeNr = 1; 10273 return (total); 10274 } 10275 } 10276 /* 10277 * Optimization for ()[last()] selection i.e. the last elem 10278 */ 10279 if ((op->ch1 != -1) && (op->ch2 != -1) && 10280 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 10281 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 10282 int f = comp->steps[op->ch2].ch1; 10283 10284 if ((f != -1) && 10285 (comp->steps[f].op == XPATH_OP_FUNCTION) && 10286 (comp->steps[f].value5 == NULL) && 10287 (comp->steps[f].value == 0) && 10288 (comp->steps[f].value4 != NULL) && 10289 (xmlStrEqual 10290 (comp->steps[f].value4, BAD_CAST "last"))) { 10291 xmlNodePtr last = NULL; 10292 10293 total += 10294 xmlXPathCompOpEvalLast(ctxt, 10295 &comp->steps[op->ch1], 10296 &last); 10297 CHECK_ERROR0; 10298 /* 10299 * The nodeset should be in document order, 10300 * Keep only the last value 10301 */ 10302 if ((ctxt->value != NULL) && 10303 (ctxt->value->type == XPATH_NODESET) && 10304 (ctxt->value->nodesetval != NULL) && 10305 (ctxt->value->nodesetval->nodeTab != NULL) && 10306 (ctxt->value->nodesetval->nodeNr > 1)) { 10307 ctxt->value->nodesetval->nodeTab[0] = 10308 ctxt->value->nodesetval->nodeTab[ctxt-> 10309 value-> 10310 nodesetval-> 10311 nodeNr - 10312 1]; 10313 ctxt->value->nodesetval->nodeNr = 1; 10314 } 10315 return (total); 10316 } 10317 } 10318 10319 if (op->ch1 != -1) 10320 total += 10321 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10322 CHECK_ERROR0; 10323 if (op->ch2 == -1) 10324 return (total); 10325 if (ctxt->value == NULL) 10326 return (total); 10327 10328 oldnode = ctxt->context->node; 10329 10330#ifdef LIBXML_XPTR_ENABLED 10331 /* 10332 * Hum are we filtering the result of an XPointer expression 10333 */ 10334 if (ctxt->value->type == XPATH_LOCATIONSET) { 10335 xmlLocationSetPtr newlocset = NULL; 10336 xmlLocationSetPtr oldlocset; 10337 10338 /* 10339 * Extract the old locset, and then evaluate the result of the 10340 * expression for all the element in the locset. use it to grow 10341 * up a new locset. 10342 */ 10343 CHECK_TYPE0(XPATH_LOCATIONSET); 10344 obj = valuePop(ctxt); 10345 oldlocset = obj->user; 10346 ctxt->context->node = NULL; 10347 10348 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 10349 ctxt->context->contextSize = 0; 10350 ctxt->context->proximityPosition = 0; 10351 if (op->ch2 != -1) 10352 total += 10353 xmlXPathCompOpEval(ctxt, 10354 &comp->steps[op->ch2]); 10355 res = valuePop(ctxt); 10356 if (res != NULL) 10357 xmlXPathFreeObject(res); 10358 valuePush(ctxt, obj); 10359 CHECK_ERROR0; 10360 return (total); 10361 } 10362 newlocset = xmlXPtrLocationSetCreate(NULL); 10363 10364 for (i = 0; i < oldlocset->locNr; i++) { 10365 /* 10366 * Run the evaluation with a node list made of a 10367 * single item in the nodelocset. 10368 */ 10369 ctxt->context->node = oldlocset->locTab[i]->user; 10370 tmp = xmlXPathNewNodeSet(ctxt->context->node); 10371 valuePush(ctxt, tmp); 10372 ctxt->context->contextSize = oldlocset->locNr; 10373 ctxt->context->proximityPosition = i + 1; 10374 10375 if (op->ch2 != -1) 10376 total += 10377 xmlXPathCompOpEval(ctxt, 10378 &comp->steps[op->ch2]); 10379 CHECK_ERROR0; 10380 10381 /* 10382 * The result of the evaluation need to be tested to 10383 * decided whether the filter succeeded or not 10384 */ 10385 res = valuePop(ctxt); 10386 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 10387 xmlXPtrLocationSetAdd(newlocset, 10388 xmlXPathObjectCopy 10389 (oldlocset->locTab[i])); 10390 } 10391 10392 /* 10393 * Cleanup 10394 */ 10395 if (res != NULL) 10396 xmlXPathFreeObject(res); 10397 if (ctxt->value == tmp) { 10398 res = valuePop(ctxt); 10399 xmlXPathFreeObject(res); 10400 } 10401 10402 ctxt->context->node = NULL; 10403 } 10404 10405 /* 10406 * The result is used as the new evaluation locset. 10407 */ 10408 xmlXPathFreeObject(obj); 10409 ctxt->context->node = NULL; 10410 ctxt->context->contextSize = -1; 10411 ctxt->context->proximityPosition = -1; 10412 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 10413 ctxt->context->node = oldnode; 10414 return (total); 10415 } 10416#endif /* LIBXML_XPTR_ENABLED */ 10417 10418 /* 10419 * Extract the old set, and then evaluate the result of the 10420 * expression for all the element in the set. use it to grow 10421 * up a new set. 10422 */ 10423 CHECK_TYPE0(XPATH_NODESET); 10424 obj = valuePop(ctxt); 10425 oldset = obj->nodesetval; 10426 10427 oldnode = ctxt->context->node; 10428 ctxt->context->node = NULL; 10429 10430 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 10431 ctxt->context->contextSize = 0; 10432 ctxt->context->proximityPosition = 0; 10433 if (op->ch2 != -1) 10434 total += 10435 xmlXPathCompOpEval(ctxt, 10436 &comp->steps[op->ch2]); 10437 CHECK_ERROR0; 10438 res = valuePop(ctxt); 10439 if (res != NULL) 10440 xmlXPathFreeObject(res); 10441 valuePush(ctxt, obj); 10442 ctxt->context->node = oldnode; 10443 CHECK_ERROR0; 10444 } else { 10445 /* 10446 * Initialize the new set. 10447 */ 10448 newset = xmlXPathNodeSetCreate(NULL); 10449 10450 for (i = 0; i < oldset->nodeNr; i++) { 10451 /* 10452 * Run the evaluation with a node list made of 10453 * a single item in the nodeset. 10454 */ 10455 ctxt->context->node = oldset->nodeTab[i]; 10456 tmp = xmlXPathNewNodeSet(ctxt->context->node); 10457 valuePush(ctxt, tmp); 10458 ctxt->context->contextSize = oldset->nodeNr; 10459 ctxt->context->proximityPosition = i + 1; 10460 10461 if (op->ch2 != -1) 10462 total += 10463 xmlXPathCompOpEval(ctxt, 10464 &comp->steps[op->ch2]); 10465 CHECK_ERROR0; 10466 10467 /* 10468 * The result of the evaluation need to be tested to 10469 * decided whether the filter succeeded or not 10470 */ 10471 res = valuePop(ctxt); 10472 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 10473 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 10474 } 10475 10476 /* 10477 * Cleanup 10478 */ 10479 if (res != NULL) 10480 xmlXPathFreeObject(res); 10481 if (ctxt->value == tmp) { 10482 res = valuePop(ctxt); 10483 xmlXPathFreeObject(res); 10484 } 10485 10486 ctxt->context->node = NULL; 10487 } 10488 10489 /* 10490 * The result is used as the new evaluation set. 10491 */ 10492 xmlXPathFreeObject(obj); 10493 ctxt->context->node = NULL; 10494 ctxt->context->contextSize = -1; 10495 ctxt->context->proximityPosition = -1; 10496 valuePush(ctxt, xmlXPathWrapNodeSet(newset)); 10497 } 10498 ctxt->context->node = oldnode; 10499 return (total); 10500 } 10501 case XPATH_OP_SORT: 10502 if (op->ch1 != -1) 10503 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10504 CHECK_ERROR0; 10505 if ((ctxt->value != NULL) && 10506 (ctxt->value->type == XPATH_NODESET) && 10507 (ctxt->value->nodesetval != NULL)) 10508 xmlXPathNodeSetSort(ctxt->value->nodesetval); 10509 return (total); 10510#ifdef LIBXML_XPTR_ENABLED 10511 case XPATH_OP_RANGETO:{ 10512 xmlXPathObjectPtr range; 10513 xmlXPathObjectPtr res, obj; 10514 xmlXPathObjectPtr tmp; 10515 xmlLocationSetPtr newset = NULL; 10516 xmlNodeSetPtr oldset; 10517 int i; 10518 10519 if (op->ch1 != -1) 10520 total += 10521 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10522 if (op->ch2 == -1) 10523 return (total); 10524 10525 CHECK_TYPE0(XPATH_NODESET); 10526 obj = valuePop(ctxt); 10527 oldset = obj->nodesetval; 10528 ctxt->context->node = NULL; 10529 10530 newset = xmlXPtrLocationSetCreate(NULL); 10531 10532 if (oldset != NULL) { 10533 for (i = 0; i < oldset->nodeNr; i++) { 10534 /* 10535 * Run the evaluation with a node list made of a single item 10536 * in the nodeset. 10537 */ 10538 ctxt->context->node = oldset->nodeTab[i]; 10539 tmp = xmlXPathNewNodeSet(ctxt->context->node); 10540 valuePush(ctxt, tmp); 10541 10542 if (op->ch2 != -1) 10543 total += 10544 xmlXPathCompOpEval(ctxt, 10545 &comp->steps[op->ch2]); 10546 CHECK_ERROR0; 10547 10548 /* 10549 * The result of the evaluation need to be tested to 10550 * decided whether the filter succeeded or not 10551 */ 10552 res = valuePop(ctxt); 10553 range = 10554 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 10555 res); 10556 if (range != NULL) { 10557 xmlXPtrLocationSetAdd(newset, range); 10558 } 10559 10560 /* 10561 * Cleanup 10562 */ 10563 if (res != NULL) 10564 xmlXPathFreeObject(res); 10565 if (ctxt->value == tmp) { 10566 res = valuePop(ctxt); 10567 xmlXPathFreeObject(res); 10568 } 10569 10570 ctxt->context->node = NULL; 10571 } 10572 } 10573 10574 /* 10575 * The result is used as the new evaluation set. 10576 */ 10577 xmlXPathFreeObject(obj); 10578 ctxt->context->node = NULL; 10579 ctxt->context->contextSize = -1; 10580 ctxt->context->proximityPosition = -1; 10581 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 10582 return (total); 10583 } 10584#endif /* LIBXML_XPTR_ENABLED */ 10585 } 10586 xmlGenericError(xmlGenericErrorContext, 10587 "XPath: unknown precompiled operation %d\n", op->op); 10588 return (total); 10589} 10590 10591/** 10592 * xmlXPathRunEval: 10593 * @ctxt: the XPath parser context with the compiled expression 10594 * 10595 * Evaluate the Precompiled XPath expression in the given context. 10596 */ 10597static void 10598xmlXPathRunEval(xmlXPathParserContextPtr ctxt) { 10599 xmlXPathCompExprPtr comp; 10600 10601 if ((ctxt == NULL) || (ctxt->comp == NULL)) 10602 return; 10603 10604 if (ctxt->valueTab == NULL) { 10605 /* Allocate the value stack */ 10606 ctxt->valueTab = (xmlXPathObjectPtr *) 10607 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 10608 if (ctxt->valueTab == NULL) { 10609 xmlFree(ctxt); 10610 } 10611 ctxt->valueNr = 0; 10612 ctxt->valueMax = 10; 10613 ctxt->value = NULL; 10614 } 10615 comp = ctxt->comp; 10616 if(comp->last < 0) { 10617 xmlGenericError(xmlGenericErrorContext, 10618 "xmlXPathRunEval: last is less than zero\n"); 10619 return; 10620 } 10621 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 10622} 10623 10624/************************************************************************ 10625 * * 10626 * Public interfaces * 10627 * * 10628 ************************************************************************/ 10629 10630/** 10631 * xmlXPathEvalPredicate: 10632 * @ctxt: the XPath context 10633 * @res: the Predicate Expression evaluation result 10634 * 10635 * Evaluate a predicate result for the current node. 10636 * A PredicateExpr is evaluated by evaluating the Expr and converting 10637 * the result to a boolean. If the result is a number, the result will 10638 * be converted to true if the number is equal to the position of the 10639 * context node in the context node list (as returned by the position 10640 * function) and will be converted to false otherwise; if the result 10641 * is not a number, then the result will be converted as if by a call 10642 * to the boolean function. 10643 * 10644 * Returns 1 if predicate is true, 0 otherwise 10645 */ 10646int 10647xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 10648 if (res == NULL) return(0); 10649 switch (res->type) { 10650 case XPATH_BOOLEAN: 10651 return(res->boolval); 10652 case XPATH_NUMBER: 10653 return(res->floatval == ctxt->proximityPosition); 10654 case XPATH_NODESET: 10655 case XPATH_XSLT_TREE: 10656 if (res->nodesetval == NULL) 10657 return(0); 10658 return(res->nodesetval->nodeNr != 0); 10659 case XPATH_STRING: 10660 return((res->stringval != NULL) && 10661 (xmlStrlen(res->stringval) != 0)); 10662 default: 10663 STRANGE 10664 } 10665 return(0); 10666} 10667 10668/** 10669 * xmlXPathEvaluatePredicateResult: 10670 * @ctxt: the XPath Parser context 10671 * @res: the Predicate Expression evaluation result 10672 * 10673 * Evaluate a predicate result for the current node. 10674 * A PredicateExpr is evaluated by evaluating the Expr and converting 10675 * the result to a boolean. If the result is a number, the result will 10676 * be converted to true if the number is equal to the position of the 10677 * context node in the context node list (as returned by the position 10678 * function) and will be converted to false otherwise; if the result 10679 * is not a number, then the result will be converted as if by a call 10680 * to the boolean function. 10681 * 10682 * Returns 1 if predicate is true, 0 otherwise 10683 */ 10684int 10685xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 10686 xmlXPathObjectPtr res) { 10687 if (res == NULL) return(0); 10688 switch (res->type) { 10689 case XPATH_BOOLEAN: 10690 return(res->boolval); 10691 case XPATH_NUMBER: 10692 return(res->floatval == ctxt->context->proximityPosition); 10693 case XPATH_NODESET: 10694 case XPATH_XSLT_TREE: 10695 if (res->nodesetval == NULL) 10696 return(0); 10697 return(res->nodesetval->nodeNr != 0); 10698 case XPATH_STRING: 10699 return((res->stringval != NULL) && 10700 (xmlStrlen(res->stringval) != 0)); 10701 default: 10702 STRANGE 10703 } 10704 return(0); 10705} 10706 10707/** 10708 * xmlXPathCompile: 10709 * @str: the XPath expression 10710 * 10711 * Compile an XPath expression 10712 * 10713 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 10714 * the caller has to free the object. 10715 */ 10716xmlXPathCompExprPtr 10717xmlXPathCompile(const xmlChar *str) { 10718 xmlXPathParserContextPtr ctxt; 10719 xmlXPathCompExprPtr comp; 10720 10721 xmlXPathInit(); 10722 10723 ctxt = xmlXPathNewParserContext(str, NULL); 10724 xmlXPathCompileExpr(ctxt); 10725 10726 if (*ctxt->cur != 0) { 10727 /* 10728 * aleksey: in some cases this line prints *second* error message 10729 * (see bug #78858) and probably this should be fixed. 10730 * However, we are not sure that all error messages are printed 10731 * out in other places. It's not critical so we leave it as-is for now 10732 */ 10733 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 10734 comp = NULL; 10735 } else { 10736 comp = ctxt->comp; 10737 ctxt->comp = NULL; 10738 } 10739 xmlXPathFreeParserContext(ctxt); 10740 if (comp != NULL) { 10741 comp->expr = xmlStrdup(str); 10742#ifdef DEBUG_EVAL_COUNTS 10743 comp->string = xmlStrdup(str); 10744 comp->nb = 0; 10745#endif 10746 } 10747 return(comp); 10748} 10749 10750/** 10751 * xmlXPathCompiledEval: 10752 * @comp: the compiled XPath expression 10753 * @ctx: the XPath context 10754 * 10755 * Evaluate the Precompiled XPath expression in the given context. 10756 * 10757 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 10758 * the caller has to free the object. 10759 */ 10760xmlXPathObjectPtr 10761xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) { 10762 xmlXPathParserContextPtr ctxt; 10763 xmlXPathObjectPtr res, tmp, init = NULL; 10764 int stack = 0; 10765#ifndef LIBXML_THREAD_ENABLED 10766 static int reentance = 0; 10767#endif 10768 10769 if ((comp == NULL) || (ctx == NULL)) 10770 return(NULL); 10771 xmlXPathInit(); 10772 10773 CHECK_CONTEXT(ctx) 10774 10775#ifndef LIBXML_THREAD_ENABLED 10776 reentance++; 10777 if (reentance > 1) 10778 xmlXPathDisableOptimizer = 1; 10779#endif 10780 10781#ifdef DEBUG_EVAL_COUNTS 10782 comp->nb++; 10783 if ((comp->string != NULL) && (comp->nb > 100)) { 10784 fprintf(stderr, "100 x %s\n", comp->string); 10785 comp->nb = 0; 10786 } 10787#endif 10788 ctxt = xmlXPathCompParserContext(comp, ctx); 10789 xmlXPathRunEval(ctxt); 10790 10791 if (ctxt->value == NULL) { 10792 xmlGenericError(xmlGenericErrorContext, 10793 "xmlXPathCompiledEval: evaluation failed\n"); 10794 res = NULL; 10795 } else { 10796 res = valuePop(ctxt); 10797 } 10798 10799 10800 do { 10801 tmp = valuePop(ctxt); 10802 if (tmp != NULL) { 10803 if (tmp != init) 10804 stack++; 10805 xmlXPathFreeObject(tmp); 10806 } 10807 } while (tmp != NULL); 10808 if ((stack != 0) && (res != NULL)) { 10809 xmlGenericError(xmlGenericErrorContext, 10810 "xmlXPathCompiledEval: %d object left on the stack\n", 10811 stack); 10812 } 10813 if (ctxt->error != XPATH_EXPRESSION_OK) { 10814 xmlXPathFreeObject(res); 10815 res = NULL; 10816 } 10817 10818 10819 ctxt->comp = NULL; 10820 xmlXPathFreeParserContext(ctxt); 10821#ifndef LIBXML_THREAD_ENABLED 10822 reentance--; 10823#endif 10824 return(res); 10825} 10826 10827/** 10828 * xmlXPathEvalExpr: 10829 * @ctxt: the XPath Parser context 10830 * 10831 * Parse and evaluate an XPath expression in the given context, 10832 * then push the result on the context stack 10833 */ 10834void 10835xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 10836 xmlXPathCompileExpr(ctxt); 10837 CHECK_ERROR; 10838 xmlXPathRunEval(ctxt); 10839} 10840 10841/** 10842 * xmlXPathEval: 10843 * @str: the XPath expression 10844 * @ctx: the XPath context 10845 * 10846 * Evaluate the XPath Location Path in the given context. 10847 * 10848 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 10849 * the caller has to free the object. 10850 */ 10851xmlXPathObjectPtr 10852xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 10853 xmlXPathParserContextPtr ctxt; 10854 xmlXPathObjectPtr res, tmp, init = NULL; 10855 int stack = 0; 10856 10857 xmlXPathInit(); 10858 10859 CHECK_CONTEXT(ctx) 10860 10861 ctxt = xmlXPathNewParserContext(str, ctx); 10862 xmlXPathEvalExpr(ctxt); 10863 10864 if (ctxt->value == NULL) { 10865 xmlGenericError(xmlGenericErrorContext, 10866 "xmlXPathEval: evaluation failed\n"); 10867 res = NULL; 10868 } else if (*ctxt->cur != 0) { 10869 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 10870 res = NULL; 10871 } else { 10872 res = valuePop(ctxt); 10873 } 10874 10875 do { 10876 tmp = valuePop(ctxt); 10877 if (tmp != NULL) { 10878 if (tmp != init) 10879 stack++; 10880 xmlXPathFreeObject(tmp); 10881 } 10882 } while (tmp != NULL); 10883 if ((stack != 0) && (res != NULL)) { 10884 xmlGenericError(xmlGenericErrorContext, 10885 "xmlXPathEval: %d object left on the stack\n", 10886 stack); 10887 } 10888 if (ctxt->error != XPATH_EXPRESSION_OK) { 10889 xmlXPathFreeObject(res); 10890 res = NULL; 10891 } 10892 10893 xmlXPathFreeParserContext(ctxt); 10894 return(res); 10895} 10896 10897/** 10898 * xmlXPathEvalExpression: 10899 * @str: the XPath expression 10900 * @ctxt: the XPath context 10901 * 10902 * Evaluate the XPath expression in the given context. 10903 * 10904 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 10905 * the caller has to free the object. 10906 */ 10907xmlXPathObjectPtr 10908xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 10909 xmlXPathParserContextPtr pctxt; 10910 xmlXPathObjectPtr res, tmp; 10911 int stack = 0; 10912 10913 xmlXPathInit(); 10914 10915 CHECK_CONTEXT(ctxt) 10916 10917 pctxt = xmlXPathNewParserContext(str, ctxt); 10918 xmlXPathEvalExpr(pctxt); 10919 10920 if (*pctxt->cur != 0) { 10921 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 10922 res = NULL; 10923 } else { 10924 res = valuePop(pctxt); 10925 } 10926 do { 10927 tmp = valuePop(pctxt); 10928 if (tmp != NULL) { 10929 xmlXPathFreeObject(tmp); 10930 stack++; 10931 } 10932 } while (tmp != NULL); 10933 if ((stack != 0) && (res != NULL)) { 10934 xmlGenericError(xmlGenericErrorContext, 10935 "xmlXPathEvalExpression: %d object left on the stack\n", 10936 stack); 10937 } 10938 xmlXPathFreeParserContext(pctxt); 10939 return(res); 10940} 10941 10942/************************************************************************ 10943 * * 10944 * Extra functions not pertaining to the XPath spec * 10945 * * 10946 ************************************************************************/ 10947/** 10948 * xmlXPathEscapeUriFunction: 10949 * @ctxt: the XPath Parser context 10950 * @nargs: the number of arguments 10951 * 10952 * Implement the escape-uri() XPath function 10953 * string escape-uri(string $str, bool $escape-reserved) 10954 * 10955 * This function applies the URI escaping rules defined in section 2 of [RFC 10956 * 2396] to the string supplied as $uri-part, which typically represents all 10957 * or part of a URI. The effect of the function is to replace any special 10958 * character in the string by an escape sequence of the form %xx%yy..., 10959 * where xxyy... is the hexadecimal representation of the octets used to 10960 * represent the character in UTF-8. 10961 * 10962 * The set of characters that are escaped depends on the setting of the 10963 * boolean argument $escape-reserved. 10964 * 10965 * If $escape-reserved is true, all characters are escaped other than lower 10966 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 10967 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 10968 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 10969 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 10970 * A-F). 10971 * 10972 * If $escape-reserved is false, the behavior differs in that characters 10973 * referred to in [RFC 2396] as reserved characters are not escaped. These 10974 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 10975 * 10976 * [RFC 2396] does not define whether escaped URIs should use lower case or 10977 * upper case for hexadecimal digits. To ensure that escaped URIs can be 10978 * compared using string comparison functions, this function must always use 10979 * the upper-case letters A-F. 10980 * 10981 * Generally, $escape-reserved should be set to true when escaping a string 10982 * that is to form a single part of a URI, and to false when escaping an 10983 * entire URI or URI reference. 10984 * 10985 * In the case of non-ascii characters, the string is encoded according to 10986 * utf-8 and then converted according to RFC 2396. 10987 * 10988 * Examples 10989 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 10990 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 10991 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 10992 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 10993 * 10994 */ 10995static void 10996xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 10997 xmlXPathObjectPtr str; 10998 int escape_reserved; 10999 xmlBufferPtr target; 11000 xmlChar *cptr; 11001 xmlChar escape[4]; 11002 11003 CHECK_ARITY(2); 11004 11005 escape_reserved = xmlXPathPopBoolean(ctxt); 11006 11007 CAST_TO_STRING; 11008 str = valuePop(ctxt); 11009 11010 target = xmlBufferCreate(); 11011 11012 escape[0] = '%'; 11013 escape[3] = 0; 11014 11015 if (target) { 11016 for (cptr = str->stringval; *cptr; cptr++) { 11017 if ((*cptr >= 'A' && *cptr <= 'Z') || 11018 (*cptr >= 'a' && *cptr <= 'z') || 11019 (*cptr >= '0' && *cptr <= '9') || 11020 *cptr == '-' || *cptr == '_' || *cptr == '.' || 11021 *cptr == '!' || *cptr == '~' || *cptr == '*' || 11022 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 11023 (*cptr == '%' && 11024 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 11025 (cptr[1] >= 'a' && cptr[1] <= 'f') || 11026 (cptr[1] >= '0' && cptr[1] <= '9')) && 11027 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 11028 (cptr[2] >= 'a' && cptr[2] <= 'f') || 11029 (cptr[2] >= '0' && cptr[2] <= '9'))) || 11030 (!escape_reserved && 11031 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 11032 *cptr == ':' || *cptr == '@' || *cptr == '&' || 11033 *cptr == '=' || *cptr == '+' || *cptr == '$' || 11034 *cptr == ','))) { 11035 xmlBufferAdd(target, cptr, 1); 11036 } else { 11037 if ((*cptr >> 4) < 10) 11038 escape[1] = '0' + (*cptr >> 4); 11039 else 11040 escape[1] = 'A' - 10 + (*cptr >> 4); 11041 if ((*cptr & 0xF) < 10) 11042 escape[2] = '0' + (*cptr & 0xF); 11043 else 11044 escape[2] = 'A' - 10 + (*cptr & 0xF); 11045 11046 xmlBufferAdd(target, &escape[0], 3); 11047 } 11048 } 11049 } 11050 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); 11051 xmlBufferFree(target); 11052 xmlXPathFreeObject(str); 11053} 11054 11055/** 11056 * xmlXPathRegisterAllFunctions: 11057 * @ctxt: the XPath context 11058 * 11059 * Registers all default XPath functions in this context 11060 */ 11061void 11062xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 11063{ 11064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 11065 xmlXPathBooleanFunction); 11066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 11067 xmlXPathCeilingFunction); 11068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 11069 xmlXPathCountFunction); 11070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 11071 xmlXPathConcatFunction); 11072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 11073 xmlXPathContainsFunction); 11074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 11075 xmlXPathIdFunction); 11076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 11077 xmlXPathFalseFunction); 11078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 11079 xmlXPathFloorFunction); 11080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 11081 xmlXPathLastFunction); 11082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 11083 xmlXPathLangFunction); 11084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 11085 xmlXPathLocalNameFunction); 11086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 11087 xmlXPathNotFunction); 11088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 11089 xmlXPathNameFunction); 11090 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 11091 xmlXPathNamespaceURIFunction); 11092 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 11093 xmlXPathNormalizeFunction); 11094 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 11095 xmlXPathNumberFunction); 11096 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 11097 xmlXPathPositionFunction); 11098 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 11099 xmlXPathRoundFunction); 11100 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 11101 xmlXPathStringFunction); 11102 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 11103 xmlXPathStringLengthFunction); 11104 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 11105 xmlXPathStartsWithFunction); 11106 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 11107 xmlXPathSubstringFunction); 11108 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 11109 xmlXPathSubstringBeforeFunction); 11110 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 11111 xmlXPathSubstringAfterFunction); 11112 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 11113 xmlXPathSumFunction); 11114 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 11115 xmlXPathTrueFunction); 11116 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 11117 xmlXPathTranslateFunction); 11118 11119 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 11120 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 11121 xmlXPathEscapeUriFunction); 11122} 11123 11124#endif /* LIBXML_XPATH_ENABLED */ 11125