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 *f 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#ifdef LIBXML_PATTERN_ENABLED 55#include <libxml/pattern.h> 56#endif 57 58#ifdef LIBXML_PATTERN_ENABLED 59#define XPATH_STREAMING 60#endif 61 62#define TODO \ 63 xmlGenericError(xmlGenericErrorContext, \ 64 "Unimplemented block at %s:%d\n", \ 65 __FILE__, __LINE__); 66 67/* 68* XP_OPTIMIZED_NON_ELEM_COMPARISON: 69* If defined, this will use xmlXPathCmpNodesExt() instead of 70* xmlXPathCmpNodes(). The new function is optimized comparison of 71* non-element nodes; actually it will speed up comparison only if 72* xmlXPathOrderDocElems() was called in order to index the elements of 73* a tree in document order; Libxslt does such an indexing, thus it will 74* benefit from this optimization. 75*/ 76#define XP_OPTIMIZED_NON_ELEM_COMPARISON 77 78/* 79* XP_OPTIMIZED_FILTER_FIRST: 80* If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 81* in a way, that it stop evaluation at the first node. 82*/ 83#define XP_OPTIMIZED_FILTER_FIRST 84 85/* 86* XP_DEBUG_OBJ_USAGE: 87* Internal flag to enable tracking of how much XPath objects have been 88* created. 89*/ 90/* #define XP_DEBUG_OBJ_USAGE */ 91 92/* 93 * TODO: 94 * There are a few spots where some tests are done which depend upon ascii 95 * data. These should be enhanced for full UTF8 support (see particularly 96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 97 */ 98 99#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 100 101/************************************************************************ 102 * * 103 * Floating point stuff * 104 * * 105 ************************************************************************/ 106 107#ifndef TRIO_REPLACE_STDIO 108#define TRIO_PUBLIC static 109#endif 110#include "trionan.c" 111 112/* 113 * The lack of portability of this section of the libc is annoying ! 114 */ 115double xmlXPathNAN = 0; 116double xmlXPathPINF = 1; 117double xmlXPathNINF = -1; 118static double xmlXPathNZERO = 0; /* not exported from headers */ 119static int xmlXPathInitialized = 0; 120 121/** 122 * xmlXPathInit: 123 * 124 * Initialize the XPath environment 125 */ 126void 127xmlXPathInit(void) { 128 if (xmlXPathInitialized) return; 129 130 xmlXPathPINF = trio_pinf(); 131 xmlXPathNINF = trio_ninf(); 132 xmlXPathNAN = trio_nan(); 133 xmlXPathNZERO = trio_nzero(); 134 135 xmlXPathInitialized = 1; 136} 137 138/** 139 * xmlXPathIsNaN: 140 * @val: a double value 141 * 142 * Provides a portable isnan() function to detect whether a double 143 * is a NotaNumber. Based on trio code 144 * http://sourceforge.net/projects/ctrio/ 145 * 146 * Returns 1 if the value is a NaN, 0 otherwise 147 */ 148int 149xmlXPathIsNaN(double val) { 150 return(trio_isnan(val)); 151} 152 153/** 154 * xmlXPathIsInf: 155 * @val: a double value 156 * 157 * Provides a portable isinf() function to detect whether a double 158 * is a +Infinite or -Infinite. Based on trio code 159 * http://sourceforge.net/projects/ctrio/ 160 * 161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise 162 */ 163int 164xmlXPathIsInf(double val) { 165 return(trio_isinf(val)); 166} 167 168#endif /* SCHEMAS or XPATH */ 169#ifdef LIBXML_XPATH_ENABLED 170/** 171 * xmlXPathGetSign: 172 * @val: a double value 173 * 174 * Provides a portable function to detect the sign of a double 175 * Modified from trio code 176 * http://sourceforge.net/projects/ctrio/ 177 * 178 * Returns 1 if the value is Negative, 0 if positive 179 */ 180static int 181xmlXPathGetSign(double val) { 182 return(trio_signbit(val)); 183} 184 185 186/* 187 * TODO: when compatibility allows remove all "fake node libxslt" strings 188 * the test should just be name[0] = ' ' 189 */ 190/* #define DEBUG */ 191/* #define DEBUG_STEP */ 192/* #define DEBUG_STEP_NTH */ 193/* #define DEBUG_EXPR */ 194/* #define DEBUG_EVAL_COUNTS */ 195 196static xmlNs xmlXPathXMLNamespaceStruct = { 197 NULL, 198 XML_NAMESPACE_DECL, 199 XML_XML_NAMESPACE, 200 BAD_CAST "xml", 201 NULL 202}; 203static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 204#ifndef LIBXML_THREAD_ENABLED 205/* 206 * Optimizer is disabled only when threaded apps are detected while 207 * the library ain't compiled for thread safety. 208 */ 209static int xmlXPathDisableOptimizer = 0; 210#endif 211 212/************************************************************************ 213 * * 214 * Error handling routines * 215 * * 216 ************************************************************************/ 217 218/** 219 * XP_ERRORNULL: 220 * @X: the error code 221 * 222 * Macro to raise an XPath error and return NULL. 223 */ 224#define XP_ERRORNULL(X) \ 225 { xmlXPathErr(ctxt, X); return(NULL); } 226 227/* 228 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 229 */ 230static const char *xmlXPathErrorMessages[] = { 231 "Ok\n", 232 "Number encoding\n", 233 "Unfinished literal\n", 234 "Start of literal\n", 235 "Expected $ for variable reference\n", 236 "Undefined variable\n", 237 "Invalid predicate\n", 238 "Invalid expression\n", 239 "Missing closing curly brace\n", 240 "Unregistered function\n", 241 "Invalid operand\n", 242 "Invalid type\n", 243 "Invalid number of arguments\n", 244 "Invalid context size\n", 245 "Invalid context position\n", 246 "Memory allocation error\n", 247 "Syntax error\n", 248 "Resource error\n", 249 "Sub resource error\n", 250 "Undefined namespace prefix\n", 251 "Encoding error\n", 252 "Char out of XML range\n", 253 "Invalid or incomplete context\n", 254 "?? Unknown error ??\n" /* Must be last in the list! */ 255}; 256#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 257 sizeof(xmlXPathErrorMessages[0])) - 1) 258/** 259 * xmlXPathErrMemory: 260 * @ctxt: an XPath context 261 * @extra: extra informations 262 * 263 * Handle a redefinition of attribute error 264 */ 265static void 266xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 267{ 268 if (ctxt != NULL) { 269 if (extra) { 270 xmlChar buf[200]; 271 272 xmlStrPrintf(buf, 200, 273 BAD_CAST "Memory allocation failed : %s\n", 274 extra); 275 ctxt->lastError.message = (char *) xmlStrdup(buf); 276 } else { 277 ctxt->lastError.message = (char *) 278 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 279 } 280 ctxt->lastError.domain = XML_FROM_XPATH; 281 ctxt->lastError.code = XML_ERR_NO_MEMORY; 282 if (ctxt->error != NULL) 283 ctxt->error(ctxt->userData, &ctxt->lastError); 284 } else { 285 if (extra) 286 __xmlRaiseError(NULL, NULL, NULL, 287 NULL, NULL, XML_FROM_XPATH, 288 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 289 extra, NULL, NULL, 0, 0, 290 "Memory allocation failed : %s\n", extra); 291 else 292 __xmlRaiseError(NULL, NULL, NULL, 293 NULL, NULL, XML_FROM_XPATH, 294 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 295 NULL, NULL, NULL, 0, 0, 296 "Memory allocation failed\n"); 297 } 298} 299 300/** 301 * xmlXPathPErrMemory: 302 * @ctxt: an XPath parser context 303 * @extra: extra informations 304 * 305 * Handle a redefinition of attribute error 306 */ 307static void 308xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 309{ 310 if (ctxt == NULL) 311 xmlXPathErrMemory(NULL, extra); 312 else { 313 ctxt->error = XPATH_MEMORY_ERROR; 314 xmlXPathErrMemory(ctxt->context, extra); 315 } 316} 317 318/** 319 * xmlXPathErr: 320 * @ctxt: a XPath parser context 321 * @error: the error code 322 * 323 * Handle an XPath error 324 */ 325void 326xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 327{ 328 if ((error < 0) || (error > MAXERRNO)) 329 error = MAXERRNO; 330 if (ctxt == NULL) { 331 __xmlRaiseError(NULL, NULL, NULL, 332 NULL, NULL, XML_FROM_XPATH, 333 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 334 XML_ERR_ERROR, NULL, 0, 335 NULL, NULL, NULL, 0, 0, 336 xmlXPathErrorMessages[error]); 337 return; 338 } 339 ctxt->error = error; 340 if (ctxt->context == NULL) { 341 __xmlRaiseError(NULL, NULL, NULL, 342 NULL, NULL, XML_FROM_XPATH, 343 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 344 XML_ERR_ERROR, NULL, 0, 345 (const char *) ctxt->base, NULL, NULL, 346 ctxt->cur - ctxt->base, 0, 347 xmlXPathErrorMessages[error]); 348 return; 349 } 350 351 /* cleanup current last error */ 352 xmlResetError(&ctxt->context->lastError); 353 354 ctxt->context->lastError.domain = XML_FROM_XPATH; 355 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 356 XPATH_EXPRESSION_OK; 357 ctxt->context->lastError.level = XML_ERR_ERROR; 358 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 359 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 360 ctxt->context->lastError.node = ctxt->context->debugNode; 361 if (ctxt->context->error != NULL) { 362 ctxt->context->error(ctxt->context->userData, 363 &ctxt->context->lastError); 364 } else { 365 __xmlRaiseError(NULL, NULL, NULL, 366 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 367 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 368 XML_ERR_ERROR, NULL, 0, 369 (const char *) ctxt->base, NULL, NULL, 370 ctxt->cur - ctxt->base, 0, 371 xmlXPathErrorMessages[error]); 372 } 373 374} 375 376/** 377 * xmlXPatherror: 378 * @ctxt: the XPath Parser context 379 * @file: the file name 380 * @line: the line number 381 * @no: the error number 382 * 383 * Formats an error message. 384 */ 385void 386xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 387 int line ATTRIBUTE_UNUSED, int no) { 388 xmlXPathErr(ctxt, no); 389} 390 391/************************************************************************ 392 * * 393 * Utilities * 394 * * 395 ************************************************************************/ 396 397/** 398 * xsltPointerList: 399 * 400 * Pointer-list for various purposes. 401 */ 402typedef struct _xmlPointerList xmlPointerList; 403typedef xmlPointerList *xmlPointerListPtr; 404struct _xmlPointerList { 405 void **items; 406 int number; 407 int size; 408}; 409/* 410* TODO: Since such a list-handling is used in xmlschemas.c and libxslt 411* and here, we should make the functions public. 412*/ 413static int 414xmlPointerListAddSize(xmlPointerListPtr list, 415 void *item, 416 int initialSize) 417{ 418 if (list->items == NULL) { 419 if (initialSize <= 0) 420 initialSize = 1; 421 list->items = (void **) xmlMalloc( 422 initialSize * sizeof(void *)); 423 if (list->items == NULL) { 424 xmlXPathErrMemory(NULL, 425 "xmlPointerListCreate: allocating item\n"); 426 return(-1); 427 } 428 list->number = 0; 429 list->size = initialSize; 430 } else if (list->size <= list->number) { 431 list->size *= 2; 432 list->items = (void **) xmlRealloc(list->items, 433 list->size * sizeof(void *)); 434 if (list->items == NULL) { 435 xmlXPathErrMemory(NULL, 436 "xmlPointerListCreate: re-allocating item\n"); 437 list->size = 0; 438 return(-1); 439 } 440 } 441 list->items[list->number++] = item; 442 return(0); 443} 444 445/** 446 * xsltPointerListCreate: 447 * 448 * Creates an xsltPointerList structure. 449 * 450 * Returns a xsltPointerList structure or NULL in case of an error. 451 */ 452static xmlPointerListPtr 453xmlPointerListCreate(int initialSize) 454{ 455 xmlPointerListPtr ret; 456 457 ret = xmlMalloc(sizeof(xmlPointerList)); 458 if (ret == NULL) { 459 xmlXPathErrMemory(NULL, 460 "xmlPointerListCreate: allocating item\n"); 461 return (NULL); 462 } 463 memset(ret, 0, sizeof(xmlPointerList)); 464 if (initialSize > 0) { 465 xmlPointerListAddSize(ret, NULL, initialSize); 466 ret->number = 0; 467 } 468 return (ret); 469} 470 471/** 472 * xsltPointerListFree: 473 * 474 * Frees the xsltPointerList structure. This does not free 475 * the content of the list. 476 */ 477static void 478xmlPointerListFree(xmlPointerListPtr list) 479{ 480 if (list == NULL) 481 return; 482 if (list->items != NULL) 483 xmlFree(list->items); 484 xmlFree(list); 485} 486 487/************************************************************************ 488 * * 489 * Parser Types * 490 * * 491 ************************************************************************/ 492 493/* 494 * Types are private: 495 */ 496 497typedef enum { 498 XPATH_OP_END=0, 499 XPATH_OP_AND, 500 XPATH_OP_OR, 501 XPATH_OP_EQUAL, 502 XPATH_OP_CMP, 503 XPATH_OP_PLUS, 504 XPATH_OP_MULT, 505 XPATH_OP_UNION, 506 XPATH_OP_ROOT, 507 XPATH_OP_NODE, 508 XPATH_OP_RESET, /* 10 */ 509 XPATH_OP_COLLECT, 510 XPATH_OP_VALUE, /* 12 */ 511 XPATH_OP_VARIABLE, 512 XPATH_OP_FUNCTION, 513 XPATH_OP_ARG, 514 XPATH_OP_PREDICATE, 515 XPATH_OP_FILTER, /* 17 */ 516 XPATH_OP_SORT /* 18 */ 517#ifdef LIBXML_XPTR_ENABLED 518 ,XPATH_OP_RANGETO 519#endif 520} xmlXPathOp; 521 522typedef enum { 523 AXIS_ANCESTOR = 1, 524 AXIS_ANCESTOR_OR_SELF, 525 AXIS_ATTRIBUTE, 526 AXIS_CHILD, 527 AXIS_DESCENDANT, 528 AXIS_DESCENDANT_OR_SELF, 529 AXIS_FOLLOWING, 530 AXIS_FOLLOWING_SIBLING, 531 AXIS_NAMESPACE, 532 AXIS_PARENT, 533 AXIS_PRECEDING, 534 AXIS_PRECEDING_SIBLING, 535 AXIS_SELF 536} xmlXPathAxisVal; 537 538typedef enum { 539 NODE_TEST_NONE = 0, 540 NODE_TEST_TYPE = 1, 541 NODE_TEST_PI = 2, 542 NODE_TEST_ALL = 3, 543 NODE_TEST_NS = 4, 544 NODE_TEST_NAME = 5 545} xmlXPathTestVal; 546 547typedef enum { 548 NODE_TYPE_NODE = 0, 549 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 550 NODE_TYPE_TEXT = XML_TEXT_NODE, 551 NODE_TYPE_PI = XML_PI_NODE 552} xmlXPathTypeVal; 553 554#define XP_REWRITE_DOS_CHILD_ELEM 1 555 556typedef struct _xmlXPathStepOp xmlXPathStepOp; 557typedef xmlXPathStepOp *xmlXPathStepOpPtr; 558struct _xmlXPathStepOp { 559 xmlXPathOp op; /* The identifier of the operation */ 560 int ch1; /* First child */ 561 int ch2; /* Second child */ 562 int value; 563 int value2; 564 int value3; 565 void *value4; 566 void *value5; 567 void *cache; 568 void *cacheURI; 569 int rewriteType; 570}; 571 572struct _xmlXPathCompExpr { 573 int nbStep; /* Number of steps in this expression */ 574 int maxStep; /* Maximum number of steps allocated */ 575 xmlXPathStepOp *steps; /* ops for computation of this expression */ 576 int last; /* index of last step in expression */ 577 xmlChar *expr; /* the expression being computed */ 578 xmlDictPtr dict; /* the dictionnary to use if any */ 579#ifdef DEBUG_EVAL_COUNTS 580 int nb; 581 xmlChar *string; 582#endif 583#ifdef XPATH_STREAMING 584 xmlPatternPtr stream; 585#endif 586}; 587 588/************************************************************************ 589 * * 590 * Forward declarations * 591 * * 592 ************************************************************************/ 593static void 594xmlXPathFreeValueTree(xmlNodeSetPtr obj); 595static void 596xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 597static int 598xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 599 xmlXPathStepOpPtr op, xmlNodePtr *first); 600static int 601xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 602 xmlXPathStepOpPtr op, 603 int isPredicate); 604 605/************************************************************************ 606 * * 607 * Parser Type functions * 608 * * 609 ************************************************************************/ 610 611/** 612 * xmlXPathNewCompExpr: 613 * 614 * Create a new Xpath component 615 * 616 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 617 */ 618static xmlXPathCompExprPtr 619xmlXPathNewCompExpr(void) { 620 xmlXPathCompExprPtr cur; 621 622 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 623 if (cur == NULL) { 624 xmlXPathErrMemory(NULL, "allocating component\n"); 625 return(NULL); 626 } 627 memset(cur, 0, sizeof(xmlXPathCompExpr)); 628 cur->maxStep = 10; 629 cur->nbStep = 0; 630 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 631 sizeof(xmlXPathStepOp)); 632 if (cur->steps == NULL) { 633 xmlXPathErrMemory(NULL, "allocating steps\n"); 634 xmlFree(cur); 635 return(NULL); 636 } 637 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 638 cur->last = -1; 639#ifdef DEBUG_EVAL_COUNTS 640 cur->nb = 0; 641#endif 642 return(cur); 643} 644 645/** 646 * xmlXPathFreeCompExpr: 647 * @comp: an XPATH comp 648 * 649 * Free up the memory allocated by @comp 650 */ 651void 652xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 653{ 654 xmlXPathStepOpPtr op; 655 int i; 656 657 if (comp == NULL) 658 return; 659 if (comp->dict == NULL) { 660 for (i = 0; i < comp->nbStep; i++) { 661 op = &comp->steps[i]; 662 if (op->value4 != NULL) { 663 if (op->op == XPATH_OP_VALUE) 664 xmlXPathFreeObject(op->value4); 665 else 666 xmlFree(op->value4); 667 } 668 if (op->value5 != NULL) 669 xmlFree(op->value5); 670 } 671 } else { 672 for (i = 0; i < comp->nbStep; i++) { 673 op = &comp->steps[i]; 674 if (op->value4 != NULL) { 675 if (op->op == XPATH_OP_VALUE) 676 xmlXPathFreeObject(op->value4); 677 } 678 } 679 xmlDictFree(comp->dict); 680 } 681 if (comp->steps != NULL) { 682 xmlFree(comp->steps); 683 } 684#ifdef DEBUG_EVAL_COUNTS 685 if (comp->string != NULL) { 686 xmlFree(comp->string); 687 } 688#endif 689#ifdef XPATH_STREAMING 690 if (comp->stream != NULL) { 691 xmlFreePatternList(comp->stream); 692 } 693#endif 694 if (comp->expr != NULL) { 695 xmlFree(comp->expr); 696 } 697 698 xmlFree(comp); 699} 700 701/** 702 * xmlXPathCompExprAdd: 703 * @comp: the compiled expression 704 * @ch1: first child index 705 * @ch2: second child index 706 * @op: an op 707 * @value: the first int value 708 * @value2: the second int value 709 * @value3: the third int value 710 * @value4: the first string value 711 * @value5: the second string value 712 * 713 * Add a step to an XPath Compiled Expression 714 * 715 * Returns -1 in case of failure, the index otherwise 716 */ 717static int 718xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 719 xmlXPathOp op, int value, 720 int value2, int value3, void *value4, void *value5) { 721 if (comp->nbStep >= comp->maxStep) { 722 xmlXPathStepOp *real; 723 724 comp->maxStep *= 2; 725 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 726 comp->maxStep * sizeof(xmlXPathStepOp)); 727 if (real == NULL) { 728 comp->maxStep /= 2; 729 xmlXPathErrMemory(NULL, "adding step\n"); 730 return(-1); 731 } 732 comp->steps = real; 733 } 734 comp->last = comp->nbStep; 735 comp->steps[comp->nbStep].rewriteType = 0; 736 comp->steps[comp->nbStep].ch1 = ch1; 737 comp->steps[comp->nbStep].ch2 = ch2; 738 comp->steps[comp->nbStep].op = op; 739 comp->steps[comp->nbStep].value = value; 740 comp->steps[comp->nbStep].value2 = value2; 741 comp->steps[comp->nbStep].value3 = value3; 742 if ((comp->dict != NULL) && 743 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 744 (op == XPATH_OP_COLLECT))) { 745 if (value4 != NULL) { 746 comp->steps[comp->nbStep].value4 = (xmlChar *) 747 (void *)xmlDictLookup(comp->dict, value4, -1); 748 xmlFree(value4); 749 } else 750 comp->steps[comp->nbStep].value4 = NULL; 751 if (value5 != NULL) { 752 comp->steps[comp->nbStep].value5 = (xmlChar *) 753 (void *)xmlDictLookup(comp->dict, value5, -1); 754 xmlFree(value5); 755 } else 756 comp->steps[comp->nbStep].value5 = NULL; 757 } else { 758 comp->steps[comp->nbStep].value4 = value4; 759 comp->steps[comp->nbStep].value5 = value5; 760 } 761 comp->steps[comp->nbStep].cache = NULL; 762 return(comp->nbStep++); 763} 764 765/** 766 * xmlXPathCompSwap: 767 * @comp: the compiled expression 768 * @op: operation index 769 * 770 * Swaps 2 operations in the compiled expression 771 */ 772static void 773xmlXPathCompSwap(xmlXPathStepOpPtr op) { 774 int tmp; 775 776#ifndef LIBXML_THREAD_ENABLED 777 /* 778 * Since this manipulates possibly shared variables, this is 779 * disabled if one detects that the library is used in a multithreaded 780 * application 781 */ 782 if (xmlXPathDisableOptimizer) 783 return; 784#endif 785 786 tmp = op->ch1; 787 op->ch1 = op->ch2; 788 op->ch2 = tmp; 789} 790 791#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 792 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 793 (op), (val), (val2), (val3), (val4), (val5)) 794#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 795 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 796 (op), (val), (val2), (val3), (val4), (val5)) 797 798#define PUSH_LEAVE_EXPR(op, val, val2) \ 799xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 800 801#define PUSH_UNARY_EXPR(op, ch, val, val2) \ 802xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 803 804#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 805xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 806 (val), (val2), 0 ,NULL ,NULL) 807 808/************************************************************************ 809 * * 810 * XPath object cache structures * 811 * * 812 ************************************************************************/ 813 814/* #define XP_DEFAULT_CACHE_ON */ 815 816#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 817 818typedef struct _xmlXPathContextCache xmlXPathContextCache; 819typedef xmlXPathContextCache *xmlXPathContextCachePtr; 820struct _xmlXPathContextCache { 821 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 822 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 823 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 824 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 825 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 826 int maxNodeset; 827 int maxString; 828 int maxBoolean; 829 int maxNumber; 830 int maxMisc; 831#ifdef XP_DEBUG_OBJ_USAGE 832 int dbgCachedAll; 833 int dbgCachedNodeset; 834 int dbgCachedString; 835 int dbgCachedBool; 836 int dbgCachedNumber; 837 int dbgCachedPoint; 838 int dbgCachedRange; 839 int dbgCachedLocset; 840 int dbgCachedUsers; 841 int dbgCachedXSLTTree; 842 int dbgCachedUndefined; 843 844 845 int dbgReusedAll; 846 int dbgReusedNodeset; 847 int dbgReusedString; 848 int dbgReusedBool; 849 int dbgReusedNumber; 850 int dbgReusedPoint; 851 int dbgReusedRange; 852 int dbgReusedLocset; 853 int dbgReusedUsers; 854 int dbgReusedXSLTTree; 855 int dbgReusedUndefined; 856 857#endif 858}; 859 860/************************************************************************ 861 * * 862 * Debugging related functions * 863 * * 864 ************************************************************************/ 865 866#define STRANGE \ 867 xmlGenericError(xmlGenericErrorContext, \ 868 "Internal error at %s:%d\n", \ 869 __FILE__, __LINE__); 870 871#ifdef LIBXML_DEBUG_ENABLED 872static void 873xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 874 int i; 875 char shift[100]; 876 877 for (i = 0;((i < depth) && (i < 25));i++) 878 shift[2 * i] = shift[2 * i + 1] = ' '; 879 shift[2 * i] = shift[2 * i + 1] = 0; 880 if (cur == NULL) { 881 fprintf(output, shift); 882 fprintf(output, "Node is NULL !\n"); 883 return; 884 885 } 886 887 if ((cur->type == XML_DOCUMENT_NODE) || 888 (cur->type == XML_HTML_DOCUMENT_NODE)) { 889 fprintf(output, shift); 890 fprintf(output, " /\n"); 891 } else if (cur->type == XML_ATTRIBUTE_NODE) 892 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 893 else 894 xmlDebugDumpOneNode(output, cur, depth); 895} 896static void 897xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 898 xmlNodePtr tmp; 899 int i; 900 char shift[100]; 901 902 for (i = 0;((i < depth) && (i < 25));i++) 903 shift[2 * i] = shift[2 * i + 1] = ' '; 904 shift[2 * i] = shift[2 * i + 1] = 0; 905 if (cur == NULL) { 906 fprintf(output, shift); 907 fprintf(output, "Node is NULL !\n"); 908 return; 909 910 } 911 912 while (cur != NULL) { 913 tmp = cur; 914 cur = cur->next; 915 xmlDebugDumpOneNode(output, tmp, depth); 916 } 917} 918 919static void 920xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 921 int i; 922 char shift[100]; 923 924 for (i = 0;((i < depth) && (i < 25));i++) 925 shift[2 * i] = shift[2 * i + 1] = ' '; 926 shift[2 * i] = shift[2 * i + 1] = 0; 927 928 if (cur == NULL) { 929 fprintf(output, shift); 930 fprintf(output, "NodeSet is NULL !\n"); 931 return; 932 933 } 934 935 if (cur != NULL) { 936 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 937 for (i = 0;i < cur->nodeNr;i++) { 938 fprintf(output, shift); 939 fprintf(output, "%d", i + 1); 940 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 941 } 942 } 943} 944 945static void 946xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 947 int i; 948 char shift[100]; 949 950 for (i = 0;((i < depth) && (i < 25));i++) 951 shift[2 * i] = shift[2 * i + 1] = ' '; 952 shift[2 * i] = shift[2 * i + 1] = 0; 953 954 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 955 fprintf(output, shift); 956 fprintf(output, "Value Tree is NULL !\n"); 957 return; 958 959 } 960 961 fprintf(output, shift); 962 fprintf(output, "%d", i + 1); 963 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 964} 965#if defined(LIBXML_XPTR_ENABLED) 966static void 967xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 968 int i; 969 char shift[100]; 970 971 for (i = 0;((i < depth) && (i < 25));i++) 972 shift[2 * i] = shift[2 * i + 1] = ' '; 973 shift[2 * i] = shift[2 * i + 1] = 0; 974 975 if (cur == NULL) { 976 fprintf(output, shift); 977 fprintf(output, "LocationSet is NULL !\n"); 978 return; 979 980 } 981 982 for (i = 0;i < cur->locNr;i++) { 983 fprintf(output, shift); 984 fprintf(output, "%d : ", i + 1); 985 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 986 } 987} 988#endif /* LIBXML_XPTR_ENABLED */ 989 990/** 991 * xmlXPathDebugDumpObject: 992 * @output: the FILE * to dump the output 993 * @cur: the object to inspect 994 * @depth: indentation level 995 * 996 * Dump the content of the object for debugging purposes 997 */ 998void 999xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1000 int i; 1001 char shift[100]; 1002 1003 if (output == NULL) return; 1004 1005 for (i = 0;((i < depth) && (i < 25));i++) 1006 shift[2 * i] = shift[2 * i + 1] = ' '; 1007 shift[2 * i] = shift[2 * i + 1] = 0; 1008 1009 1010 fprintf(output, shift); 1011 1012 if (cur == NULL) { 1013 fprintf(output, "Object is empty (NULL)\n"); 1014 return; 1015 } 1016 switch(cur->type) { 1017 case XPATH_UNDEFINED: 1018 fprintf(output, "Object is uninitialized\n"); 1019 break; 1020 case XPATH_NODESET: 1021 fprintf(output, "Object is a Node Set :\n"); 1022 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1023 break; 1024 case XPATH_XSLT_TREE: 1025 fprintf(output, "Object is an XSLT value tree :\n"); 1026 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1027 break; 1028 case XPATH_BOOLEAN: 1029 fprintf(output, "Object is a Boolean : "); 1030 if (cur->boolval) fprintf(output, "true\n"); 1031 else fprintf(output, "false\n"); 1032 break; 1033 case XPATH_NUMBER: 1034 switch (xmlXPathIsInf(cur->floatval)) { 1035 case 1: 1036 fprintf(output, "Object is a number : Infinity\n"); 1037 break; 1038 case -1: 1039 fprintf(output, "Object is a number : -Infinity\n"); 1040 break; 1041 default: 1042 if (xmlXPathIsNaN(cur->floatval)) { 1043 fprintf(output, "Object is a number : NaN\n"); 1044 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 1045 fprintf(output, "Object is a number : 0\n"); 1046 } else { 1047 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1048 } 1049 } 1050 break; 1051 case XPATH_STRING: 1052 fprintf(output, "Object is a string : "); 1053 xmlDebugDumpString(output, cur->stringval); 1054 fprintf(output, "\n"); 1055 break; 1056 case XPATH_POINT: 1057 fprintf(output, "Object is a point : index %d in node", cur->index); 1058 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1059 fprintf(output, "\n"); 1060 break; 1061 case XPATH_RANGE: 1062 if ((cur->user2 == NULL) || 1063 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1064 fprintf(output, "Object is a collapsed range :\n"); 1065 fprintf(output, shift); 1066 if (cur->index >= 0) 1067 fprintf(output, "index %d in ", cur->index); 1068 fprintf(output, "node\n"); 1069 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1070 depth + 1); 1071 } else { 1072 fprintf(output, "Object is a range :\n"); 1073 fprintf(output, shift); 1074 fprintf(output, "From "); 1075 if (cur->index >= 0) 1076 fprintf(output, "index %d in ", cur->index); 1077 fprintf(output, "node\n"); 1078 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1079 depth + 1); 1080 fprintf(output, shift); 1081 fprintf(output, "To "); 1082 if (cur->index2 >= 0) 1083 fprintf(output, "index %d in ", cur->index2); 1084 fprintf(output, "node\n"); 1085 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1086 depth + 1); 1087 fprintf(output, "\n"); 1088 } 1089 break; 1090 case XPATH_LOCATIONSET: 1091#if defined(LIBXML_XPTR_ENABLED) 1092 fprintf(output, "Object is a Location Set:\n"); 1093 xmlXPathDebugDumpLocationSet(output, 1094 (xmlLocationSetPtr) cur->user, depth); 1095#endif 1096 break; 1097 case XPATH_USERS: 1098 fprintf(output, "Object is user defined\n"); 1099 break; 1100 } 1101} 1102 1103static void 1104xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1105 xmlXPathStepOpPtr op, int depth) { 1106 int i; 1107 char shift[100]; 1108 1109 for (i = 0;((i < depth) && (i < 25));i++) 1110 shift[2 * i] = shift[2 * i + 1] = ' '; 1111 shift[2 * i] = shift[2 * i + 1] = 0; 1112 1113 fprintf(output, shift); 1114 if (op == NULL) { 1115 fprintf(output, "Step is NULL\n"); 1116 return; 1117 } 1118 switch (op->op) { 1119 case XPATH_OP_END: 1120 fprintf(output, "END"); break; 1121 case XPATH_OP_AND: 1122 fprintf(output, "AND"); break; 1123 case XPATH_OP_OR: 1124 fprintf(output, "OR"); break; 1125 case XPATH_OP_EQUAL: 1126 if (op->value) 1127 fprintf(output, "EQUAL ="); 1128 else 1129 fprintf(output, "EQUAL !="); 1130 break; 1131 case XPATH_OP_CMP: 1132 if (op->value) 1133 fprintf(output, "CMP <"); 1134 else 1135 fprintf(output, "CMP >"); 1136 if (!op->value2) 1137 fprintf(output, "="); 1138 break; 1139 case XPATH_OP_PLUS: 1140 if (op->value == 0) 1141 fprintf(output, "PLUS -"); 1142 else if (op->value == 1) 1143 fprintf(output, "PLUS +"); 1144 else if (op->value == 2) 1145 fprintf(output, "PLUS unary -"); 1146 else if (op->value == 3) 1147 fprintf(output, "PLUS unary - -"); 1148 break; 1149 case XPATH_OP_MULT: 1150 if (op->value == 0) 1151 fprintf(output, "MULT *"); 1152 else if (op->value == 1) 1153 fprintf(output, "MULT div"); 1154 else 1155 fprintf(output, "MULT mod"); 1156 break; 1157 case XPATH_OP_UNION: 1158 fprintf(output, "UNION"); break; 1159 case XPATH_OP_ROOT: 1160 fprintf(output, "ROOT"); break; 1161 case XPATH_OP_NODE: 1162 fprintf(output, "NODE"); break; 1163 case XPATH_OP_RESET: 1164 fprintf(output, "RESET"); break; 1165 case XPATH_OP_SORT: 1166 fprintf(output, "SORT"); break; 1167 case XPATH_OP_COLLECT: { 1168 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1169 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1170 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1171 const xmlChar *prefix = op->value4; 1172 const xmlChar *name = op->value5; 1173 1174 fprintf(output, "COLLECT "); 1175 switch (axis) { 1176 case AXIS_ANCESTOR: 1177 fprintf(output, " 'ancestors' "); break; 1178 case AXIS_ANCESTOR_OR_SELF: 1179 fprintf(output, " 'ancestors-or-self' "); break; 1180 case AXIS_ATTRIBUTE: 1181 fprintf(output, " 'attributes' "); break; 1182 case AXIS_CHILD: 1183 fprintf(output, " 'child' "); break; 1184 case AXIS_DESCENDANT: 1185 fprintf(output, " 'descendant' "); break; 1186 case AXIS_DESCENDANT_OR_SELF: 1187 fprintf(output, " 'descendant-or-self' "); break; 1188 case AXIS_FOLLOWING: 1189 fprintf(output, " 'following' "); break; 1190 case AXIS_FOLLOWING_SIBLING: 1191 fprintf(output, " 'following-siblings' "); break; 1192 case AXIS_NAMESPACE: 1193 fprintf(output, " 'namespace' "); break; 1194 case AXIS_PARENT: 1195 fprintf(output, " 'parent' "); break; 1196 case AXIS_PRECEDING: 1197 fprintf(output, " 'preceding' "); break; 1198 case AXIS_PRECEDING_SIBLING: 1199 fprintf(output, " 'preceding-sibling' "); break; 1200 case AXIS_SELF: 1201 fprintf(output, " 'self' "); break; 1202 } 1203 switch (test) { 1204 case NODE_TEST_NONE: 1205 fprintf(output, "'none' "); break; 1206 case NODE_TEST_TYPE: 1207 fprintf(output, "'type' "); break; 1208 case NODE_TEST_PI: 1209 fprintf(output, "'PI' "); break; 1210 case NODE_TEST_ALL: 1211 fprintf(output, "'all' "); break; 1212 case NODE_TEST_NS: 1213 fprintf(output, "'namespace' "); break; 1214 case NODE_TEST_NAME: 1215 fprintf(output, "'name' "); break; 1216 } 1217 switch (type) { 1218 case NODE_TYPE_NODE: 1219 fprintf(output, "'node' "); break; 1220 case NODE_TYPE_COMMENT: 1221 fprintf(output, "'comment' "); break; 1222 case NODE_TYPE_TEXT: 1223 fprintf(output, "'text' "); break; 1224 case NODE_TYPE_PI: 1225 fprintf(output, "'PI' "); break; 1226 } 1227 if (prefix != NULL) 1228 fprintf(output, "%s:", prefix); 1229 if (name != NULL) 1230 fprintf(output, "%s", (const char *) name); 1231 break; 1232 1233 } 1234 case XPATH_OP_VALUE: { 1235 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1236 1237 fprintf(output, "ELEM "); 1238 xmlXPathDebugDumpObject(output, object, 0); 1239 goto finish; 1240 } 1241 case XPATH_OP_VARIABLE: { 1242 const xmlChar *prefix = op->value5; 1243 const xmlChar *name = op->value4; 1244 1245 if (prefix != NULL) 1246 fprintf(output, "VARIABLE %s:%s", prefix, name); 1247 else 1248 fprintf(output, "VARIABLE %s", name); 1249 break; 1250 } 1251 case XPATH_OP_FUNCTION: { 1252 int nbargs = op->value; 1253 const xmlChar *prefix = op->value5; 1254 const xmlChar *name = op->value4; 1255 1256 if (prefix != NULL) 1257 fprintf(output, "FUNCTION %s:%s(%d args)", 1258 prefix, name, nbargs); 1259 else 1260 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1261 break; 1262 } 1263 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1264 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1265 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1266#ifdef LIBXML_XPTR_ENABLED 1267 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1268#endif 1269 default: 1270 fprintf(output, "UNKNOWN %d\n", op->op); return; 1271 } 1272 fprintf(output, "\n"); 1273finish: 1274 if (op->ch1 >= 0) 1275 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1276 if (op->ch2 >= 0) 1277 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1278} 1279 1280/** 1281 * xmlXPathDebugDumpCompExpr: 1282 * @output: the FILE * for the output 1283 * @comp: the precompiled XPath expression 1284 * @depth: the indentation level. 1285 * 1286 * Dumps the tree of the compiled XPath expression. 1287 */ 1288void 1289xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1290 int depth) { 1291 int i; 1292 char shift[100]; 1293 1294 if ((output == NULL) || (comp == NULL)) return; 1295 1296 for (i = 0;((i < depth) && (i < 25));i++) 1297 shift[2 * i] = shift[2 * i + 1] = ' '; 1298 shift[2 * i] = shift[2 * i + 1] = 0; 1299 1300 fprintf(output, shift); 1301 1302 fprintf(output, "Compiled Expression : %d elements\n", 1303 comp->nbStep); 1304 i = comp->last; 1305 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1306} 1307 1308#ifdef XP_DEBUG_OBJ_USAGE 1309 1310/* 1311* XPath object usage related debugging variables. 1312*/ 1313static int xmlXPathDebugObjCounterUndefined = 0; 1314static int xmlXPathDebugObjCounterNodeset = 0; 1315static int xmlXPathDebugObjCounterBool = 0; 1316static int xmlXPathDebugObjCounterNumber = 0; 1317static int xmlXPathDebugObjCounterString = 0; 1318static int xmlXPathDebugObjCounterPoint = 0; 1319static int xmlXPathDebugObjCounterRange = 0; 1320static int xmlXPathDebugObjCounterLocset = 0; 1321static int xmlXPathDebugObjCounterUsers = 0; 1322static int xmlXPathDebugObjCounterXSLTTree = 0; 1323static int xmlXPathDebugObjCounterAll = 0; 1324 1325static int xmlXPathDebugObjTotalUndefined = 0; 1326static int xmlXPathDebugObjTotalNodeset = 0; 1327static int xmlXPathDebugObjTotalBool = 0; 1328static int xmlXPathDebugObjTotalNumber = 0; 1329static int xmlXPathDebugObjTotalString = 0; 1330static int xmlXPathDebugObjTotalPoint = 0; 1331static int xmlXPathDebugObjTotalRange = 0; 1332static int xmlXPathDebugObjTotalLocset = 0; 1333static int xmlXPathDebugObjTotalUsers = 0; 1334static int xmlXPathDebugObjTotalXSLTTree = 0; 1335static int xmlXPathDebugObjTotalAll = 0; 1336 1337static int xmlXPathDebugObjMaxUndefined = 0; 1338static int xmlXPathDebugObjMaxNodeset = 0; 1339static int xmlXPathDebugObjMaxBool = 0; 1340static int xmlXPathDebugObjMaxNumber = 0; 1341static int xmlXPathDebugObjMaxString = 0; 1342static int xmlXPathDebugObjMaxPoint = 0; 1343static int xmlXPathDebugObjMaxRange = 0; 1344static int xmlXPathDebugObjMaxLocset = 0; 1345static int xmlXPathDebugObjMaxUsers = 0; 1346static int xmlXPathDebugObjMaxXSLTTree = 0; 1347static int xmlXPathDebugObjMaxAll = 0; 1348 1349/* REVISIT TODO: Make this static when committing */ 1350static void 1351xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1352{ 1353 if (ctxt != NULL) { 1354 if (ctxt->cache != NULL) { 1355 xmlXPathContextCachePtr cache = 1356 (xmlXPathContextCachePtr) ctxt->cache; 1357 1358 cache->dbgCachedAll = 0; 1359 cache->dbgCachedNodeset = 0; 1360 cache->dbgCachedString = 0; 1361 cache->dbgCachedBool = 0; 1362 cache->dbgCachedNumber = 0; 1363 cache->dbgCachedPoint = 0; 1364 cache->dbgCachedRange = 0; 1365 cache->dbgCachedLocset = 0; 1366 cache->dbgCachedUsers = 0; 1367 cache->dbgCachedXSLTTree = 0; 1368 cache->dbgCachedUndefined = 0; 1369 1370 cache->dbgReusedAll = 0; 1371 cache->dbgReusedNodeset = 0; 1372 cache->dbgReusedString = 0; 1373 cache->dbgReusedBool = 0; 1374 cache->dbgReusedNumber = 0; 1375 cache->dbgReusedPoint = 0; 1376 cache->dbgReusedRange = 0; 1377 cache->dbgReusedLocset = 0; 1378 cache->dbgReusedUsers = 0; 1379 cache->dbgReusedXSLTTree = 0; 1380 cache->dbgReusedUndefined = 0; 1381 } 1382 } 1383 1384 xmlXPathDebugObjCounterUndefined = 0; 1385 xmlXPathDebugObjCounterNodeset = 0; 1386 xmlXPathDebugObjCounterBool = 0; 1387 xmlXPathDebugObjCounterNumber = 0; 1388 xmlXPathDebugObjCounterString = 0; 1389 xmlXPathDebugObjCounterPoint = 0; 1390 xmlXPathDebugObjCounterRange = 0; 1391 xmlXPathDebugObjCounterLocset = 0; 1392 xmlXPathDebugObjCounterUsers = 0; 1393 xmlXPathDebugObjCounterXSLTTree = 0; 1394 xmlXPathDebugObjCounterAll = 0; 1395 1396 xmlXPathDebugObjTotalUndefined = 0; 1397 xmlXPathDebugObjTotalNodeset = 0; 1398 xmlXPathDebugObjTotalBool = 0; 1399 xmlXPathDebugObjTotalNumber = 0; 1400 xmlXPathDebugObjTotalString = 0; 1401 xmlXPathDebugObjTotalPoint = 0; 1402 xmlXPathDebugObjTotalRange = 0; 1403 xmlXPathDebugObjTotalLocset = 0; 1404 xmlXPathDebugObjTotalUsers = 0; 1405 xmlXPathDebugObjTotalXSLTTree = 0; 1406 xmlXPathDebugObjTotalAll = 0; 1407 1408 xmlXPathDebugObjMaxUndefined = 0; 1409 xmlXPathDebugObjMaxNodeset = 0; 1410 xmlXPathDebugObjMaxBool = 0; 1411 xmlXPathDebugObjMaxNumber = 0; 1412 xmlXPathDebugObjMaxString = 0; 1413 xmlXPathDebugObjMaxPoint = 0; 1414 xmlXPathDebugObjMaxRange = 0; 1415 xmlXPathDebugObjMaxLocset = 0; 1416 xmlXPathDebugObjMaxUsers = 0; 1417 xmlXPathDebugObjMaxXSLTTree = 0; 1418 xmlXPathDebugObjMaxAll = 0; 1419 1420} 1421 1422static void 1423xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1424 xmlXPathObjectType objType) 1425{ 1426 int isCached = 0; 1427 1428 if (ctxt != NULL) { 1429 if (ctxt->cache != NULL) { 1430 xmlXPathContextCachePtr cache = 1431 (xmlXPathContextCachePtr) ctxt->cache; 1432 1433 isCached = 1; 1434 1435 cache->dbgReusedAll++; 1436 switch (objType) { 1437 case XPATH_UNDEFINED: 1438 cache->dbgReusedUndefined++; 1439 break; 1440 case XPATH_NODESET: 1441 cache->dbgReusedNodeset++; 1442 break; 1443 case XPATH_BOOLEAN: 1444 cache->dbgReusedBool++; 1445 break; 1446 case XPATH_NUMBER: 1447 cache->dbgReusedNumber++; 1448 break; 1449 case XPATH_STRING: 1450 cache->dbgReusedString++; 1451 break; 1452 case XPATH_POINT: 1453 cache->dbgReusedPoint++; 1454 break; 1455 case XPATH_RANGE: 1456 cache->dbgReusedRange++; 1457 break; 1458 case XPATH_LOCATIONSET: 1459 cache->dbgReusedLocset++; 1460 break; 1461 case XPATH_USERS: 1462 cache->dbgReusedUsers++; 1463 break; 1464 case XPATH_XSLT_TREE: 1465 cache->dbgReusedXSLTTree++; 1466 break; 1467 default: 1468 break; 1469 } 1470 } 1471 } 1472 1473 switch (objType) { 1474 case XPATH_UNDEFINED: 1475 if (! isCached) 1476 xmlXPathDebugObjTotalUndefined++; 1477 xmlXPathDebugObjCounterUndefined++; 1478 if (xmlXPathDebugObjCounterUndefined > 1479 xmlXPathDebugObjMaxUndefined) 1480 xmlXPathDebugObjMaxUndefined = 1481 xmlXPathDebugObjCounterUndefined; 1482 break; 1483 case XPATH_NODESET: 1484 if (! isCached) 1485 xmlXPathDebugObjTotalNodeset++; 1486 xmlXPathDebugObjCounterNodeset++; 1487 if (xmlXPathDebugObjCounterNodeset > 1488 xmlXPathDebugObjMaxNodeset) 1489 xmlXPathDebugObjMaxNodeset = 1490 xmlXPathDebugObjCounterNodeset; 1491 break; 1492 case XPATH_BOOLEAN: 1493 if (! isCached) 1494 xmlXPathDebugObjTotalBool++; 1495 xmlXPathDebugObjCounterBool++; 1496 if (xmlXPathDebugObjCounterBool > 1497 xmlXPathDebugObjMaxBool) 1498 xmlXPathDebugObjMaxBool = 1499 xmlXPathDebugObjCounterBool; 1500 break; 1501 case XPATH_NUMBER: 1502 if (! isCached) 1503 xmlXPathDebugObjTotalNumber++; 1504 xmlXPathDebugObjCounterNumber++; 1505 if (xmlXPathDebugObjCounterNumber > 1506 xmlXPathDebugObjMaxNumber) 1507 xmlXPathDebugObjMaxNumber = 1508 xmlXPathDebugObjCounterNumber; 1509 break; 1510 case XPATH_STRING: 1511 if (! isCached) 1512 xmlXPathDebugObjTotalString++; 1513 xmlXPathDebugObjCounterString++; 1514 if (xmlXPathDebugObjCounterString > 1515 xmlXPathDebugObjMaxString) 1516 xmlXPathDebugObjMaxString = 1517 xmlXPathDebugObjCounterString; 1518 break; 1519 case XPATH_POINT: 1520 if (! isCached) 1521 xmlXPathDebugObjTotalPoint++; 1522 xmlXPathDebugObjCounterPoint++; 1523 if (xmlXPathDebugObjCounterPoint > 1524 xmlXPathDebugObjMaxPoint) 1525 xmlXPathDebugObjMaxPoint = 1526 xmlXPathDebugObjCounterPoint; 1527 break; 1528 case XPATH_RANGE: 1529 if (! isCached) 1530 xmlXPathDebugObjTotalRange++; 1531 xmlXPathDebugObjCounterRange++; 1532 if (xmlXPathDebugObjCounterRange > 1533 xmlXPathDebugObjMaxRange) 1534 xmlXPathDebugObjMaxRange = 1535 xmlXPathDebugObjCounterRange; 1536 break; 1537 case XPATH_LOCATIONSET: 1538 if (! isCached) 1539 xmlXPathDebugObjTotalLocset++; 1540 xmlXPathDebugObjCounterLocset++; 1541 if (xmlXPathDebugObjCounterLocset > 1542 xmlXPathDebugObjMaxLocset) 1543 xmlXPathDebugObjMaxLocset = 1544 xmlXPathDebugObjCounterLocset; 1545 break; 1546 case XPATH_USERS: 1547 if (! isCached) 1548 xmlXPathDebugObjTotalUsers++; 1549 xmlXPathDebugObjCounterUsers++; 1550 if (xmlXPathDebugObjCounterUsers > 1551 xmlXPathDebugObjMaxUsers) 1552 xmlXPathDebugObjMaxUsers = 1553 xmlXPathDebugObjCounterUsers; 1554 break; 1555 case XPATH_XSLT_TREE: 1556 if (! isCached) 1557 xmlXPathDebugObjTotalXSLTTree++; 1558 xmlXPathDebugObjCounterXSLTTree++; 1559 if (xmlXPathDebugObjCounterXSLTTree > 1560 xmlXPathDebugObjMaxXSLTTree) 1561 xmlXPathDebugObjMaxXSLTTree = 1562 xmlXPathDebugObjCounterXSLTTree; 1563 break; 1564 default: 1565 break; 1566 } 1567 if (! isCached) 1568 xmlXPathDebugObjTotalAll++; 1569 xmlXPathDebugObjCounterAll++; 1570 if (xmlXPathDebugObjCounterAll > 1571 xmlXPathDebugObjMaxAll) 1572 xmlXPathDebugObjMaxAll = 1573 xmlXPathDebugObjCounterAll; 1574} 1575 1576static void 1577xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1578 xmlXPathObjectType objType) 1579{ 1580 int isCached = 0; 1581 1582 if (ctxt != NULL) { 1583 if (ctxt->cache != NULL) { 1584 xmlXPathContextCachePtr cache = 1585 (xmlXPathContextCachePtr) ctxt->cache; 1586 1587 isCached = 1; 1588 1589 cache->dbgCachedAll++; 1590 switch (objType) { 1591 case XPATH_UNDEFINED: 1592 cache->dbgCachedUndefined++; 1593 break; 1594 case XPATH_NODESET: 1595 cache->dbgCachedNodeset++; 1596 break; 1597 case XPATH_BOOLEAN: 1598 cache->dbgCachedBool++; 1599 break; 1600 case XPATH_NUMBER: 1601 cache->dbgCachedNumber++; 1602 break; 1603 case XPATH_STRING: 1604 cache->dbgCachedString++; 1605 break; 1606 case XPATH_POINT: 1607 cache->dbgCachedPoint++; 1608 break; 1609 case XPATH_RANGE: 1610 cache->dbgCachedRange++; 1611 break; 1612 case XPATH_LOCATIONSET: 1613 cache->dbgCachedLocset++; 1614 break; 1615 case XPATH_USERS: 1616 cache->dbgCachedUsers++; 1617 break; 1618 case XPATH_XSLT_TREE: 1619 cache->dbgCachedXSLTTree++; 1620 break; 1621 default: 1622 break; 1623 } 1624 1625 } 1626 } 1627 switch (objType) { 1628 case XPATH_UNDEFINED: 1629 xmlXPathDebugObjCounterUndefined--; 1630 break; 1631 case XPATH_NODESET: 1632 xmlXPathDebugObjCounterNodeset--; 1633 break; 1634 case XPATH_BOOLEAN: 1635 xmlXPathDebugObjCounterBool--; 1636 break; 1637 case XPATH_NUMBER: 1638 xmlXPathDebugObjCounterNumber--; 1639 break; 1640 case XPATH_STRING: 1641 xmlXPathDebugObjCounterString--; 1642 break; 1643 case XPATH_POINT: 1644 xmlXPathDebugObjCounterPoint--; 1645 break; 1646 case XPATH_RANGE: 1647 xmlXPathDebugObjCounterRange--; 1648 break; 1649 case XPATH_LOCATIONSET: 1650 xmlXPathDebugObjCounterLocset--; 1651 break; 1652 case XPATH_USERS: 1653 xmlXPathDebugObjCounterUsers--; 1654 break; 1655 case XPATH_XSLT_TREE: 1656 xmlXPathDebugObjCounterXSLTTree--; 1657 break; 1658 default: 1659 break; 1660 } 1661 xmlXPathDebugObjCounterAll--; 1662} 1663 1664/* REVISIT TODO: Make this static when committing */ 1665static void 1666xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 1667{ 1668 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 1669 reqXSLTTree, reqUndefined; 1670 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 1671 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 1672 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 1673 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 1674 int leftObjs = xmlXPathDebugObjCounterAll; 1675 1676 reqAll = xmlXPathDebugObjTotalAll; 1677 reqNodeset = xmlXPathDebugObjTotalNodeset; 1678 reqString = xmlXPathDebugObjTotalString; 1679 reqBool = xmlXPathDebugObjTotalBool; 1680 reqNumber = xmlXPathDebugObjTotalNumber; 1681 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 1682 reqUndefined = xmlXPathDebugObjTotalUndefined; 1683 1684 printf("# XPath object usage:\n"); 1685 1686 if (ctxt != NULL) { 1687 if (ctxt->cache != NULL) { 1688 xmlXPathContextCachePtr cache = 1689 (xmlXPathContextCachePtr) ctxt->cache; 1690 1691 reAll = cache->dbgReusedAll; 1692 reqAll += reAll; 1693 reNodeset = cache->dbgReusedNodeset; 1694 reqNodeset += reNodeset; 1695 reString = cache->dbgReusedString; 1696 reqString += reString; 1697 reBool = cache->dbgReusedBool; 1698 reqBool += reBool; 1699 reNumber = cache->dbgReusedNumber; 1700 reqNumber += reNumber; 1701 reXSLTTree = cache->dbgReusedXSLTTree; 1702 reqXSLTTree += reXSLTTree; 1703 reUndefined = cache->dbgReusedUndefined; 1704 reqUndefined += reUndefined; 1705 1706 caAll = cache->dbgCachedAll; 1707 caBool = cache->dbgCachedBool; 1708 caNodeset = cache->dbgCachedNodeset; 1709 caString = cache->dbgCachedString; 1710 caNumber = cache->dbgCachedNumber; 1711 caXSLTTree = cache->dbgCachedXSLTTree; 1712 caUndefined = cache->dbgCachedUndefined; 1713 1714 if (cache->nodesetObjs) 1715 leftObjs -= cache->nodesetObjs->number; 1716 if (cache->stringObjs) 1717 leftObjs -= cache->stringObjs->number; 1718 if (cache->booleanObjs) 1719 leftObjs -= cache->booleanObjs->number; 1720 if (cache->numberObjs) 1721 leftObjs -= cache->numberObjs->number; 1722 if (cache->miscObjs) 1723 leftObjs -= cache->miscObjs->number; 1724 } 1725 } 1726 1727 printf("# all\n"); 1728 printf("# total : %d\n", reqAll); 1729 printf("# left : %d\n", leftObjs); 1730 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 1731 printf("# reused : %d\n", reAll); 1732 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 1733 1734 printf("# node-sets\n"); 1735 printf("# total : %d\n", reqNodeset); 1736 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 1737 printf("# reused : %d\n", reNodeset); 1738 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 1739 1740 printf("# strings\n"); 1741 printf("# total : %d\n", reqString); 1742 printf("# created: %d\n", xmlXPathDebugObjTotalString); 1743 printf("# reused : %d\n", reString); 1744 printf("# max : %d\n", xmlXPathDebugObjMaxString); 1745 1746 printf("# booleans\n"); 1747 printf("# total : %d\n", reqBool); 1748 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 1749 printf("# reused : %d\n", reBool); 1750 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 1751 1752 printf("# numbers\n"); 1753 printf("# total : %d\n", reqNumber); 1754 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 1755 printf("# reused : %d\n", reNumber); 1756 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 1757 1758 printf("# XSLT result tree fragments\n"); 1759 printf("# total : %d\n", reqXSLTTree); 1760 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 1761 printf("# reused : %d\n", reXSLTTree); 1762 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 1763 1764 printf("# undefined\n"); 1765 printf("# total : %d\n", reqUndefined); 1766 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 1767 printf("# reused : %d\n", reUndefined); 1768 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 1769 1770} 1771 1772#endif /* XP_DEBUG_OBJ_USAGE */ 1773 1774#endif /* LIBXML_DEBUG_ENABLED */ 1775 1776/************************************************************************ 1777 * * 1778 * XPath object caching * 1779 * * 1780 ************************************************************************/ 1781 1782/** 1783 * xmlXPathNewCache: 1784 * 1785 * Create a new object cache 1786 * 1787 * Returns the xmlXPathCache just allocated. 1788 */ 1789static xmlXPathContextCachePtr 1790xmlXPathNewCache(void) 1791{ 1792 xmlXPathContextCachePtr ret; 1793 1794 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 1795 if (ret == NULL) { 1796 xmlXPathErrMemory(NULL, "creating object cache\n"); 1797 return(NULL); 1798 } 1799 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 1800 ret->maxNodeset = 100; 1801 ret->maxString = 100; 1802 ret->maxBoolean = 100; 1803 ret->maxNumber = 100; 1804 ret->maxMisc = 100; 1805 return(ret); 1806} 1807 1808static void 1809xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 1810{ 1811 int i; 1812 xmlXPathObjectPtr obj; 1813 1814 if (list == NULL) 1815 return; 1816 1817 for (i = 0; i < list->number; i++) { 1818 obj = list->items[i]; 1819 /* 1820 * Note that it is already assured that we don't need to 1821 * look out for namespace nodes in the node-set. 1822 */ 1823 if (obj->nodesetval != NULL) { 1824 if (obj->nodesetval->nodeTab != NULL) 1825 xmlFree(obj->nodesetval->nodeTab); 1826 xmlFree(obj->nodesetval); 1827 } 1828 xmlFree(obj); 1829#ifdef XP_DEBUG_OBJ_USAGE 1830 xmlXPathDebugObjCounterAll--; 1831#endif 1832 } 1833 xmlPointerListFree(list); 1834} 1835 1836static void 1837xmlXPathFreeCache(xmlXPathContextCachePtr cache) 1838{ 1839 if (cache == NULL) 1840 return; 1841 if (cache->nodesetObjs) 1842 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 1843 if (cache->stringObjs) 1844 xmlXPathCacheFreeObjectList(cache->stringObjs); 1845 if (cache->booleanObjs) 1846 xmlXPathCacheFreeObjectList(cache->booleanObjs); 1847 if (cache->numberObjs) 1848 xmlXPathCacheFreeObjectList(cache->numberObjs); 1849 if (cache->miscObjs) 1850 xmlXPathCacheFreeObjectList(cache->miscObjs); 1851 xmlFree(cache); 1852} 1853 1854/** 1855 * xmlXPathContextSetCache: 1856 * 1857 * @ctxt: the XPath context 1858 * @active: enables/disables (creates/frees) the cache 1859 * @value: a value with semantics dependant on @options 1860 * @options: options (currently only the value 0 is used) 1861 * 1862 * Creates/frees an object cache on the XPath context. 1863 * If activates XPath objects (xmlXPathObject) will be cached internally 1864 * to be reused. 1865 * @options: 1866 * 0: This will set the XPath object caching: 1867 * @value: 1868 * This will set the maximum number of XPath objects 1869 * to be cached per slot 1870 * There are 5 slots for: node-set, string, number, boolean, and 1871 * misc objects. Use <0 for the default number (100). 1872 * Other values for @options have currently no effect. 1873 * 1874 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 1875 */ 1876int 1877xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 1878 int active, 1879 int value, 1880 int options) 1881{ 1882 if (ctxt == NULL) 1883 return(-1); 1884 if (active) { 1885 xmlXPathContextCachePtr cache; 1886 1887 if (ctxt->cache == NULL) { 1888 ctxt->cache = xmlXPathNewCache(); 1889 if (ctxt->cache == NULL) 1890 return(-1); 1891 } 1892 cache = (xmlXPathContextCachePtr) ctxt->cache; 1893 if (options == 0) { 1894 if (value < 0) 1895 value = 100; 1896 cache->maxNodeset = value; 1897 cache->maxString = value; 1898 cache->maxNumber = value; 1899 cache->maxBoolean = value; 1900 cache->maxMisc = value; 1901 } 1902 } else if (ctxt->cache != NULL) { 1903 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 1904 ctxt->cache = NULL; 1905 } 1906 return(0); 1907} 1908 1909/** 1910 * xmlXPathCacheWrapNodeSet: 1911 * @ctxt: the XPath context 1912 * @val: the NodePtr value 1913 * 1914 * This is the cached version of xmlXPathWrapNodeSet(). 1915 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 1916 * 1917 * Returns the created or reused object. 1918 */ 1919static xmlXPathObjectPtr 1920xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 1921{ 1922 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1923 xmlXPathContextCachePtr cache = 1924 (xmlXPathContextCachePtr) ctxt->cache; 1925 1926 if ((cache->miscObjs != NULL) && 1927 (cache->miscObjs->number != 0)) 1928 { 1929 xmlXPathObjectPtr ret; 1930 1931 ret = (xmlXPathObjectPtr) 1932 cache->miscObjs->items[--cache->miscObjs->number]; 1933 ret->type = XPATH_NODESET; 1934 ret->nodesetval = val; 1935#ifdef XP_DEBUG_OBJ_USAGE 1936 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 1937#endif 1938 return(ret); 1939 } 1940 } 1941 1942 return(xmlXPathWrapNodeSet(val)); 1943 1944} 1945 1946/** 1947 * xmlXPathCacheWrapString: 1948 * @ctxt: the XPath context 1949 * @val: the xmlChar * value 1950 * 1951 * This is the cached version of xmlXPathWrapString(). 1952 * Wraps the @val string into an XPath object. 1953 * 1954 * Returns the created or reused object. 1955 */ 1956static xmlXPathObjectPtr 1957xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 1958{ 1959 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1960 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 1961 1962 if ((cache->stringObjs != NULL) && 1963 (cache->stringObjs->number != 0)) 1964 { 1965 1966 xmlXPathObjectPtr ret; 1967 1968 ret = (xmlXPathObjectPtr) 1969 cache->stringObjs->items[--cache->stringObjs->number]; 1970 ret->type = XPATH_STRING; 1971 ret->stringval = val; 1972#ifdef XP_DEBUG_OBJ_USAGE 1973 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1974#endif 1975 return(ret); 1976 } else if ((cache->miscObjs != NULL) && 1977 (cache->miscObjs->number != 0)) 1978 { 1979 xmlXPathObjectPtr ret; 1980 /* 1981 * Fallback to misc-cache. 1982 */ 1983 ret = (xmlXPathObjectPtr) 1984 cache->miscObjs->items[--cache->miscObjs->number]; 1985 1986 ret->type = XPATH_STRING; 1987 ret->stringval = val; 1988#ifdef XP_DEBUG_OBJ_USAGE 1989 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1990#endif 1991 return(ret); 1992 } 1993 } 1994 return(xmlXPathWrapString(val)); 1995} 1996 1997/** 1998 * xmlXPathCacheNewNodeSet: 1999 * @ctxt: the XPath context 2000 * @val: the NodePtr value 2001 * 2002 * This is the cached version of xmlXPathNewNodeSet(). 2003 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2004 * it with the single Node @val 2005 * 2006 * Returns the created or reused object. 2007 */ 2008static xmlXPathObjectPtr 2009xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2010{ 2011 if ((ctxt != NULL) && (ctxt->cache)) { 2012 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2013 2014 if ((cache->nodesetObjs != NULL) && 2015 (cache->nodesetObjs->number != 0)) 2016 { 2017 xmlXPathObjectPtr ret; 2018 /* 2019 * Use the nodset-cache. 2020 */ 2021 ret = (xmlXPathObjectPtr) 2022 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2023 ret->type = XPATH_NODESET; 2024 ret->boolval = 0; 2025 if (val) { 2026 if ((ret->nodesetval->nodeMax == 0) || 2027 (val->type == XML_NAMESPACE_DECL)) 2028 { 2029 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2030 } else { 2031 ret->nodesetval->nodeTab[0] = val; 2032 ret->nodesetval->nodeNr = 1; 2033 } 2034 } 2035#ifdef XP_DEBUG_OBJ_USAGE 2036 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2037#endif 2038 return(ret); 2039 } else if ((cache->miscObjs != NULL) && 2040 (cache->miscObjs->number != 0)) 2041 { 2042 xmlXPathObjectPtr ret; 2043 /* 2044 * Fallback to misc-cache. 2045 */ 2046 2047 ret = (xmlXPathObjectPtr) 2048 cache->miscObjs->items[--cache->miscObjs->number]; 2049 2050 ret->type = XPATH_NODESET; 2051 ret->boolval = 0; 2052 ret->nodesetval = xmlXPathNodeSetCreate(val); 2053#ifdef XP_DEBUG_OBJ_USAGE 2054 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2055#endif 2056 return(ret); 2057 } 2058 } 2059 return(xmlXPathNewNodeSet(val)); 2060} 2061 2062/** 2063 * xmlXPathCacheNewCString: 2064 * @ctxt: the XPath context 2065 * @val: the char * value 2066 * 2067 * This is the cached version of xmlXPathNewCString(). 2068 * Acquire an xmlXPathObjectPtr of type string and of value @val 2069 * 2070 * Returns the created or reused object. 2071 */ 2072static xmlXPathObjectPtr 2073xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2074{ 2075 if ((ctxt != NULL) && (ctxt->cache)) { 2076 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2077 2078 if ((cache->stringObjs != NULL) && 2079 (cache->stringObjs->number != 0)) 2080 { 2081 xmlXPathObjectPtr ret; 2082 2083 ret = (xmlXPathObjectPtr) 2084 cache->stringObjs->items[--cache->stringObjs->number]; 2085 2086 ret->type = XPATH_STRING; 2087 ret->stringval = xmlStrdup(BAD_CAST val); 2088#ifdef XP_DEBUG_OBJ_USAGE 2089 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2090#endif 2091 return(ret); 2092 } else if ((cache->miscObjs != NULL) && 2093 (cache->miscObjs->number != 0)) 2094 { 2095 xmlXPathObjectPtr ret; 2096 2097 ret = (xmlXPathObjectPtr) 2098 cache->miscObjs->items[--cache->miscObjs->number]; 2099 2100 ret->type = XPATH_STRING; 2101 ret->stringval = xmlStrdup(BAD_CAST val); 2102#ifdef XP_DEBUG_OBJ_USAGE 2103 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2104#endif 2105 return(ret); 2106 } 2107 } 2108 return(xmlXPathNewCString(val)); 2109} 2110 2111/** 2112 * xmlXPathCacheNewString: 2113 * @ctxt: the XPath context 2114 * @val: the xmlChar * value 2115 * 2116 * This is the cached version of xmlXPathNewString(). 2117 * Acquire an xmlXPathObjectPtr of type string and of value @val 2118 * 2119 * Returns the created or reused object. 2120 */ 2121static xmlXPathObjectPtr 2122xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2123{ 2124 if ((ctxt != NULL) && (ctxt->cache)) { 2125 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2126 2127 if ((cache->stringObjs != NULL) && 2128 (cache->stringObjs->number != 0)) 2129 { 2130 xmlXPathObjectPtr ret; 2131 2132 ret = (xmlXPathObjectPtr) 2133 cache->stringObjs->items[--cache->stringObjs->number]; 2134 ret->type = XPATH_STRING; 2135 if (val != NULL) 2136 ret->stringval = xmlStrdup(val); 2137 else 2138 ret->stringval = xmlStrdup((const xmlChar *)""); 2139#ifdef XP_DEBUG_OBJ_USAGE 2140 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2141#endif 2142 return(ret); 2143 } else if ((cache->miscObjs != NULL) && 2144 (cache->miscObjs->number != 0)) 2145 { 2146 xmlXPathObjectPtr ret; 2147 2148 ret = (xmlXPathObjectPtr) 2149 cache->miscObjs->items[--cache->miscObjs->number]; 2150 2151 ret->type = XPATH_STRING; 2152 if (val != NULL) 2153 ret->stringval = xmlStrdup(val); 2154 else 2155 ret->stringval = xmlStrdup((const xmlChar *)""); 2156#ifdef XP_DEBUG_OBJ_USAGE 2157 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2158#endif 2159 return(ret); 2160 } 2161 } 2162 return(xmlXPathNewString(val)); 2163} 2164 2165/** 2166 * xmlXPathCacheNewBoolean: 2167 * @ctxt: the XPath context 2168 * @val: the boolean value 2169 * 2170 * This is the cached version of xmlXPathNewBoolean(). 2171 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2172 * 2173 * Returns the created or reused object. 2174 */ 2175static xmlXPathObjectPtr 2176xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2177{ 2178 if ((ctxt != NULL) && (ctxt->cache)) { 2179 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2180 2181 if ((cache->booleanObjs != NULL) && 2182 (cache->booleanObjs->number != 0)) 2183 { 2184 xmlXPathObjectPtr ret; 2185 2186 ret = (xmlXPathObjectPtr) 2187 cache->booleanObjs->items[--cache->booleanObjs->number]; 2188 ret->type = XPATH_BOOLEAN; 2189 ret->boolval = (val != 0); 2190#ifdef XP_DEBUG_OBJ_USAGE 2191 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2192#endif 2193 return(ret); 2194 } else if ((cache->miscObjs != NULL) && 2195 (cache->miscObjs->number != 0)) 2196 { 2197 xmlXPathObjectPtr ret; 2198 2199 ret = (xmlXPathObjectPtr) 2200 cache->miscObjs->items[--cache->miscObjs->number]; 2201 2202 ret->type = XPATH_BOOLEAN; 2203 ret->boolval = (val != 0); 2204#ifdef XP_DEBUG_OBJ_USAGE 2205 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2206#endif 2207 return(ret); 2208 } 2209 } 2210 return(xmlXPathNewBoolean(val)); 2211} 2212 2213/** 2214 * xmlXPathCacheNewFloat: 2215 * @ctxt: the XPath context 2216 * @val: the double value 2217 * 2218 * This is the cached version of xmlXPathNewFloat(). 2219 * Acquires an xmlXPathObjectPtr of type double and of value @val 2220 * 2221 * Returns the created or reused object. 2222 */ 2223static xmlXPathObjectPtr 2224xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2225{ 2226 if ((ctxt != NULL) && (ctxt->cache)) { 2227 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2228 2229 if ((cache->numberObjs != NULL) && 2230 (cache->numberObjs->number != 0)) 2231 { 2232 xmlXPathObjectPtr ret; 2233 2234 ret = (xmlXPathObjectPtr) 2235 cache->numberObjs->items[--cache->numberObjs->number]; 2236 ret->type = XPATH_NUMBER; 2237 ret->floatval = val; 2238#ifdef XP_DEBUG_OBJ_USAGE 2239 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2240#endif 2241 return(ret); 2242 } else if ((cache->miscObjs != NULL) && 2243 (cache->miscObjs->number != 0)) 2244 { 2245 xmlXPathObjectPtr ret; 2246 2247 ret = (xmlXPathObjectPtr) 2248 cache->miscObjs->items[--cache->miscObjs->number]; 2249 2250 ret->type = XPATH_NUMBER; 2251 ret->floatval = val; 2252#ifdef XP_DEBUG_OBJ_USAGE 2253 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2254#endif 2255 return(ret); 2256 } 2257 } 2258 return(xmlXPathNewFloat(val)); 2259} 2260 2261/** 2262 * xmlXPathCacheConvertString: 2263 * @ctxt: the XPath context 2264 * @val: an XPath object 2265 * 2266 * This is the cached version of xmlXPathConvertString(). 2267 * Converts an existing object to its string() equivalent 2268 * 2269 * Returns a created or reused object, the old one is freed (cached) 2270 * (or the operation is done directly on @val) 2271 */ 2272 2273static xmlXPathObjectPtr 2274xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2275 xmlChar *res = NULL; 2276 2277 if (val == NULL) 2278 return(xmlXPathCacheNewCString(ctxt, "")); 2279 2280 switch (val->type) { 2281 case XPATH_UNDEFINED: 2282#ifdef DEBUG_EXPR 2283 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2284#endif 2285 break; 2286 case XPATH_NODESET: 2287 case XPATH_XSLT_TREE: 2288 res = xmlXPathCastNodeSetToString(val->nodesetval); 2289 break; 2290 case XPATH_STRING: 2291 return(val); 2292 case XPATH_BOOLEAN: 2293 res = xmlXPathCastBooleanToString(val->boolval); 2294 break; 2295 case XPATH_NUMBER: 2296 res = xmlXPathCastNumberToString(val->floatval); 2297 break; 2298 case XPATH_USERS: 2299 case XPATH_POINT: 2300 case XPATH_RANGE: 2301 case XPATH_LOCATIONSET: 2302 TODO; 2303 break; 2304 } 2305 xmlXPathReleaseObject(ctxt, val); 2306 if (res == NULL) 2307 return(xmlXPathCacheNewCString(ctxt, "")); 2308 return(xmlXPathCacheWrapString(ctxt, res)); 2309} 2310 2311/** 2312 * xmlXPathCacheObjectCopy: 2313 * @ctxt: the XPath context 2314 * @val: the original object 2315 * 2316 * This is the cached version of xmlXPathObjectCopy(). 2317 * Acquire a copy of a given object 2318 * 2319 * Returns a created or reused created object. 2320 */ 2321static xmlXPathObjectPtr 2322xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2323{ 2324 if (val == NULL) 2325 return(NULL); 2326 2327 if (XP_HAS_CACHE(ctxt)) { 2328 switch (val->type) { 2329 case XPATH_NODESET: 2330 return(xmlXPathCacheWrapNodeSet(ctxt, 2331 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2332 case XPATH_STRING: 2333 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2334 case XPATH_BOOLEAN: 2335 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2336 case XPATH_NUMBER: 2337 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2338 default: 2339 break; 2340 } 2341 } 2342 return(xmlXPathObjectCopy(val)); 2343} 2344 2345/** 2346 * xmlXPathCacheConvertBoolean: 2347 * @ctxt: the XPath context 2348 * @val: an XPath object 2349 * 2350 * This is the cached version of xmlXPathConvertBoolean(). 2351 * Converts an existing object to its boolean() equivalent 2352 * 2353 * Returns a created or reused object, the old one is freed (or the operation 2354 * is done directly on @val) 2355 */ 2356static xmlXPathObjectPtr 2357xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2358 xmlXPathObjectPtr ret; 2359 2360 if (val == NULL) 2361 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2362 if (val->type == XPATH_BOOLEAN) 2363 return(val); 2364 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2365 xmlXPathReleaseObject(ctxt, val); 2366 return(ret); 2367} 2368 2369/** 2370 * xmlXPathCacheConvertNumber: 2371 * @ctxt: the XPath context 2372 * @val: an XPath object 2373 * 2374 * This is the cached version of xmlXPathConvertNumber(). 2375 * Converts an existing object to its number() equivalent 2376 * 2377 * Returns a created or reused object, the old one is freed (or the operation 2378 * is done directly on @val) 2379 */ 2380static xmlXPathObjectPtr 2381xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2382 xmlXPathObjectPtr ret; 2383 2384 if (val == NULL) 2385 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2386 if (val->type == XPATH_NUMBER) 2387 return(val); 2388 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2389 xmlXPathReleaseObject(ctxt, val); 2390 return(ret); 2391} 2392 2393/************************************************************************ 2394 * * 2395 * Parser stacks related functions and macros * 2396 * * 2397 ************************************************************************/ 2398 2399/** 2400 * valuePop: 2401 * @ctxt: an XPath evaluation context 2402 * 2403 * Pops the top XPath object from the value stack 2404 * 2405 * Returns the XPath object just removed 2406 */ 2407xmlXPathObjectPtr 2408valuePop(xmlXPathParserContextPtr ctxt) 2409{ 2410 xmlXPathObjectPtr ret; 2411 2412 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2413 return (NULL); 2414 ctxt->valueNr--; 2415 if (ctxt->valueNr > 0) 2416 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2417 else 2418 ctxt->value = NULL; 2419 ret = ctxt->valueTab[ctxt->valueNr]; 2420 ctxt->valueTab[ctxt->valueNr] = NULL; 2421 return (ret); 2422} 2423/** 2424 * valuePush: 2425 * @ctxt: an XPath evaluation context 2426 * @value: the XPath object 2427 * 2428 * Pushes a new XPath object on top of the value stack 2429 * 2430 * returns the number of items on the value stack 2431 */ 2432int 2433valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2434{ 2435 if ((ctxt == NULL) || (value == NULL)) return(-1); 2436 if (ctxt->valueNr >= ctxt->valueMax) { 2437 xmlXPathObjectPtr *tmp; 2438 2439 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2440 2 * ctxt->valueMax * 2441 sizeof(ctxt->valueTab[0])); 2442 if (tmp == NULL) { 2443 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 2444 return (0); 2445 } 2446 ctxt->valueMax *= 2; 2447 ctxt->valueTab = tmp; 2448 } 2449 ctxt->valueTab[ctxt->valueNr] = value; 2450 ctxt->value = value; 2451 return (ctxt->valueNr++); 2452} 2453 2454/** 2455 * xmlXPathPopBoolean: 2456 * @ctxt: an XPath parser context 2457 * 2458 * Pops a boolean from the stack, handling conversion if needed. 2459 * Check error with #xmlXPathCheckError. 2460 * 2461 * Returns the boolean 2462 */ 2463int 2464xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2465 xmlXPathObjectPtr obj; 2466 int ret; 2467 2468 obj = valuePop(ctxt); 2469 if (obj == NULL) { 2470 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2471 return(0); 2472 } 2473 if (obj->type != XPATH_BOOLEAN) 2474 ret = xmlXPathCastToBoolean(obj); 2475 else 2476 ret = obj->boolval; 2477 xmlXPathReleaseObject(ctxt->context, obj); 2478 return(ret); 2479} 2480 2481/** 2482 * xmlXPathPopNumber: 2483 * @ctxt: an XPath parser context 2484 * 2485 * Pops a number from the stack, handling conversion if needed. 2486 * Check error with #xmlXPathCheckError. 2487 * 2488 * Returns the number 2489 */ 2490double 2491xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2492 xmlXPathObjectPtr obj; 2493 double ret; 2494 2495 obj = valuePop(ctxt); 2496 if (obj == NULL) { 2497 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2498 return(0); 2499 } 2500 if (obj->type != XPATH_NUMBER) 2501 ret = xmlXPathCastToNumber(obj); 2502 else 2503 ret = obj->floatval; 2504 xmlXPathReleaseObject(ctxt->context, obj); 2505 return(ret); 2506} 2507 2508/** 2509 * xmlXPathPopString: 2510 * @ctxt: an XPath parser context 2511 * 2512 * Pops a string from the stack, handling conversion if needed. 2513 * Check error with #xmlXPathCheckError. 2514 * 2515 * Returns the string 2516 */ 2517xmlChar * 2518xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2519 xmlXPathObjectPtr obj; 2520 xmlChar * ret; 2521 2522 obj = valuePop(ctxt); 2523 if (obj == NULL) { 2524 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2525 return(NULL); 2526 } 2527 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2528 /* TODO: needs refactoring somewhere else */ 2529 if (obj->stringval == ret) 2530 obj->stringval = NULL; 2531 xmlXPathReleaseObject(ctxt->context, obj); 2532 return(ret); 2533} 2534 2535/** 2536 * xmlXPathPopNodeSet: 2537 * @ctxt: an XPath parser context 2538 * 2539 * Pops a node-set from the stack, handling conversion if needed. 2540 * Check error with #xmlXPathCheckError. 2541 * 2542 * Returns the node-set 2543 */ 2544xmlNodeSetPtr 2545xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 2546 xmlXPathObjectPtr obj; 2547 xmlNodeSetPtr ret; 2548 2549 if (ctxt == NULL) return(NULL); 2550 if (ctxt->value == NULL) { 2551 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2552 return(NULL); 2553 } 2554 if (!xmlXPathStackIsNodeSet(ctxt)) { 2555 xmlXPathSetTypeError(ctxt); 2556 return(NULL); 2557 } 2558 obj = valuePop(ctxt); 2559 ret = obj->nodesetval; 2560#if 0 2561 /* to fix memory leak of not clearing obj->user */ 2562 if (obj->boolval && obj->user != NULL) 2563 xmlFreeNodeList((xmlNodePtr) obj->user); 2564#endif 2565 obj->nodesetval = NULL; 2566 xmlXPathReleaseObject(ctxt->context, obj); 2567 return(ret); 2568} 2569 2570/** 2571 * xmlXPathPopExternal: 2572 * @ctxt: an XPath parser context 2573 * 2574 * Pops an external object from the stack, handling conversion if needed. 2575 * Check error with #xmlXPathCheckError. 2576 * 2577 * Returns the object 2578 */ 2579void * 2580xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 2581 xmlXPathObjectPtr obj; 2582 void * ret; 2583 2584 if ((ctxt == NULL) || (ctxt->value == NULL)) { 2585 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2586 return(NULL); 2587 } 2588 if (ctxt->value->type != XPATH_USERS) { 2589 xmlXPathSetTypeError(ctxt); 2590 return(NULL); 2591 } 2592 obj = valuePop(ctxt); 2593 ret = obj->user; 2594 obj->user = NULL; 2595 xmlXPathReleaseObject(ctxt->context, obj); 2596 return(ret); 2597} 2598 2599/* 2600 * Macros for accessing the content. Those should be used only by the parser, 2601 * and not exported. 2602 * 2603 * Dirty macros, i.e. one need to make assumption on the context to use them 2604 * 2605 * CUR_PTR return the current pointer to the xmlChar to be parsed. 2606 * CUR returns the current xmlChar value, i.e. a 8 bit value 2607 * in ISO-Latin or UTF-8. 2608 * This should be used internally by the parser 2609 * only to compare to ASCII values otherwise it would break when 2610 * running with UTF-8 encoding. 2611 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 2612 * to compare on ASCII based substring. 2613 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 2614 * strings within the parser. 2615 * CURRENT Returns the current char value, with the full decoding of 2616 * UTF-8 if we are using this mode. It returns an int. 2617 * NEXT Skip to the next character, this does the proper decoding 2618 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 2619 * It returns the pointer to the current xmlChar. 2620 */ 2621 2622#define CUR (*ctxt->cur) 2623#define SKIP(val) ctxt->cur += (val) 2624#define NXT(val) ctxt->cur[(val)] 2625#define CUR_PTR ctxt->cur 2626#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 2627 2628#define COPY_BUF(l,b,i,v) \ 2629 if (l == 1) b[i++] = (xmlChar) v; \ 2630 else i += xmlCopyChar(l,&b[i],v) 2631 2632#define NEXTL(l) ctxt->cur += l 2633 2634#define SKIP_BLANKS \ 2635 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 2636 2637#define CURRENT (*ctxt->cur) 2638#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 2639 2640 2641#ifndef DBL_DIG 2642#define DBL_DIG 16 2643#endif 2644#ifndef DBL_EPSILON 2645#define DBL_EPSILON 1E-9 2646#endif 2647 2648#define UPPER_DOUBLE 1E9 2649#define LOWER_DOUBLE 1E-5 2650 2651#define INTEGER_DIGITS DBL_DIG 2652#define FRACTION_DIGITS (DBL_DIG + 1) 2653#define EXPONENT_DIGITS (3 + 2) 2654 2655/** 2656 * xmlXPathFormatNumber: 2657 * @number: number to format 2658 * @buffer: output buffer 2659 * @buffersize: size of output buffer 2660 * 2661 * Convert the number into a string representation. 2662 */ 2663static void 2664xmlXPathFormatNumber(double number, char buffer[], int buffersize) 2665{ 2666 switch (xmlXPathIsInf(number)) { 2667 case 1: 2668 if (buffersize > (int)sizeof("Infinity")) 2669 snprintf(buffer, buffersize, "Infinity"); 2670 break; 2671 case -1: 2672 if (buffersize > (int)sizeof("-Infinity")) 2673 snprintf(buffer, buffersize, "-Infinity"); 2674 break; 2675 default: 2676 if (xmlXPathIsNaN(number)) { 2677 if (buffersize > (int)sizeof("NaN")) 2678 snprintf(buffer, buffersize, "NaN"); 2679 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 2680 snprintf(buffer, buffersize, "0"); 2681 } else if (number == ((int) number)) { 2682 char work[30]; 2683 char *ptr, *cur; 2684 int value = (int) number; 2685 2686 ptr = &buffer[0]; 2687 if (value == 0) { 2688 *ptr++ = '0'; 2689 } else { 2690 snprintf(work, 29, "%d", value); 2691 cur = &work[0]; 2692 while ((*cur) && (ptr - buffer < buffersize)) { 2693 *ptr++ = *cur++; 2694 } 2695 } 2696 if (ptr - buffer < buffersize) { 2697 *ptr = 0; 2698 } else if (buffersize > 0) { 2699 ptr--; 2700 *ptr = 0; 2701 } 2702 } else { 2703 /* 3 is sign, decimal point, and terminating zero */ 2704 char work[DBL_DIG + EXPONENT_DIGITS + 3]; 2705 int integer_place, fraction_place; 2706 char *ptr; 2707 char *after_fraction; 2708 double absolute_value; 2709 int size; 2710 2711 absolute_value = fabs(number); 2712 2713 /* 2714 * First choose format - scientific or regular floating point. 2715 * In either case, result is in work, and after_fraction points 2716 * just past the fractional part. 2717 */ 2718 if ( ((absolute_value > UPPER_DOUBLE) || 2719 (absolute_value < LOWER_DOUBLE)) && 2720 (absolute_value != 0.0) ) { 2721 /* Use scientific notation */ 2722 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 2723 fraction_place = DBL_DIG - 1; 2724 size = snprintf(work, sizeof(work),"%*.*e", 2725 integer_place, fraction_place, number); 2726 while ((size > 0) && (work[size] != 'e')) size--; 2727 after_fraction = work + size; 2728 2729 } 2730 else { 2731 /* Use regular notation */ 2732 if (absolute_value > 0.0) 2733 integer_place = 1 + (int)log10(absolute_value); 2734 else 2735 integer_place = 0; 2736 fraction_place = (integer_place > 0) 2737 ? DBL_DIG - integer_place 2738 : DBL_DIG; 2739 size = snprintf(work, sizeof(work), "%0.*f", 2740 fraction_place, number); 2741 after_fraction = work + size; 2742 } 2743 2744 /* Remove fractional trailing zeroes */ 2745 ptr = after_fraction; 2746 while (*(--ptr) == '0') 2747 ; 2748 if (*ptr != '.') 2749 ptr++; 2750 while ((*ptr++ = *after_fraction++) != 0); 2751 2752 /* Finally copy result back to caller */ 2753 size = strlen(work) + 1; 2754 if (size > buffersize) { 2755 work[buffersize - 1] = 0; 2756 size = buffersize; 2757 } 2758 memmove(buffer, work, size); 2759 } 2760 break; 2761 } 2762} 2763 2764 2765/************************************************************************ 2766 * * 2767 * Routines to handle NodeSets * 2768 * * 2769 ************************************************************************/ 2770 2771/** 2772 * xmlXPathOrderDocElems: 2773 * @doc: an input document 2774 * 2775 * Call this routine to speed up XPath computation on static documents. 2776 * This stamps all the element nodes with the document order 2777 * Like for line information, the order is kept in the element->content 2778 * field, the value stored is actually - the node number (starting at -1) 2779 * to be able to differentiate from line numbers. 2780 * 2781 * Returns the number of elements found in the document or -1 in case 2782 * of error. 2783 */ 2784long 2785xmlXPathOrderDocElems(xmlDocPtr doc) { 2786 long count = 0; 2787 xmlNodePtr cur; 2788 2789 if (doc == NULL) 2790 return(-1); 2791 cur = doc->children; 2792 while (cur != NULL) { 2793 if (cur->type == XML_ELEMENT_NODE) { 2794 cur->content = (void *) (-(++count)); 2795 if (cur->children != NULL) { 2796 cur = cur->children; 2797 continue; 2798 } 2799 } 2800 if (cur->next != NULL) { 2801 cur = cur->next; 2802 continue; 2803 } 2804 do { 2805 cur = cur->parent; 2806 if (cur == NULL) 2807 break; 2808 if (cur == (xmlNodePtr) doc) { 2809 cur = NULL; 2810 break; 2811 } 2812 if (cur->next != NULL) { 2813 cur = cur->next; 2814 break; 2815 } 2816 } while (cur != NULL); 2817 } 2818 return(count); 2819} 2820 2821/** 2822 * xmlXPathCmpNodes: 2823 * @node1: the first node 2824 * @node2: the second node 2825 * 2826 * Compare two nodes w.r.t document order 2827 * 2828 * Returns -2 in case of error 1 if first point < second point, 0 if 2829 * it's the same node, -1 otherwise 2830 */ 2831int 2832xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 2833 int depth1, depth2; 2834 int attr1 = 0, attr2 = 0; 2835 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 2836 xmlNodePtr cur, root; 2837 2838 if ((node1 == NULL) || (node2 == NULL)) 2839 return(-2); 2840 /* 2841 * a couple of optimizations which will avoid computations in most cases 2842 */ 2843 if (node1->type == XML_ATTRIBUTE_NODE) { 2844 attr1 = 1; 2845 attrNode1 = node1; 2846 node1 = node1->parent; 2847 } 2848 if (node2->type == XML_ATTRIBUTE_NODE) { 2849 attr2 = 1; 2850 attrNode2 = node2; 2851 node2 = node2->parent; 2852 } 2853 if (node1 == node2) { 2854 if (attr1 == attr2) { 2855 /* not required, but we keep attributes in order */ 2856 if (attr1 != 0) { 2857 cur = attrNode2->prev; 2858 while (cur != NULL) { 2859 if (cur == attrNode1) 2860 return (1); 2861 cur = cur->prev; 2862 } 2863 return (-1); 2864 } 2865 return(0); 2866 } 2867 if (attr2 == 1) 2868 return(1); 2869 return(-1); 2870 } 2871 if ((node1->type == XML_NAMESPACE_DECL) || 2872 (node2->type == XML_NAMESPACE_DECL)) 2873 return(1); 2874 if (node1 == node2->prev) 2875 return(1); 2876 if (node1 == node2->next) 2877 return(-1); 2878 2879 /* 2880 * Speedup using document order if availble. 2881 */ 2882 if ((node1->type == XML_ELEMENT_NODE) && 2883 (node2->type == XML_ELEMENT_NODE) && 2884 (0 > (long) node1->content) && 2885 (0 > (long) node2->content) && 2886 (node1->doc == node2->doc)) { 2887 long l1, l2; 2888 2889 l1 = -((long) node1->content); 2890 l2 = -((long) node2->content); 2891 if (l1 < l2) 2892 return(1); 2893 if (l1 > l2) 2894 return(-1); 2895 } 2896 2897 /* 2898 * compute depth to root 2899 */ 2900 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 2901 if (cur == node1) 2902 return(1); 2903 depth2++; 2904 } 2905 root = cur; 2906 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 2907 if (cur == node2) 2908 return(-1); 2909 depth1++; 2910 } 2911 /* 2912 * Distinct document (or distinct entities :-( ) case. 2913 */ 2914 if (root != cur) { 2915 return(-2); 2916 } 2917 /* 2918 * get the nearest common ancestor. 2919 */ 2920 while (depth1 > depth2) { 2921 depth1--; 2922 node1 = node1->parent; 2923 } 2924 while (depth2 > depth1) { 2925 depth2--; 2926 node2 = node2->parent; 2927 } 2928 while (node1->parent != node2->parent) { 2929 node1 = node1->parent; 2930 node2 = node2->parent; 2931 /* should not happen but just in case ... */ 2932 if ((node1 == NULL) || (node2 == NULL)) 2933 return(-2); 2934 } 2935 /* 2936 * Find who's first. 2937 */ 2938 if (node1 == node2->prev) 2939 return(1); 2940 if (node1 == node2->next) 2941 return(-1); 2942 /* 2943 * Speedup using document order if availble. 2944 */ 2945 if ((node1->type == XML_ELEMENT_NODE) && 2946 (node2->type == XML_ELEMENT_NODE) && 2947 (0 > (long) node1->content) && 2948 (0 > (long) node2->content) && 2949 (node1->doc == node2->doc)) { 2950 long l1, l2; 2951 2952 l1 = -((long) node1->content); 2953 l2 = -((long) node2->content); 2954 if (l1 < l2) 2955 return(1); 2956 if (l1 > l2) 2957 return(-1); 2958 } 2959 2960 for (cur = node1->next;cur != NULL;cur = cur->next) 2961 if (cur == node2) 2962 return(1); 2963 return(-1); /* assume there is no sibling list corruption */ 2964} 2965 2966#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 2967/** 2968 * xmlXPathCmpNodesExt: 2969 * @node1: the first node 2970 * @node2: the second node 2971 * 2972 * Compare two nodes w.r.t document order. 2973 * This one is optimized for handling of non-element nodes. 2974 * 2975 * Returns -2 in case of error 1 if first point < second point, 0 if 2976 * it's the same node, -1 otherwise 2977 */ 2978static int 2979xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 2980 int depth1, depth2; 2981 int misc = 0, precedence1 = 0, precedence2 = 0; 2982 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 2983 xmlNodePtr cur, root; 2984 long l1, l2; 2985 2986 if ((node1 == NULL) || (node2 == NULL)) 2987 return(-2); 2988 2989 if (node1 == node2) 2990 return(0); 2991 2992 /* 2993 * a couple of optimizations which will avoid computations in most cases 2994 */ 2995 switch (node1->type) { 2996 case XML_ELEMENT_NODE: 2997 if (node2->type == XML_ELEMENT_NODE) { 2998 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */ 2999 (0 > (long) node2->content) && 3000 (node1->doc == node2->doc)) 3001 { 3002 l1 = -((long) node1->content); 3003 l2 = -((long) node2->content); 3004 if (l1 < l2) 3005 return(1); 3006 if (l1 > l2) 3007 return(-1); 3008 } else 3009 goto turtle_comparison; 3010 } 3011 break; 3012 case XML_ATTRIBUTE_NODE: 3013 precedence1 = 1; /* element is owner */ 3014 miscNode1 = node1; 3015 node1 = node1->parent; 3016 misc = 1; 3017 break; 3018 case XML_TEXT_NODE: 3019 case XML_CDATA_SECTION_NODE: 3020 case XML_COMMENT_NODE: 3021 case XML_PI_NODE: { 3022 miscNode1 = node1; 3023 /* 3024 * Find nearest element node. 3025 */ 3026 if (node1->prev != NULL) { 3027 do { 3028 node1 = node1->prev; 3029 if (node1->type == XML_ELEMENT_NODE) { 3030 precedence1 = 3; /* element in prev-sibl axis */ 3031 break; 3032 } 3033 if (node1->prev == NULL) { 3034 precedence1 = 2; /* element is parent */ 3035 /* 3036 * URGENT TODO: Are there any cases, where the 3037 * parent of such a node is not an element node? 3038 */ 3039 node1 = node1->parent; 3040 break; 3041 } 3042 } while (1); 3043 } else { 3044 precedence1 = 2; /* element is parent */ 3045 node1 = node1->parent; 3046 } 3047 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) { 3048 /* 3049 * Fallback for whatever case. 3050 */ 3051 node1 = miscNode1; 3052 precedence1 = 0; 3053 } else 3054 misc = 1; 3055 } 3056 break; 3057 case XML_NAMESPACE_DECL: 3058 /* 3059 * TODO: why do we return 1 for namespace nodes? 3060 */ 3061 return(1); 3062 default: 3063 break; 3064 } 3065 switch (node2->type) { 3066 case XML_ELEMENT_NODE: 3067 break; 3068 case XML_ATTRIBUTE_NODE: 3069 precedence2 = 1; /* element is owner */ 3070 miscNode2 = node2; 3071 node2 = node2->parent; 3072 misc = 1; 3073 break; 3074 case XML_TEXT_NODE: 3075 case XML_CDATA_SECTION_NODE: 3076 case XML_COMMENT_NODE: 3077 case XML_PI_NODE: { 3078 miscNode2 = node2; 3079 if (node2->prev != NULL) { 3080 do { 3081 node2 = node2->prev; 3082 if (node2->type == XML_ELEMENT_NODE) { 3083 precedence2 = 3; /* element in prev-sibl axis */ 3084 break; 3085 } 3086 if (node2->prev == NULL) { 3087 precedence2 = 2; /* element is parent */ 3088 node2 = node2->parent; 3089 break; 3090 } 3091 } while (1); 3092 } else { 3093 precedence2 = 2; /* element is parent */ 3094 node2 = node2->parent; 3095 } 3096 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 3097 (0 <= (long) node1->content)) 3098 { 3099 node2 = miscNode2; 3100 precedence2 = 0; 3101 } else 3102 misc = 1; 3103 } 3104 break; 3105 case XML_NAMESPACE_DECL: 3106 return(1); 3107 default: 3108 break; 3109 } 3110 if (misc) { 3111 if (node1 == node2) { 3112 if (precedence1 == precedence2) { 3113 /* 3114 * The ugly case; but normally there aren't many 3115 * adjacent non-element nodes around. 3116 */ 3117 cur = miscNode2->prev; 3118 while (cur != NULL) { 3119 if (cur == miscNode1) 3120 return(1); 3121 if (cur->type == XML_ELEMENT_NODE) 3122 return(-1); 3123 cur = cur->prev; 3124 } 3125 return (-1); 3126 } else { 3127 /* 3128 * Evaluate based on higher precedence wrt to the element. 3129 * TODO: This assumes attributes are sorted before content. 3130 * Is this 100% correct? 3131 */ 3132 if (precedence1 < precedence2) 3133 return(1); 3134 else 3135 return(-1); 3136 } 3137 } 3138 /* 3139 * Special case: One of the helper-elements is contained by the other. 3140 * <foo> 3141 * <node2> 3142 * <node1>Text-1(precedence1 == 2)</node1> 3143 * </node2> 3144 * Text-6(precedence2 == 3) 3145 * </foo> 3146 */ 3147 if ((precedence2 == 3) && (precedence1 > 1)) { 3148 cur = node1->parent; 3149 while (cur) { 3150 if (cur == node2) 3151 return(1); 3152 cur = cur->parent; 3153 } 3154 } 3155 if ((precedence1 == 3) && (precedence2 > 1)) { 3156 cur = node2->parent; 3157 while (cur) { 3158 if (cur == node1) 3159 return(-1); 3160 cur = cur->parent; 3161 } 3162 } 3163 } 3164 3165 /* 3166 * Speedup using document order if availble. 3167 */ 3168 if ((node1->type == XML_ELEMENT_NODE) && 3169 (node2->type == XML_ELEMENT_NODE) && 3170 (0 > (long) node1->content) && 3171 (0 > (long) node2->content) && 3172 (node1->doc == node2->doc)) { 3173 3174 l1 = -((long) node1->content); 3175 l2 = -((long) node2->content); 3176 if (l1 < l2) 3177 return(1); 3178 if (l1 > l2) 3179 return(-1); 3180 } 3181 3182turtle_comparison: 3183 3184 if (node1 == node2->prev) 3185 return(1); 3186 if (node1 == node2->next) 3187 return(-1); 3188 /* 3189 * compute depth to root 3190 */ 3191 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3192 if (cur == node1) 3193 return(1); 3194 depth2++; 3195 } 3196 root = cur; 3197 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3198 if (cur == node2) 3199 return(-1); 3200 depth1++; 3201 } 3202 /* 3203 * Distinct document (or distinct entities :-( ) case. 3204 */ 3205 if (root != cur) { 3206 return(-2); 3207 } 3208 /* 3209 * get the nearest common ancestor. 3210 */ 3211 while (depth1 > depth2) { 3212 depth1--; 3213 node1 = node1->parent; 3214 } 3215 while (depth2 > depth1) { 3216 depth2--; 3217 node2 = node2->parent; 3218 } 3219 while (node1->parent != node2->parent) { 3220 node1 = node1->parent; 3221 node2 = node2->parent; 3222 /* should not happen but just in case ... */ 3223 if ((node1 == NULL) || (node2 == NULL)) 3224 return(-2); 3225 } 3226 /* 3227 * Find who's first. 3228 */ 3229 if (node1 == node2->prev) 3230 return(1); 3231 if (node1 == node2->next) 3232 return(-1); 3233 /* 3234 * Speedup using document order if availble. 3235 */ 3236 if ((node1->type == XML_ELEMENT_NODE) && 3237 (node2->type == XML_ELEMENT_NODE) && 3238 (0 > (long) node1->content) && 3239 (0 > (long) node2->content) && 3240 (node1->doc == node2->doc)) { 3241 3242 l1 = -((long) node1->content); 3243 l2 = -((long) node2->content); 3244 if (l1 < l2) 3245 return(1); 3246 if (l1 > l2) 3247 return(-1); 3248 } 3249 3250 for (cur = node1->next;cur != NULL;cur = cur->next) 3251 if (cur == node2) 3252 return(1); 3253 return(-1); /* assume there is no sibling list corruption */ 3254} 3255#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 3256 3257/** 3258 * xmlXPathNodeSetSort: 3259 * @set: the node set 3260 * 3261 * Sort the node set in document order 3262 */ 3263void 3264xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3265 int i, j, incr, len; 3266 xmlNodePtr tmp; 3267 3268 if (set == NULL) 3269 return; 3270 3271 /* Use Shell's sort to sort the node-set */ 3272 len = set->nodeNr; 3273 for (incr = len / 2; incr > 0; incr /= 2) { 3274 for (i = incr; i < len; i++) { 3275 j = i - incr; 3276 while (j >= 0) { 3277#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3278 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3279 set->nodeTab[j + incr]) == -1) 3280#else 3281 if (xmlXPathCmpNodes(set->nodeTab[j], 3282 set->nodeTab[j + incr]) == -1) 3283#endif 3284 { 3285 tmp = set->nodeTab[j]; 3286 set->nodeTab[j] = set->nodeTab[j + incr]; 3287 set->nodeTab[j + incr] = tmp; 3288 j -= incr; 3289 } else 3290 break; 3291 } 3292 } 3293 } 3294} 3295 3296#define XML_NODESET_DEFAULT 10 3297/** 3298 * xmlXPathNodeSetDupNs: 3299 * @node: the parent node of the namespace XPath node 3300 * @ns: the libxml namespace declaration node. 3301 * 3302 * Namespace node in libxml don't match the XPath semantic. In a node set 3303 * the namespace nodes are duplicated and the next pointer is set to the 3304 * parent node in the XPath semantic. 3305 * 3306 * Returns the newly created object. 3307 */ 3308static xmlNodePtr 3309xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3310 xmlNsPtr cur; 3311 3312 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3313 return(NULL); 3314 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3315 return((xmlNodePtr) ns); 3316 3317 /* 3318 * Allocate a new Namespace and fill the fields. 3319 */ 3320 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3321 if (cur == NULL) { 3322 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3323 return(NULL); 3324 } 3325 memset(cur, 0, sizeof(xmlNs)); 3326 cur->type = XML_NAMESPACE_DECL; 3327 if (ns->href != NULL) 3328 cur->href = xmlStrdup(ns->href); 3329 if (ns->prefix != NULL) 3330 cur->prefix = xmlStrdup(ns->prefix); 3331 cur->next = (xmlNsPtr) node; 3332 return((xmlNodePtr) cur); 3333} 3334 3335/** 3336 * xmlXPathNodeSetFreeNs: 3337 * @ns: the XPath namespace node found in a nodeset. 3338 * 3339 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3340 * the namespace nodes are duplicated and the next pointer is set to the 3341 * parent node in the XPath semantic. Check if such a node needs to be freed 3342 */ 3343void 3344xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3345 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3346 return; 3347 3348 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3349 if (ns->href != NULL) 3350 xmlFree((xmlChar *)ns->href); 3351 if (ns->prefix != NULL) 3352 xmlFree((xmlChar *)ns->prefix); 3353 xmlFree(ns); 3354 } 3355} 3356 3357/** 3358 * xmlXPathNodeSetCreate: 3359 * @val: an initial xmlNodePtr, or NULL 3360 * 3361 * Create a new xmlNodeSetPtr of type double and of value @val 3362 * 3363 * Returns the newly created object. 3364 */ 3365xmlNodeSetPtr 3366xmlXPathNodeSetCreate(xmlNodePtr val) { 3367 xmlNodeSetPtr ret; 3368 3369 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3370 if (ret == NULL) { 3371 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3372 return(NULL); 3373 } 3374 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3375 if (val != NULL) { 3376 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3377 sizeof(xmlNodePtr)); 3378 if (ret->nodeTab == NULL) { 3379 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3380 xmlFree(ret); 3381 return(NULL); 3382 } 3383 memset(ret->nodeTab, 0 , 3384 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3385 ret->nodeMax = XML_NODESET_DEFAULT; 3386 if (val->type == XML_NAMESPACE_DECL) { 3387 xmlNsPtr ns = (xmlNsPtr) val; 3388 3389 ret->nodeTab[ret->nodeNr++] = 3390 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3391 } else 3392 ret->nodeTab[ret->nodeNr++] = val; 3393 } 3394 return(ret); 3395} 3396 3397/** 3398 * xmlXPathNodeSetCreateSize: 3399 * @size: the initial size of the set 3400 * 3401 * Create a new xmlNodeSetPtr of type double and of value @val 3402 * 3403 * Returns the newly created object. 3404 */ 3405static xmlNodeSetPtr 3406xmlXPathNodeSetCreateSize(int size) { 3407 xmlNodeSetPtr ret; 3408 3409 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3410 if (ret == NULL) { 3411 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3412 return(NULL); 3413 } 3414 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3415 if (size < XML_NODESET_DEFAULT) 3416 size = XML_NODESET_DEFAULT; 3417 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr)); 3418 if (ret->nodeTab == NULL) { 3419 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3420 xmlFree(ret); 3421 return(NULL); 3422 } 3423 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr)); 3424 ret->nodeMax = size; 3425 return(ret); 3426} 3427 3428/** 3429 * xmlXPathNodeSetContains: 3430 * @cur: the node-set 3431 * @val: the node 3432 * 3433 * checks whether @cur contains @val 3434 * 3435 * Returns true (1) if @cur contains @val, false (0) otherwise 3436 */ 3437int 3438xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3439 int i; 3440 3441 if ((cur == NULL) || (val == NULL)) return(0); 3442 if (val->type == XML_NAMESPACE_DECL) { 3443 for (i = 0; i < cur->nodeNr; i++) { 3444 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3445 xmlNsPtr ns1, ns2; 3446 3447 ns1 = (xmlNsPtr) val; 3448 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3449 if (ns1 == ns2) 3450 return(1); 3451 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3452 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3453 return(1); 3454 } 3455 } 3456 } else { 3457 for (i = 0; i < cur->nodeNr; i++) { 3458 if (cur->nodeTab[i] == val) 3459 return(1); 3460 } 3461 } 3462 return(0); 3463} 3464 3465/** 3466 * xmlXPathNodeSetAddNs: 3467 * @cur: the initial node set 3468 * @node: the hosting node 3469 * @ns: a the namespace node 3470 * 3471 * add a new namespace node to an existing NodeSet 3472 */ 3473void 3474xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3475 int i; 3476 3477 3478 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3479 (ns->type != XML_NAMESPACE_DECL) || 3480 (node->type != XML_ELEMENT_NODE)) 3481 return; 3482 3483 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3484 /* 3485 * prevent duplicates 3486 */ 3487 for (i = 0;i < cur->nodeNr;i++) { 3488 if ((cur->nodeTab[i] != NULL) && 3489 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3490 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3491 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3492 return; 3493 } 3494 3495 /* 3496 * grow the nodeTab if needed 3497 */ 3498 if (cur->nodeMax == 0) { 3499 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3500 sizeof(xmlNodePtr)); 3501 if (cur->nodeTab == NULL) { 3502 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3503 return; 3504 } 3505 memset(cur->nodeTab, 0 , 3506 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3507 cur->nodeMax = XML_NODESET_DEFAULT; 3508 } else if (cur->nodeNr == cur->nodeMax) { 3509 xmlNodePtr *temp; 3510 3511 cur->nodeMax *= 2; 3512 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3513 sizeof(xmlNodePtr)); 3514 if (temp == NULL) { 3515 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3516 return; 3517 } 3518 cur->nodeTab = temp; 3519 } 3520 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3521} 3522 3523/** 3524 * xmlXPathNodeSetAdd: 3525 * @cur: the initial node set 3526 * @val: a new xmlNodePtr 3527 * 3528 * add a new xmlNodePtr to an existing NodeSet 3529 */ 3530void 3531xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3532 int i; 3533 3534 if ((cur == NULL) || (val == NULL)) return; 3535 3536#if 0 3537 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3538 return; /* an XSLT fake node */ 3539#endif 3540 3541 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3542 /* 3543 * prevent duplcates 3544 */ 3545 for (i = 0;i < cur->nodeNr;i++) 3546 if (cur->nodeTab[i] == val) return; 3547 3548 /* 3549 * grow the nodeTab if needed 3550 */ 3551 if (cur->nodeMax == 0) { 3552 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3553 sizeof(xmlNodePtr)); 3554 if (cur->nodeTab == NULL) { 3555 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3556 return; 3557 } 3558 memset(cur->nodeTab, 0 , 3559 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3560 cur->nodeMax = XML_NODESET_DEFAULT; 3561 } else if (cur->nodeNr == cur->nodeMax) { 3562 xmlNodePtr *temp; 3563 3564 cur->nodeMax *= 2; 3565 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3566 sizeof(xmlNodePtr)); 3567 if (temp == NULL) { 3568 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3569 return; 3570 } 3571 cur->nodeTab = temp; 3572 } 3573 if (val->type == XML_NAMESPACE_DECL) { 3574 xmlNsPtr ns = (xmlNsPtr) val; 3575 3576 cur->nodeTab[cur->nodeNr++] = 3577 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3578 } else 3579 cur->nodeTab[cur->nodeNr++] = val; 3580} 3581 3582/** 3583 * xmlXPathNodeSetAddUnique: 3584 * @cur: the initial node set 3585 * @val: a new xmlNodePtr 3586 * 3587 * add a new xmlNodePtr to an existing NodeSet, optimized version 3588 * when we are sure the node is not already in the set. 3589 */ 3590void 3591xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3592 if ((cur == NULL) || (val == NULL)) return; 3593 3594#if 0 3595 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3596 return; /* an XSLT fake node */ 3597#endif 3598 3599 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3600 /* 3601 * grow the nodeTab if needed 3602 */ 3603 if (cur->nodeMax == 0) { 3604 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3605 sizeof(xmlNodePtr)); 3606 if (cur->nodeTab == NULL) { 3607 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3608 return; 3609 } 3610 memset(cur->nodeTab, 0 , 3611 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3612 cur->nodeMax = XML_NODESET_DEFAULT; 3613 } else if (cur->nodeNr == cur->nodeMax) { 3614 xmlNodePtr *temp; 3615 3616 cur->nodeMax *= 2; 3617 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3618 sizeof(xmlNodePtr)); 3619 if (temp == NULL) { 3620 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3621 return; 3622 } 3623 cur->nodeTab = temp; 3624 } 3625 if (val->type == XML_NAMESPACE_DECL) { 3626 xmlNsPtr ns = (xmlNsPtr) val; 3627 3628 cur->nodeTab[cur->nodeNr++] = 3629 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3630 } else 3631 cur->nodeTab[cur->nodeNr++] = val; 3632} 3633 3634/** 3635 * xmlXPathNodeSetMerge: 3636 * @val1: the first NodeSet or NULL 3637 * @val2: the second NodeSet 3638 * 3639 * Merges two nodesets, all nodes from @val2 are added to @val1 3640 * if @val1 is NULL, a new set is created and copied from @val2 3641 * 3642 * Returns @val1 once extended or NULL in case of error. 3643 */ 3644xmlNodeSetPtr 3645xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3646 int i, j, initNr, skip; 3647 xmlNodePtr n1, n2; 3648 3649 if (val2 == NULL) return(val1); 3650 if (val1 == NULL) { 3651 val1 = xmlXPathNodeSetCreate(NULL); 3652#if 0 3653 /* 3654 * TODO: The optimization won't work in every case, since 3655 * those nasty namespace nodes need to be added with 3656 * xmlXPathNodeSetDupNs() to the set; thus a pure 3657 * memcpy is not possible. 3658 * If there was a flag on the nodesetval, indicating that 3659 * some temporary nodes are in, that would be helpfull. 3660 */ 3661 /* 3662 * Optimization: Create an equally sized node-set 3663 * and memcpy the content. 3664 */ 3665 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3666 if (val1 == NULL) 3667 return(NULL); 3668 if (val2->nodeNr != 0) { 3669 if (val2->nodeNr == 1) 3670 *(val1->nodeTab) = *(val2->nodeTab); 3671 else { 3672 memcpy(val1->nodeTab, val2->nodeTab, 3673 val2->nodeNr * sizeof(xmlNodePtr)); 3674 } 3675 val1->nodeNr = val2->nodeNr; 3676 } 3677 return(val1); 3678#endif 3679 } 3680 3681 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3682 initNr = val1->nodeNr; 3683 3684 for (i = 0;i < val2->nodeNr;i++) { 3685 n2 = val2->nodeTab[i]; 3686 /* 3687 * check against duplicates 3688 */ 3689 skip = 0; 3690 for (j = 0; j < initNr; j++) { 3691 n1 = val1->nodeTab[j]; 3692 if (n1 == n2) { 3693 skip = 1; 3694 break; 3695 } else if ((n1->type == XML_NAMESPACE_DECL) && 3696 (n2->type == XML_NAMESPACE_DECL)) { 3697 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3698 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3699 ((xmlNsPtr) n2)->prefix))) 3700 { 3701 skip = 1; 3702 break; 3703 } 3704 } 3705 } 3706 if (skip) 3707 continue; 3708 3709 /* 3710 * grow the nodeTab if needed 3711 */ 3712 if (val1->nodeMax == 0) { 3713 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3714 sizeof(xmlNodePtr)); 3715 if (val1->nodeTab == NULL) { 3716 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3717 return(NULL); 3718 } 3719 memset(val1->nodeTab, 0 , 3720 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3721 val1->nodeMax = XML_NODESET_DEFAULT; 3722 } else if (val1->nodeNr == val1->nodeMax) { 3723 xmlNodePtr *temp; 3724 3725 val1->nodeMax *= 2; 3726 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 3727 sizeof(xmlNodePtr)); 3728 if (temp == NULL) { 3729 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3730 return(NULL); 3731 } 3732 val1->nodeTab = temp; 3733 } 3734 if (n2->type == XML_NAMESPACE_DECL) { 3735 xmlNsPtr ns = (xmlNsPtr) n2; 3736 3737 val1->nodeTab[val1->nodeNr++] = 3738 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3739 } else 3740 val1->nodeTab[val1->nodeNr++] = n2; 3741 } 3742 3743 return(val1); 3744} 3745 3746#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 3747/** 3748 * xmlXPathNodeSetMergeUnique: 3749 * @val1: the first NodeSet or NULL 3750 * @val2: the second NodeSet 3751 * 3752 * Merges two nodesets, all nodes from @val2 are added to @val1 3753 * if @val1 is NULL, a new set is created and copied from @val2 3754 * 3755 * Returns @val1 once extended or NULL in case of error. 3756 */ 3757static xmlNodeSetPtr 3758xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3759 int i; 3760 3761 if (val2 == NULL) return(val1); 3762 if (val1 == NULL) { 3763 val1 = xmlXPathNodeSetCreate(NULL); 3764 } 3765 3766 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3767 3768 for (i = 0;i < val2->nodeNr;i++) { 3769 /* 3770 * grow the nodeTab if needed 3771 */ 3772 if (val1->nodeMax == 0) { 3773 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3774 sizeof(xmlNodePtr)); 3775 if (val1->nodeTab == NULL) { 3776 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3777 return(NULL); 3778 } 3779 memset(val1->nodeTab, 0 , 3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3781 val1->nodeMax = XML_NODESET_DEFAULT; 3782 } else if (val1->nodeNr == val1->nodeMax) { 3783 xmlNodePtr *temp; 3784 3785 val1->nodeMax *= 2; 3786 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 3787 sizeof(xmlNodePtr)); 3788 if (temp == NULL) { 3789 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3790 return(NULL); 3791 } 3792 val1->nodeTab = temp; 3793 } 3794 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3795 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; 3796 3797 val1->nodeTab[val1->nodeNr++] = 3798 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3799 } else 3800 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; 3801 } 3802 3803 return(val1); 3804} 3805#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 3806 3807/** 3808 * xmlXPathNodeSetMergeAndClear: 3809 * @set1: the first NodeSet or NULL 3810 * @set2: the second NodeSet 3811 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3812 * 3813 * Merges two nodesets, all nodes from @set2 are added to @set1 3814 * if @set1 is NULL, a new set is created and copied from @set2. 3815 * Checks for duplicate nodes. Clears set2. 3816 * 3817 * Returns @set1 once extended or NULL in case of error. 3818 */ 3819static xmlNodeSetPtr 3820xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3821 int hasNullEntries) 3822{ 3823 if ((set1 == NULL) && (hasNullEntries == 0)) { 3824 /* 3825 * Note that doing a memcpy of the list, namespace nodes are 3826 * just assigned to set1, since set2 is cleared anyway. 3827 */ 3828 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3829 if (set1 == NULL) 3830 return(NULL); 3831 if (set2->nodeNr != 0) { 3832 memcpy(set1->nodeTab, set2->nodeTab, 3833 set2->nodeNr * sizeof(xmlNodePtr)); 3834 set1->nodeNr = set2->nodeNr; 3835 } 3836 } else { 3837 int i, j, initNbSet1; 3838 xmlNodePtr n1, n2; 3839 3840 if (set1 == NULL) 3841 set1 = xmlXPathNodeSetCreate(NULL); 3842 3843 initNbSet1 = set1->nodeNr; 3844 for (i = 0;i < set2->nodeNr;i++) { 3845 n2 = set2->nodeTab[i]; 3846 /* 3847 * Skip NULLed entries. 3848 */ 3849 if (n2 == NULL) 3850 continue; 3851 /* 3852 * Skip duplicates. 3853 */ 3854 for (j = 0; j < initNbSet1; j++) { 3855 n1 = set1->nodeTab[j]; 3856 if (n1 == n2) { 3857 goto skip_node; 3858 } else if ((n1->type == XML_NAMESPACE_DECL) && 3859 (n2->type == XML_NAMESPACE_DECL)) 3860 { 3861 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3862 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3863 ((xmlNsPtr) n2)->prefix))) 3864 { 3865 /* 3866 * Free the namespace node. 3867 */ 3868 set2->nodeTab[i] = NULL; 3869 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3870 goto skip_node; 3871 } 3872 } 3873 } 3874 /* 3875 * grow the nodeTab if needed 3876 */ 3877 if (set1->nodeMax == 0) { 3878 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3879 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3880 if (set1->nodeTab == NULL) { 3881 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3882 return(NULL); 3883 } 3884 memset(set1->nodeTab, 0, 3885 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3886 set1->nodeMax = XML_NODESET_DEFAULT; 3887 } else if (set1->nodeNr >= set1->nodeMax) { 3888 xmlNodePtr *temp; 3889 3890 set1->nodeMax *= 2; 3891 temp = (xmlNodePtr *) xmlRealloc( 3892 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr)); 3893 if (temp == NULL) { 3894 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3895 return(NULL); 3896 } 3897 set1->nodeTab = temp; 3898 } 3899 if (n2->type == XML_NAMESPACE_DECL) { 3900 xmlNsPtr ns = (xmlNsPtr) n2; 3901 3902 set1->nodeTab[set1->nodeNr++] = 3903 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3904 } else 3905 set1->nodeTab[set1->nodeNr++] = n2; 3906skip_node: 3907 {} 3908 } 3909 } 3910 set2->nodeNr = 0; 3911 return(set1); 3912} 3913 3914/** 3915 * xmlXPathNodeSetMergeAndClearNoDupls: 3916 * @set1: the first NodeSet or NULL 3917 * @set2: the second NodeSet 3918 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3919 * 3920 * Merges two nodesets, all nodes from @set2 are added to @set1 3921 * if @set1 is NULL, a new set is created and copied from @set2. 3922 * Doesn't chack for duplicate nodes. Clears set2. 3923 * 3924 * Returns @set1 once extended or NULL in case of error. 3925 */ 3926static xmlNodeSetPtr 3927xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3928 int hasNullEntries) 3929{ 3930 if (set2 == NULL) 3931 return(set1); 3932 if ((set1 == NULL) && (hasNullEntries == 0)) { 3933 /* 3934 * Note that doing a memcpy of the list, namespace nodes are 3935 * just assigned to set1, since set2 is cleared anyway. 3936 */ 3937 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3938 if (set1 == NULL) 3939 return(NULL); 3940 if (set2->nodeNr != 0) { 3941 memcpy(set1->nodeTab, set2->nodeTab, 3942 set2->nodeNr * sizeof(xmlNodePtr)); 3943 set1->nodeNr = set2->nodeNr; 3944 } 3945 } else { 3946 int i; 3947 xmlNodePtr n2; 3948 3949 if (set1 == NULL) 3950 set1 = xmlXPathNodeSetCreate(NULL); 3951 3952 for (i = 0;i < set2->nodeNr;i++) { 3953 n2 = set2->nodeTab[i]; 3954 /* 3955 * Skip NULLed entries. 3956 */ 3957 if (n2 == NULL) 3958 continue; 3959 if (set1->nodeMax == 0) { 3960 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3961 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3962 if (set1->nodeTab == NULL) { 3963 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3964 return(NULL); 3965 } 3966 memset(set1->nodeTab, 0, 3967 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3968 set1->nodeMax = XML_NODESET_DEFAULT; 3969 } else if (set1->nodeNr >= set1->nodeMax) { 3970 xmlNodePtr *temp; 3971 3972 set1->nodeMax *= 2; 3973 temp = (xmlNodePtr *) xmlRealloc( 3974 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr)); 3975 if (temp == NULL) { 3976 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3977 return(NULL); 3978 } 3979 set1->nodeTab = temp; 3980 } 3981 set1->nodeTab[set1->nodeNr++] = n2; 3982 } 3983 } 3984 set2->nodeNr = 0; 3985 return(set1); 3986} 3987 3988/** 3989 * xmlXPathNodeSetDel: 3990 * @cur: the initial node set 3991 * @val: an xmlNodePtr 3992 * 3993 * Removes an xmlNodePtr from an existing NodeSet 3994 */ 3995void 3996xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 3997 int i; 3998 3999 if (cur == NULL) return; 4000 if (val == NULL) return; 4001 4002 /* 4003 * find node in nodeTab 4004 */ 4005 for (i = 0;i < cur->nodeNr;i++) 4006 if (cur->nodeTab[i] == val) break; 4007 4008 if (i >= cur->nodeNr) { /* not found */ 4009#ifdef DEBUG 4010 xmlGenericError(xmlGenericErrorContext, 4011 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4012 val->name); 4013#endif 4014 return; 4015 } 4016 if ((cur->nodeTab[i] != NULL) && 4017 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4018 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4019 cur->nodeNr--; 4020 for (;i < cur->nodeNr;i++) 4021 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4022 cur->nodeTab[cur->nodeNr] = NULL; 4023} 4024 4025/** 4026 * xmlXPathNodeSetRemove: 4027 * @cur: the initial node set 4028 * @val: the index to remove 4029 * 4030 * Removes an entry from an existing NodeSet list. 4031 */ 4032void 4033xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4034 if (cur == NULL) return; 4035 if (val >= cur->nodeNr) return; 4036 if ((cur->nodeTab[val] != NULL) && 4037 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4038 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4039 cur->nodeNr--; 4040 for (;val < cur->nodeNr;val++) 4041 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4042 cur->nodeTab[cur->nodeNr] = NULL; 4043} 4044 4045/** 4046 * xmlXPathFreeNodeSet: 4047 * @obj: the xmlNodeSetPtr to free 4048 * 4049 * Free the NodeSet compound (not the actual nodes !). 4050 */ 4051void 4052xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4053 if (obj == NULL) return; 4054 if (obj->nodeTab != NULL) { 4055 int i; 4056 4057 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4058 for (i = 0;i < obj->nodeNr;i++) 4059 if ((obj->nodeTab[i] != NULL) && 4060 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4061 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4062 xmlFree(obj->nodeTab); 4063 } 4064 xmlFree(obj); 4065} 4066 4067/** 4068 * xmlXPathNodeSetClear: 4069 * @set: the node set to clear 4070 * 4071 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4072 * are feed), but does *not* free the list itself. Sets the length of the 4073 * list to 0. 4074 */ 4075static void 4076xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4077{ 4078 if ((set == NULL) || (set->nodeNr <= 0)) 4079 return; 4080 else if (hasNsNodes) { 4081 int i; 4082 xmlNodePtr node; 4083 4084 for (i = 0; i < set->nodeNr; i++) { 4085 node = set->nodeTab[i]; 4086 if ((node != NULL) && 4087 (node->type == XML_NAMESPACE_DECL)) 4088 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4089 } 4090 } 4091 set->nodeNr = 0; 4092} 4093 4094/** 4095 * xmlXPathNodeSetClearFromPos: 4096 * @set: the node set to be cleared 4097 * @pos: the start position to clear from 4098 * 4099 * Clears the list from temporary XPath objects (e.g. namespace nodes 4100 * are feed) starting with the entry at @pos, but does *not* free the list 4101 * itself. Sets the length of the list to @pos. 4102 */ 4103static void 4104xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4105{ 4106 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr)) 4107 return; 4108 else if ((hasNsNodes)) { 4109 int i; 4110 xmlNodePtr node; 4111 4112 for (i = pos; i < set->nodeNr; i++) { 4113 node = set->nodeTab[i]; 4114 if ((node != NULL) && 4115 (node->type == XML_NAMESPACE_DECL)) 4116 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4117 } 4118 } 4119 set->nodeNr = pos; 4120} 4121 4122/** 4123 * xmlXPathFreeValueTree: 4124 * @obj: the xmlNodeSetPtr to free 4125 * 4126 * Free the NodeSet compound and the actual tree, this is different 4127 * from xmlXPathFreeNodeSet() 4128 */ 4129static void 4130xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4131 int i; 4132 4133 if (obj == NULL) return; 4134 4135 if (obj->nodeTab != NULL) { 4136 for (i = 0;i < obj->nodeNr;i++) { 4137 if (obj->nodeTab[i] != NULL) { 4138 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4139 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4140 } else { 4141 xmlFreeNodeList(obj->nodeTab[i]); 4142 } 4143 } 4144 } 4145 xmlFree(obj->nodeTab); 4146 } 4147 xmlFree(obj); 4148} 4149 4150#if defined(DEBUG) || defined(DEBUG_STEP) 4151/** 4152 * xmlGenericErrorContextNodeSet: 4153 * @output: a FILE * for the output 4154 * @obj: the xmlNodeSetPtr to display 4155 * 4156 * Quick display of a NodeSet 4157 */ 4158void 4159xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4160 int i; 4161 4162 if (output == NULL) output = xmlGenericErrorContext; 4163 if (obj == NULL) { 4164 fprintf(output, "NodeSet == NULL !\n"); 4165 return; 4166 } 4167 if (obj->nodeNr == 0) { 4168 fprintf(output, "NodeSet is empty\n"); 4169 return; 4170 } 4171 if (obj->nodeTab == NULL) { 4172 fprintf(output, " nodeTab == NULL !\n"); 4173 return; 4174 } 4175 for (i = 0; i < obj->nodeNr; i++) { 4176 if (obj->nodeTab[i] == NULL) { 4177 fprintf(output, " NULL !\n"); 4178 return; 4179 } 4180 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4181 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4182 fprintf(output, " /"); 4183 else if (obj->nodeTab[i]->name == NULL) 4184 fprintf(output, " noname!"); 4185 else fprintf(output, " %s", obj->nodeTab[i]->name); 4186 } 4187 fprintf(output, "\n"); 4188} 4189#endif 4190 4191/** 4192 * xmlXPathNewNodeSet: 4193 * @val: the NodePtr value 4194 * 4195 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4196 * it with the single Node @val 4197 * 4198 * Returns the newly created object. 4199 */ 4200xmlXPathObjectPtr 4201xmlXPathNewNodeSet(xmlNodePtr val) { 4202 xmlXPathObjectPtr ret; 4203 4204 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4205 if (ret == NULL) { 4206 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4207 return(NULL); 4208 } 4209 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4210 ret->type = XPATH_NODESET; 4211 ret->boolval = 0; 4212 ret->nodesetval = xmlXPathNodeSetCreate(val); 4213 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4214#ifdef XP_DEBUG_OBJ_USAGE 4215 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4216#endif 4217 return(ret); 4218} 4219 4220/** 4221 * xmlXPathNewValueTree: 4222 * @val: the NodePtr value 4223 * 4224 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4225 * it with the tree root @val 4226 * 4227 * Returns the newly created object. 4228 */ 4229xmlXPathObjectPtr 4230xmlXPathNewValueTree(xmlNodePtr val) { 4231 xmlXPathObjectPtr ret; 4232 4233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4234 if (ret == NULL) { 4235 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4236 return(NULL); 4237 } 4238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4239 ret->type = XPATH_XSLT_TREE; 4240 ret->boolval = 1; 4241 ret->user = (void *) val; 4242 ret->nodesetval = xmlXPathNodeSetCreate(val); 4243#ifdef XP_DEBUG_OBJ_USAGE 4244 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4245#endif 4246 return(ret); 4247} 4248 4249/** 4250 * xmlXPathNewNodeSetList: 4251 * @val: an existing NodeSet 4252 * 4253 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4254 * it with the Nodeset @val 4255 * 4256 * Returns the newly created object. 4257 */ 4258xmlXPathObjectPtr 4259xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4260{ 4261 xmlXPathObjectPtr ret; 4262 int i; 4263 4264 if (val == NULL) 4265 ret = NULL; 4266 else if (val->nodeTab == NULL) 4267 ret = xmlXPathNewNodeSet(NULL); 4268 else { 4269 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4270 for (i = 1; i < val->nodeNr; ++i) 4271 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]); 4272 } 4273 4274 return (ret); 4275} 4276 4277/** 4278 * xmlXPathWrapNodeSet: 4279 * @val: the NodePtr value 4280 * 4281 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4282 * 4283 * Returns the newly created object. 4284 */ 4285xmlXPathObjectPtr 4286xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4287 xmlXPathObjectPtr ret; 4288 4289 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4290 if (ret == NULL) { 4291 xmlXPathErrMemory(NULL, "creating node set object\n"); 4292 return(NULL); 4293 } 4294 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4295 ret->type = XPATH_NODESET; 4296 ret->nodesetval = val; 4297#ifdef XP_DEBUG_OBJ_USAGE 4298 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4299#endif 4300 return(ret); 4301} 4302 4303/** 4304 * xmlXPathFreeNodeSetList: 4305 * @obj: an existing NodeSetList object 4306 * 4307 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4308 * the list contrary to xmlXPathFreeObject(). 4309 */ 4310void 4311xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4312 if (obj == NULL) return; 4313#ifdef XP_DEBUG_OBJ_USAGE 4314 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4315#endif 4316 xmlFree(obj); 4317} 4318 4319/** 4320 * xmlXPathDifference: 4321 * @nodes1: a node-set 4322 * @nodes2: a node-set 4323 * 4324 * Implements the EXSLT - Sets difference() function: 4325 * node-set set:difference (node-set, node-set) 4326 * 4327 * Returns the difference between the two node sets, or nodes1 if 4328 * nodes2 is empty 4329 */ 4330xmlNodeSetPtr 4331xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4332 xmlNodeSetPtr ret; 4333 int i, l1; 4334 xmlNodePtr cur; 4335 4336 if (xmlXPathNodeSetIsEmpty(nodes2)) 4337 return(nodes1); 4338 4339 ret = xmlXPathNodeSetCreate(NULL); 4340 if (xmlXPathNodeSetIsEmpty(nodes1)) 4341 return(ret); 4342 4343 l1 = xmlXPathNodeSetGetLength(nodes1); 4344 4345 for (i = 0; i < l1; i++) { 4346 cur = xmlXPathNodeSetItem(nodes1, i); 4347 if (!xmlXPathNodeSetContains(nodes2, cur)) 4348 xmlXPathNodeSetAddUnique(ret, cur); 4349 } 4350 return(ret); 4351} 4352 4353/** 4354 * xmlXPathIntersection: 4355 * @nodes1: a node-set 4356 * @nodes2: a node-set 4357 * 4358 * Implements the EXSLT - Sets intersection() function: 4359 * node-set set:intersection (node-set, node-set) 4360 * 4361 * Returns a node set comprising the nodes that are within both the 4362 * node sets passed as arguments 4363 */ 4364xmlNodeSetPtr 4365xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4366 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4367 int i, l1; 4368 xmlNodePtr cur; 4369 4370 if (xmlXPathNodeSetIsEmpty(nodes1)) 4371 return(ret); 4372 if (xmlXPathNodeSetIsEmpty(nodes2)) 4373 return(ret); 4374 4375 l1 = xmlXPathNodeSetGetLength(nodes1); 4376 4377 for (i = 0; i < l1; i++) { 4378 cur = xmlXPathNodeSetItem(nodes1, i); 4379 if (xmlXPathNodeSetContains(nodes2, cur)) 4380 xmlXPathNodeSetAddUnique(ret, cur); 4381 } 4382 return(ret); 4383} 4384 4385/** 4386 * xmlXPathDistinctSorted: 4387 * @nodes: a node-set, sorted by document order 4388 * 4389 * Implements the EXSLT - Sets distinct() function: 4390 * node-set set:distinct (node-set) 4391 * 4392 * Returns a subset of the nodes contained in @nodes, or @nodes if 4393 * it is empty 4394 */ 4395xmlNodeSetPtr 4396xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4397 xmlNodeSetPtr ret; 4398 xmlHashTablePtr hash; 4399 int i, l; 4400 xmlChar * strval; 4401 xmlNodePtr cur; 4402 4403 if (xmlXPathNodeSetIsEmpty(nodes)) 4404 return(nodes); 4405 4406 ret = xmlXPathNodeSetCreate(NULL); 4407 l = xmlXPathNodeSetGetLength(nodes); 4408 hash = xmlHashCreate (l); 4409 for (i = 0; i < l; i++) { 4410 cur = xmlXPathNodeSetItem(nodes, i); 4411 strval = xmlXPathCastNodeToString(cur); 4412 if (xmlHashLookup(hash, strval) == NULL) { 4413 xmlHashAddEntry(hash, strval, strval); 4414 xmlXPathNodeSetAddUnique(ret, cur); 4415 } else { 4416 xmlFree(strval); 4417 } 4418 } 4419 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 4420 return(ret); 4421} 4422 4423/** 4424 * xmlXPathDistinct: 4425 * @nodes: a node-set 4426 * 4427 * Implements the EXSLT - Sets distinct() function: 4428 * node-set set:distinct (node-set) 4429 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4430 * is called with the sorted node-set 4431 * 4432 * Returns a subset of the nodes contained in @nodes, or @nodes if 4433 * it is empty 4434 */ 4435xmlNodeSetPtr 4436xmlXPathDistinct (xmlNodeSetPtr nodes) { 4437 if (xmlXPathNodeSetIsEmpty(nodes)) 4438 return(nodes); 4439 4440 xmlXPathNodeSetSort(nodes); 4441 return(xmlXPathDistinctSorted(nodes)); 4442} 4443 4444/** 4445 * xmlXPathHasSameNodes: 4446 * @nodes1: a node-set 4447 * @nodes2: a node-set 4448 * 4449 * Implements the EXSLT - Sets has-same-nodes function: 4450 * boolean set:has-same-node(node-set, node-set) 4451 * 4452 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4453 * otherwise 4454 */ 4455int 4456xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4457 int i, l; 4458 xmlNodePtr cur; 4459 4460 if (xmlXPathNodeSetIsEmpty(nodes1) || 4461 xmlXPathNodeSetIsEmpty(nodes2)) 4462 return(0); 4463 4464 l = xmlXPathNodeSetGetLength(nodes1); 4465 for (i = 0; i < l; i++) { 4466 cur = xmlXPathNodeSetItem(nodes1, i); 4467 if (xmlXPathNodeSetContains(nodes2, cur)) 4468 return(1); 4469 } 4470 return(0); 4471} 4472 4473/** 4474 * xmlXPathNodeLeadingSorted: 4475 * @nodes: a node-set, sorted by document order 4476 * @node: a node 4477 * 4478 * Implements the EXSLT - Sets leading() function: 4479 * node-set set:leading (node-set, node-set) 4480 * 4481 * Returns the nodes in @nodes that precede @node in document order, 4482 * @nodes if @node is NULL or an empty node-set if @nodes 4483 * doesn't contain @node 4484 */ 4485xmlNodeSetPtr 4486xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4487 int i, l; 4488 xmlNodePtr cur; 4489 xmlNodeSetPtr ret; 4490 4491 if (node == NULL) 4492 return(nodes); 4493 4494 ret = xmlXPathNodeSetCreate(NULL); 4495 if (xmlXPathNodeSetIsEmpty(nodes) || 4496 (!xmlXPathNodeSetContains(nodes, node))) 4497 return(ret); 4498 4499 l = xmlXPathNodeSetGetLength(nodes); 4500 for (i = 0; i < l; i++) { 4501 cur = xmlXPathNodeSetItem(nodes, i); 4502 if (cur == node) 4503 break; 4504 xmlXPathNodeSetAddUnique(ret, cur); 4505 } 4506 return(ret); 4507} 4508 4509/** 4510 * xmlXPathNodeLeading: 4511 * @nodes: a node-set 4512 * @node: a node 4513 * 4514 * Implements the EXSLT - Sets leading() function: 4515 * node-set set:leading (node-set, node-set) 4516 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4517 * is called. 4518 * 4519 * Returns the nodes in @nodes that precede @node in document order, 4520 * @nodes if @node is NULL or an empty node-set if @nodes 4521 * doesn't contain @node 4522 */ 4523xmlNodeSetPtr 4524xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4525 xmlXPathNodeSetSort(nodes); 4526 return(xmlXPathNodeLeadingSorted(nodes, node)); 4527} 4528 4529/** 4530 * xmlXPathLeadingSorted: 4531 * @nodes1: a node-set, sorted by document order 4532 * @nodes2: a node-set, sorted by document order 4533 * 4534 * Implements the EXSLT - Sets leading() function: 4535 * node-set set:leading (node-set, node-set) 4536 * 4537 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4538 * in document order, @nodes1 if @nodes2 is NULL or empty or 4539 * an empty node-set if @nodes1 doesn't contain @nodes2 4540 */ 4541xmlNodeSetPtr 4542xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4543 if (xmlXPathNodeSetIsEmpty(nodes2)) 4544 return(nodes1); 4545 return(xmlXPathNodeLeadingSorted(nodes1, 4546 xmlXPathNodeSetItem(nodes2, 1))); 4547} 4548 4549/** 4550 * xmlXPathLeading: 4551 * @nodes1: a node-set 4552 * @nodes2: a node-set 4553 * 4554 * Implements the EXSLT - Sets leading() function: 4555 * node-set set:leading (node-set, node-set) 4556 * @nodes1 and @nodes2 are sorted by document order, then 4557 * #exslSetsLeadingSorted is called. 4558 * 4559 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4560 * in document order, @nodes1 if @nodes2 is NULL or empty or 4561 * an empty node-set if @nodes1 doesn't contain @nodes2 4562 */ 4563xmlNodeSetPtr 4564xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4565 if (xmlXPathNodeSetIsEmpty(nodes2)) 4566 return(nodes1); 4567 if (xmlXPathNodeSetIsEmpty(nodes1)) 4568 return(xmlXPathNodeSetCreate(NULL)); 4569 xmlXPathNodeSetSort(nodes1); 4570 xmlXPathNodeSetSort(nodes2); 4571 return(xmlXPathNodeLeadingSorted(nodes1, 4572 xmlXPathNodeSetItem(nodes2, 1))); 4573} 4574 4575/** 4576 * xmlXPathNodeTrailingSorted: 4577 * @nodes: a node-set, sorted by document order 4578 * @node: a node 4579 * 4580 * Implements the EXSLT - Sets trailing() function: 4581 * node-set set:trailing (node-set, node-set) 4582 * 4583 * Returns the nodes in @nodes that follow @node in document order, 4584 * @nodes if @node is NULL or an empty node-set if @nodes 4585 * doesn't contain @node 4586 */ 4587xmlNodeSetPtr 4588xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4589 int i, l; 4590 xmlNodePtr cur; 4591 xmlNodeSetPtr ret; 4592 4593 if (node == NULL) 4594 return(nodes); 4595 4596 ret = xmlXPathNodeSetCreate(NULL); 4597 if (xmlXPathNodeSetIsEmpty(nodes) || 4598 (!xmlXPathNodeSetContains(nodes, node))) 4599 return(ret); 4600 4601 l = xmlXPathNodeSetGetLength(nodes); 4602 for (i = l; i > 0; i--) { 4603 cur = xmlXPathNodeSetItem(nodes, i); 4604 if (cur == node) 4605 break; 4606 xmlXPathNodeSetAddUnique(ret, cur); 4607 } 4608 return(ret); 4609} 4610 4611/** 4612 * xmlXPathNodeTrailing: 4613 * @nodes: a node-set 4614 * @node: a node 4615 * 4616 * Implements the EXSLT - Sets trailing() function: 4617 * node-set set:trailing (node-set, node-set) 4618 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4619 * is called. 4620 * 4621 * Returns the nodes in @nodes that follow @node in document order, 4622 * @nodes if @node is NULL or an empty node-set if @nodes 4623 * doesn't contain @node 4624 */ 4625xmlNodeSetPtr 4626xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4627 xmlXPathNodeSetSort(nodes); 4628 return(xmlXPathNodeTrailingSorted(nodes, node)); 4629} 4630 4631/** 4632 * xmlXPathTrailingSorted: 4633 * @nodes1: a node-set, sorted by document order 4634 * @nodes2: a node-set, sorted by document order 4635 * 4636 * Implements the EXSLT - Sets trailing() function: 4637 * node-set set:trailing (node-set, node-set) 4638 * 4639 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4640 * in document order, @nodes1 if @nodes2 is NULL or empty or 4641 * an empty node-set if @nodes1 doesn't contain @nodes2 4642 */ 4643xmlNodeSetPtr 4644xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4645 if (xmlXPathNodeSetIsEmpty(nodes2)) 4646 return(nodes1); 4647 return(xmlXPathNodeTrailingSorted(nodes1, 4648 xmlXPathNodeSetItem(nodes2, 0))); 4649} 4650 4651/** 4652 * xmlXPathTrailing: 4653 * @nodes1: a node-set 4654 * @nodes2: a node-set 4655 * 4656 * Implements the EXSLT - Sets trailing() function: 4657 * node-set set:trailing (node-set, node-set) 4658 * @nodes1 and @nodes2 are sorted by document order, then 4659 * #xmlXPathTrailingSorted is called. 4660 * 4661 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4662 * in document order, @nodes1 if @nodes2 is NULL or empty or 4663 * an empty node-set if @nodes1 doesn't contain @nodes2 4664 */ 4665xmlNodeSetPtr 4666xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4667 if (xmlXPathNodeSetIsEmpty(nodes2)) 4668 return(nodes1); 4669 if (xmlXPathNodeSetIsEmpty(nodes1)) 4670 return(xmlXPathNodeSetCreate(NULL)); 4671 xmlXPathNodeSetSort(nodes1); 4672 xmlXPathNodeSetSort(nodes2); 4673 return(xmlXPathNodeTrailingSorted(nodes1, 4674 xmlXPathNodeSetItem(nodes2, 0))); 4675} 4676 4677/************************************************************************ 4678 * * 4679 * Routines to handle extra functions * 4680 * * 4681 ************************************************************************/ 4682 4683/** 4684 * xmlXPathRegisterFunc: 4685 * @ctxt: the XPath context 4686 * @name: the function name 4687 * @f: the function implementation or NULL 4688 * 4689 * Register a new function. If @f is NULL it unregisters the function 4690 * 4691 * Returns 0 in case of success, -1 in case of error 4692 */ 4693int 4694xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4695 xmlXPathFunction f) { 4696 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4697} 4698 4699/** 4700 * xmlXPathRegisterFuncNS: 4701 * @ctxt: the XPath context 4702 * @name: the function name 4703 * @ns_uri: the function namespace URI 4704 * @f: the function implementation or NULL 4705 * 4706 * Register a new function. If @f is NULL it unregisters the function 4707 * 4708 * Returns 0 in case of success, -1 in case of error 4709 */ 4710int 4711xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4712 const xmlChar *ns_uri, xmlXPathFunction f) { 4713 if (ctxt == NULL) 4714 return(-1); 4715 if (name == NULL) 4716 return(-1); 4717 4718 if (ctxt->funcHash == NULL) 4719 ctxt->funcHash = xmlHashCreate(0); 4720 if (ctxt->funcHash == NULL) 4721 return(-1); 4722 if (f == NULL) 4723 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4724 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f))); 4725} 4726 4727/** 4728 * xmlXPathRegisterFuncLookup: 4729 * @ctxt: the XPath context 4730 * @f: the lookup function 4731 * @funcCtxt: the lookup data 4732 * 4733 * Registers an external mechanism to do function lookup. 4734 */ 4735void 4736xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4737 xmlXPathFuncLookupFunc f, 4738 void *funcCtxt) { 4739 if (ctxt == NULL) 4740 return; 4741 ctxt->funcLookupFunc = f; 4742 ctxt->funcLookupData = funcCtxt; 4743} 4744 4745/** 4746 * xmlXPathFunctionLookup: 4747 * @ctxt: the XPath context 4748 * @name: the function name 4749 * 4750 * Search in the Function array of the context for the given 4751 * function. 4752 * 4753 * Returns the xmlXPathFunction or NULL if not found 4754 */ 4755xmlXPathFunction 4756xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4757 if (ctxt == NULL) 4758 return (NULL); 4759 4760 if (ctxt->funcLookupFunc != NULL) { 4761 xmlXPathFunction ret; 4762 xmlXPathFuncLookupFunc f; 4763 4764 f = ctxt->funcLookupFunc; 4765 ret = f(ctxt->funcLookupData, name, NULL); 4766 if (ret != NULL) 4767 return(ret); 4768 } 4769 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4770} 4771 4772/** 4773 * xmlXPathFunctionLookupNS: 4774 * @ctxt: the XPath context 4775 * @name: the function name 4776 * @ns_uri: the function namespace URI 4777 * 4778 * Search in the Function array of the context for the given 4779 * function. 4780 * 4781 * Returns the xmlXPathFunction or NULL if not found 4782 */ 4783xmlXPathFunction 4784xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4785 const xmlChar *ns_uri) { 4786 xmlXPathFunction ret; 4787 4788 if (ctxt == NULL) 4789 return(NULL); 4790 if (name == NULL) 4791 return(NULL); 4792 4793 if (ctxt->funcLookupFunc != NULL) { 4794 xmlXPathFuncLookupFunc f; 4795 4796 f = ctxt->funcLookupFunc; 4797 ret = f(ctxt->funcLookupData, name, ns_uri); 4798 if (ret != NULL) 4799 return(ret); 4800 } 4801 4802 if (ctxt->funcHash == NULL) 4803 return(NULL); 4804 4805 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4806 return(ret); 4807} 4808 4809/** 4810 * xmlXPathRegisteredFuncsCleanup: 4811 * @ctxt: the XPath context 4812 * 4813 * Cleanup the XPath context data associated to registered functions 4814 */ 4815void 4816xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4817 if (ctxt == NULL) 4818 return; 4819 4820 xmlHashFree(ctxt->funcHash, NULL); 4821 ctxt->funcHash = NULL; 4822} 4823 4824/************************************************************************ 4825 * * 4826 * Routines to handle Variables * 4827 * * 4828 ************************************************************************/ 4829 4830/** 4831 * xmlXPathRegisterVariable: 4832 * @ctxt: the XPath context 4833 * @name: the variable name 4834 * @value: the variable value or NULL 4835 * 4836 * Register a new variable value. If @value is NULL it unregisters 4837 * the variable 4838 * 4839 * Returns 0 in case of success, -1 in case of error 4840 */ 4841int 4842xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 4843 xmlXPathObjectPtr value) { 4844 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 4845} 4846 4847/** 4848 * xmlXPathRegisterVariableNS: 4849 * @ctxt: the XPath context 4850 * @name: the variable name 4851 * @ns_uri: the variable namespace URI 4852 * @value: the variable value or NULL 4853 * 4854 * Register a new variable value. If @value is NULL it unregisters 4855 * the variable 4856 * 4857 * Returns 0 in case of success, -1 in case of error 4858 */ 4859int 4860xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4861 const xmlChar *ns_uri, 4862 xmlXPathObjectPtr value) { 4863 if (ctxt == NULL) 4864 return(-1); 4865 if (name == NULL) 4866 return(-1); 4867 4868 if (ctxt->varHash == NULL) 4869 ctxt->varHash = xmlHashCreate(0); 4870 if (ctxt->varHash == NULL) 4871 return(-1); 4872 if (value == NULL) 4873 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 4874 (xmlHashDeallocator)xmlXPathFreeObject)); 4875 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 4876 (void *) value, 4877 (xmlHashDeallocator)xmlXPathFreeObject)); 4878} 4879 4880/** 4881 * xmlXPathRegisterVariableLookup: 4882 * @ctxt: the XPath context 4883 * @f: the lookup function 4884 * @data: the lookup data 4885 * 4886 * register an external mechanism to do variable lookup 4887 */ 4888void 4889xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 4890 xmlXPathVariableLookupFunc f, void *data) { 4891 if (ctxt == NULL) 4892 return; 4893 ctxt->varLookupFunc = f; 4894 ctxt->varLookupData = data; 4895} 4896 4897/** 4898 * xmlXPathVariableLookup: 4899 * @ctxt: the XPath context 4900 * @name: the variable name 4901 * 4902 * Search in the Variable array of the context for the given 4903 * variable value. 4904 * 4905 * Returns a copy of the value or NULL if not found 4906 */ 4907xmlXPathObjectPtr 4908xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4909 if (ctxt == NULL) 4910 return(NULL); 4911 4912 if (ctxt->varLookupFunc != NULL) { 4913 xmlXPathObjectPtr ret; 4914 4915 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 4916 (ctxt->varLookupData, name, NULL); 4917 return(ret); 4918 } 4919 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 4920} 4921 4922/** 4923 * xmlXPathVariableLookupNS: 4924 * @ctxt: the XPath context 4925 * @name: the variable name 4926 * @ns_uri: the variable namespace URI 4927 * 4928 * Search in the Variable array of the context for the given 4929 * variable value. 4930 * 4931 * Returns the a copy of the value or NULL if not found 4932 */ 4933xmlXPathObjectPtr 4934xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4935 const xmlChar *ns_uri) { 4936 if (ctxt == NULL) 4937 return(NULL); 4938 4939 if (ctxt->varLookupFunc != NULL) { 4940 xmlXPathObjectPtr ret; 4941 4942 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 4943 (ctxt->varLookupData, name, ns_uri); 4944 if (ret != NULL) return(ret); 4945 } 4946 4947 if (ctxt->varHash == NULL) 4948 return(NULL); 4949 if (name == NULL) 4950 return(NULL); 4951 4952 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 4953 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 4954} 4955 4956/** 4957 * xmlXPathRegisteredVariablesCleanup: 4958 * @ctxt: the XPath context 4959 * 4960 * Cleanup the XPath context data associated to registered variables 4961 */ 4962void 4963xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 4964 if (ctxt == NULL) 4965 return; 4966 4967 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 4968 ctxt->varHash = NULL; 4969} 4970 4971/** 4972 * xmlXPathRegisterNs: 4973 * @ctxt: the XPath context 4974 * @prefix: the namespace prefix 4975 * @ns_uri: the namespace name 4976 * 4977 * Register a new namespace. If @ns_uri is NULL it unregisters 4978 * the namespace 4979 * 4980 * Returns 0 in case of success, -1 in case of error 4981 */ 4982int 4983xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 4984 const xmlChar *ns_uri) { 4985 if (ctxt == NULL) 4986 return(-1); 4987 if (prefix == NULL) 4988 return(-1); 4989 4990 if (ctxt->nsHash == NULL) 4991 ctxt->nsHash = xmlHashCreate(10); 4992 if (ctxt->nsHash == NULL) 4993 return(-1); 4994 if (ns_uri == NULL) 4995 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 4996 (xmlHashDeallocator)xmlFree)); 4997 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 4998 (xmlHashDeallocator)xmlFree)); 4999} 5000 5001/** 5002 * xmlXPathNsLookup: 5003 * @ctxt: the XPath context 5004 * @prefix: the namespace prefix value 5005 * 5006 * Search in the namespace declaration array of the context for the given 5007 * namespace name associated to the given prefix 5008 * 5009 * Returns the value or NULL if not found 5010 */ 5011const xmlChar * 5012xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5013 if (ctxt == NULL) 5014 return(NULL); 5015 if (prefix == NULL) 5016 return(NULL); 5017 5018#ifdef XML_XML_NAMESPACE 5019 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5020 return(XML_XML_NAMESPACE); 5021#endif 5022 5023 if (ctxt->namespaces != NULL) { 5024 int i; 5025 5026 for (i = 0;i < ctxt->nsNr;i++) { 5027 if ((ctxt->namespaces[i] != NULL) && 5028 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5029 return(ctxt->namespaces[i]->href); 5030 } 5031 } 5032 5033 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5034} 5035 5036/** 5037 * xmlXPathRegisteredNsCleanup: 5038 * @ctxt: the XPath context 5039 * 5040 * Cleanup the XPath context data associated to registered variables 5041 */ 5042void 5043xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5044 if (ctxt == NULL) 5045 return; 5046 5047 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); 5048 ctxt->nsHash = NULL; 5049} 5050 5051/************************************************************************ 5052 * * 5053 * Routines to handle Values * 5054 * * 5055 ************************************************************************/ 5056 5057/* Allocations are terrible, one needs to optimize all this !!! */ 5058 5059/** 5060 * xmlXPathNewFloat: 5061 * @val: the double value 5062 * 5063 * Create a new xmlXPathObjectPtr of type double and of value @val 5064 * 5065 * Returns the newly created object. 5066 */ 5067xmlXPathObjectPtr 5068xmlXPathNewFloat(double val) { 5069 xmlXPathObjectPtr ret; 5070 5071 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5072 if (ret == NULL) { 5073 xmlXPathErrMemory(NULL, "creating float object\n"); 5074 return(NULL); 5075 } 5076 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5077 ret->type = XPATH_NUMBER; 5078 ret->floatval = val; 5079#ifdef XP_DEBUG_OBJ_USAGE 5080 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5081#endif 5082 return(ret); 5083} 5084 5085/** 5086 * xmlXPathNewBoolean: 5087 * @val: the boolean value 5088 * 5089 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5090 * 5091 * Returns the newly created object. 5092 */ 5093xmlXPathObjectPtr 5094xmlXPathNewBoolean(int val) { 5095 xmlXPathObjectPtr ret; 5096 5097 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5098 if (ret == NULL) { 5099 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5100 return(NULL); 5101 } 5102 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5103 ret->type = XPATH_BOOLEAN; 5104 ret->boolval = (val != 0); 5105#ifdef XP_DEBUG_OBJ_USAGE 5106 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5107#endif 5108 return(ret); 5109} 5110 5111/** 5112 * xmlXPathNewString: 5113 * @val: the xmlChar * value 5114 * 5115 * Create a new xmlXPathObjectPtr of type string and of value @val 5116 * 5117 * Returns the newly created object. 5118 */ 5119xmlXPathObjectPtr 5120xmlXPathNewString(const xmlChar *val) { 5121 xmlXPathObjectPtr ret; 5122 5123 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5124 if (ret == NULL) { 5125 xmlXPathErrMemory(NULL, "creating string object\n"); 5126 return(NULL); 5127 } 5128 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5129 ret->type = XPATH_STRING; 5130 if (val != NULL) 5131 ret->stringval = xmlStrdup(val); 5132 else 5133 ret->stringval = xmlStrdup((const xmlChar *)""); 5134#ifdef XP_DEBUG_OBJ_USAGE 5135 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5136#endif 5137 return(ret); 5138} 5139 5140/** 5141 * xmlXPathWrapString: 5142 * @val: the xmlChar * value 5143 * 5144 * Wraps the @val string into an XPath object. 5145 * 5146 * Returns the newly created object. 5147 */ 5148xmlXPathObjectPtr 5149xmlXPathWrapString (xmlChar *val) { 5150 xmlXPathObjectPtr ret; 5151 5152 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5153 if (ret == NULL) { 5154 xmlXPathErrMemory(NULL, "creating string object\n"); 5155 return(NULL); 5156 } 5157 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5158 ret->type = XPATH_STRING; 5159 ret->stringval = val; 5160#ifdef XP_DEBUG_OBJ_USAGE 5161 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5162#endif 5163 return(ret); 5164} 5165 5166/** 5167 * xmlXPathNewCString: 5168 * @val: the char * value 5169 * 5170 * Create a new xmlXPathObjectPtr of type string and of value @val 5171 * 5172 * Returns the newly created object. 5173 */ 5174xmlXPathObjectPtr 5175xmlXPathNewCString(const char *val) { 5176 xmlXPathObjectPtr ret; 5177 5178 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5179 if (ret == NULL) { 5180 xmlXPathErrMemory(NULL, "creating string object\n"); 5181 return(NULL); 5182 } 5183 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5184 ret->type = XPATH_STRING; 5185 ret->stringval = xmlStrdup(BAD_CAST val); 5186#ifdef XP_DEBUG_OBJ_USAGE 5187 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5188#endif 5189 return(ret); 5190} 5191 5192/** 5193 * xmlXPathWrapCString: 5194 * @val: the char * value 5195 * 5196 * Wraps a string into an XPath object. 5197 * 5198 * Returns the newly created object. 5199 */ 5200xmlXPathObjectPtr 5201xmlXPathWrapCString (char * val) { 5202 return(xmlXPathWrapString((xmlChar *)(val))); 5203} 5204 5205/** 5206 * xmlXPathWrapExternal: 5207 * @val: the user data 5208 * 5209 * Wraps the @val data into an XPath object. 5210 * 5211 * Returns the newly created object. 5212 */ 5213xmlXPathObjectPtr 5214xmlXPathWrapExternal (void *val) { 5215 xmlXPathObjectPtr ret; 5216 5217 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5218 if (ret == NULL) { 5219 xmlXPathErrMemory(NULL, "creating user object\n"); 5220 return(NULL); 5221 } 5222 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5223 ret->type = XPATH_USERS; 5224 ret->user = val; 5225#ifdef XP_DEBUG_OBJ_USAGE 5226 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5227#endif 5228 return(ret); 5229} 5230 5231/** 5232 * xmlXPathObjectCopy: 5233 * @val: the original object 5234 * 5235 * allocate a new copy of a given object 5236 * 5237 * Returns the newly created object. 5238 */ 5239xmlXPathObjectPtr 5240xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5241 xmlXPathObjectPtr ret; 5242 5243 if (val == NULL) 5244 return(NULL); 5245 5246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5247 if (ret == NULL) { 5248 xmlXPathErrMemory(NULL, "copying object\n"); 5249 return(NULL); 5250 } 5251 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5252#ifdef XP_DEBUG_OBJ_USAGE 5253 xmlXPathDebugObjUsageRequested(NULL, val->type); 5254#endif 5255 switch (val->type) { 5256 case XPATH_BOOLEAN: 5257 case XPATH_NUMBER: 5258 case XPATH_POINT: 5259 case XPATH_RANGE: 5260 break; 5261 case XPATH_STRING: 5262 ret->stringval = xmlStrdup(val->stringval); 5263 break; 5264 case XPATH_XSLT_TREE: 5265#if 0 5266/* 5267 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5268 this previous handling is no longer correct, and can cause some serious 5269 problems (ref. bug 145547) 5270*/ 5271 if ((val->nodesetval != NULL) && 5272 (val->nodesetval->nodeTab != NULL)) { 5273 xmlNodePtr cur, tmp; 5274 xmlDocPtr top; 5275 5276 ret->boolval = 1; 5277 top = xmlNewDoc(NULL); 5278 top->name = (char *) 5279 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5280 ret->user = top; 5281 if (top != NULL) { 5282 top->doc = top; 5283 cur = val->nodesetval->nodeTab[0]->children; 5284 while (cur != NULL) { 5285 tmp = xmlDocCopyNode(cur, top, 1); 5286 xmlAddChild((xmlNodePtr) top, tmp); 5287 cur = cur->next; 5288 } 5289 } 5290 5291 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5292 } else 5293 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5294 /* Deallocate the copied tree value */ 5295 break; 5296#endif 5297 case XPATH_NODESET: 5298 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5299 /* Do not deallocate the copied tree value */ 5300 ret->boolval = 0; 5301 break; 5302 case XPATH_LOCATIONSET: 5303#ifdef LIBXML_XPTR_ENABLED 5304 { 5305 xmlLocationSetPtr loc = val->user; 5306 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5307 break; 5308 } 5309#endif 5310 case XPATH_USERS: 5311 ret->user = val->user; 5312 break; 5313 case XPATH_UNDEFINED: 5314 xmlGenericError(xmlGenericErrorContext, 5315 "xmlXPathObjectCopy: unsupported type %d\n", 5316 val->type); 5317 break; 5318 } 5319 return(ret); 5320} 5321 5322/** 5323 * xmlXPathFreeObject: 5324 * @obj: the object to free 5325 * 5326 * Free up an xmlXPathObjectPtr object. 5327 */ 5328void 5329xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5330 if (obj == NULL) return; 5331 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5332 if (obj->boolval) { 5333#if 0 5334 if (obj->user != NULL) { 5335 xmlXPathFreeNodeSet(obj->nodesetval); 5336 xmlFreeNodeList((xmlNodePtr) obj->user); 5337 } else 5338#endif 5339 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5340 if (obj->nodesetval != NULL) 5341 xmlXPathFreeValueTree(obj->nodesetval); 5342 } else { 5343 if (obj->nodesetval != NULL) 5344 xmlXPathFreeNodeSet(obj->nodesetval); 5345 } 5346#ifdef LIBXML_XPTR_ENABLED 5347 } else if (obj->type == XPATH_LOCATIONSET) { 5348 if (obj->user != NULL) 5349 xmlXPtrFreeLocationSet(obj->user); 5350#endif 5351 } else if (obj->type == XPATH_STRING) { 5352 if (obj->stringval != NULL) 5353 xmlFree(obj->stringval); 5354 } 5355#ifdef XP_DEBUG_OBJ_USAGE 5356 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5357#endif 5358 xmlFree(obj); 5359} 5360 5361/** 5362 * xmlXPathReleaseObject: 5363 * @obj: the xmlXPathObjectPtr to free or to cache 5364 * 5365 * Depending on the state of the cache this frees the given 5366 * XPath object or stores it in the cache. 5367 */ 5368static void 5369xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5370{ 5371#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5372 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5373 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5374 5375#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5376 5377 if (obj == NULL) 5378 return; 5379 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5380 xmlXPathFreeObject(obj); 5381 } else { 5382 xmlXPathContextCachePtr cache = 5383 (xmlXPathContextCachePtr) ctxt->cache; 5384 5385 switch (obj->type) { 5386 case XPATH_NODESET: 5387 case XPATH_XSLT_TREE: 5388 if (obj->nodesetval != NULL) { 5389 if (obj->boolval) { 5390 /* 5391 * It looks like the @boolval is used for 5392 * evaluation if this an XSLT Result Tree Fragment. 5393 * TODO: Check if this assumption is correct. 5394 */ 5395 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5396 xmlXPathFreeValueTree(obj->nodesetval); 5397 obj->nodesetval = NULL; 5398 } else if ((obj->nodesetval->nodeMax <= 40) && 5399 (XP_CACHE_WANTS(cache->nodesetObjs, 5400 cache->maxNodeset))) 5401 { 5402 XP_CACHE_ADD(cache->nodesetObjs, obj); 5403 goto obj_cached; 5404 } else { 5405 xmlXPathFreeNodeSet(obj->nodesetval); 5406 obj->nodesetval = NULL; 5407 } 5408 } 5409 break; 5410 case XPATH_STRING: 5411 if (obj->stringval != NULL) 5412 xmlFree(obj->stringval); 5413 5414 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5415 XP_CACHE_ADD(cache->stringObjs, obj); 5416 goto obj_cached; 5417 } 5418 break; 5419 case XPATH_BOOLEAN: 5420 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5421 XP_CACHE_ADD(cache->booleanObjs, obj); 5422 goto obj_cached; 5423 } 5424 break; 5425 case XPATH_NUMBER: 5426 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5427 XP_CACHE_ADD(cache->numberObjs, obj); 5428 goto obj_cached; 5429 } 5430 break; 5431#ifdef LIBXML_XPTR_ENABLED 5432 case XPATH_LOCATIONSET: 5433 if (obj->user != NULL) { 5434 xmlXPtrFreeLocationSet(obj->user); 5435 } 5436 goto free_obj; 5437#endif 5438 default: 5439 goto free_obj; 5440 } 5441 5442 /* 5443 * Fallback to adding to the misc-objects slot. 5444 */ 5445 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5446 XP_CACHE_ADD(cache->miscObjs, obj); 5447 } else 5448 goto free_obj; 5449 5450obj_cached: 5451 5452#ifdef XP_DEBUG_OBJ_USAGE 5453 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5454#endif 5455 5456 if (obj->nodesetval != NULL) { 5457 xmlNodeSetPtr tmpset = obj->nodesetval; 5458 5459 /* 5460 * TODO: Due to those nasty ns-nodes, we need to traverse 5461 * the list and free the ns-nodes. 5462 * URGENT TODO: Check if it's actually slowing things down. 5463 * Maybe we shouldn't try to preserve the list. 5464 */ 5465 if (tmpset->nodeNr > 1) { 5466 int i; 5467 xmlNodePtr node; 5468 5469 for (i = 0; i < tmpset->nodeNr; i++) { 5470 node = tmpset->nodeTab[i]; 5471 if ((node != NULL) && 5472 (node->type == XML_NAMESPACE_DECL)) 5473 { 5474 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5475 } 5476 } 5477 } else if (tmpset->nodeNr == 1) { 5478 if ((tmpset->nodeTab[0] != NULL) && 5479 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5480 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5481 } 5482 tmpset->nodeNr = 0; 5483 memset(obj, 0, sizeof(xmlXPathObject)); 5484 obj->nodesetval = tmpset; 5485 } else 5486 memset(obj, 0, sizeof(xmlXPathObject)); 5487 5488 return; 5489 5490free_obj: 5491 /* 5492 * Cache is full; free the object. 5493 */ 5494 if (obj->nodesetval != NULL) 5495 xmlXPathFreeNodeSet(obj->nodesetval); 5496#ifdef XP_DEBUG_OBJ_USAGE 5497 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5498#endif 5499 xmlFree(obj); 5500 } 5501 return; 5502} 5503 5504 5505/************************************************************************ 5506 * * 5507 * Type Casting Routines * 5508 * * 5509 ************************************************************************/ 5510 5511/** 5512 * xmlXPathCastBooleanToString: 5513 * @val: a boolean 5514 * 5515 * Converts a boolean to its string value. 5516 * 5517 * Returns a newly allocated string. 5518 */ 5519xmlChar * 5520xmlXPathCastBooleanToString (int val) { 5521 xmlChar *ret; 5522 if (val) 5523 ret = xmlStrdup((const xmlChar *) "true"); 5524 else 5525 ret = xmlStrdup((const xmlChar *) "false"); 5526 return(ret); 5527} 5528 5529/** 5530 * xmlXPathCastNumberToString: 5531 * @val: a number 5532 * 5533 * Converts a number to its string value. 5534 * 5535 * Returns a newly allocated string. 5536 */ 5537xmlChar * 5538xmlXPathCastNumberToString (double val) { 5539 xmlChar *ret; 5540 switch (xmlXPathIsInf(val)) { 5541 case 1: 5542 ret = xmlStrdup((const xmlChar *) "Infinity"); 5543 break; 5544 case -1: 5545 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5546 break; 5547 default: 5548 if (xmlXPathIsNaN(val)) { 5549 ret = xmlStrdup((const xmlChar *) "NaN"); 5550 } else if (val == 0 && xmlXPathGetSign(val) != 0) { 5551 ret = xmlStrdup((const xmlChar *) "0"); 5552 } else { 5553 /* could be improved */ 5554 char buf[100]; 5555 xmlXPathFormatNumber(val, buf, 99); 5556 buf[99] = 0; 5557 ret = xmlStrdup((const xmlChar *) buf); 5558 } 5559 } 5560 return(ret); 5561} 5562 5563/** 5564 * xmlXPathCastNodeToString: 5565 * @node: a node 5566 * 5567 * Converts a node to its string value. 5568 * 5569 * Returns a newly allocated string. 5570 */ 5571xmlChar * 5572xmlXPathCastNodeToString (xmlNodePtr node) { 5573 return(xmlNodeGetContent(node)); 5574} 5575 5576/** 5577 * xmlXPathCastNodeSetToString: 5578 * @ns: a node-set 5579 * 5580 * Converts a node-set to its string value. 5581 * 5582 * Returns a newly allocated string. 5583 */ 5584xmlChar * 5585xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5586 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5587 return(xmlStrdup((const xmlChar *) "")); 5588 5589 if (ns->nodeNr > 1) 5590 xmlXPathNodeSetSort(ns); 5591 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5592} 5593 5594/** 5595 * xmlXPathCastToString: 5596 * @val: an XPath object 5597 * 5598 * Converts an existing object to its string() equivalent 5599 * 5600 * Returns the allocated string value of the object, NULL in case of error. 5601 * It's up to the caller to free the string memory with xmlFree(). 5602 */ 5603xmlChar * 5604xmlXPathCastToString(xmlXPathObjectPtr val) { 5605 xmlChar *ret = NULL; 5606 5607 if (val == NULL) 5608 return(xmlStrdup((const xmlChar *) "")); 5609 switch (val->type) { 5610 case XPATH_UNDEFINED: 5611#ifdef DEBUG_EXPR 5612 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5613#endif 5614 ret = xmlStrdup((const xmlChar *) ""); 5615 break; 5616 case XPATH_NODESET: 5617 case XPATH_XSLT_TREE: 5618 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5619 break; 5620 case XPATH_STRING: 5621 return(xmlStrdup(val->stringval)); 5622 case XPATH_BOOLEAN: 5623 ret = xmlXPathCastBooleanToString(val->boolval); 5624 break; 5625 case XPATH_NUMBER: { 5626 ret = xmlXPathCastNumberToString(val->floatval); 5627 break; 5628 } 5629 case XPATH_USERS: 5630 case XPATH_POINT: 5631 case XPATH_RANGE: 5632 case XPATH_LOCATIONSET: 5633 TODO 5634 ret = xmlStrdup((const xmlChar *) ""); 5635 break; 5636 } 5637 return(ret); 5638} 5639 5640/** 5641 * xmlXPathConvertString: 5642 * @val: an XPath object 5643 * 5644 * Converts an existing object to its string() equivalent 5645 * 5646 * Returns the new object, the old one is freed (or the operation 5647 * is done directly on @val) 5648 */ 5649xmlXPathObjectPtr 5650xmlXPathConvertString(xmlXPathObjectPtr val) { 5651 xmlChar *res = NULL; 5652 5653 if (val == NULL) 5654 return(xmlXPathNewCString("")); 5655 5656 switch (val->type) { 5657 case XPATH_UNDEFINED: 5658#ifdef DEBUG_EXPR 5659 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5660#endif 5661 break; 5662 case XPATH_NODESET: 5663 case XPATH_XSLT_TREE: 5664 res = xmlXPathCastNodeSetToString(val->nodesetval); 5665 break; 5666 case XPATH_STRING: 5667 return(val); 5668 case XPATH_BOOLEAN: 5669 res = xmlXPathCastBooleanToString(val->boolval); 5670 break; 5671 case XPATH_NUMBER: 5672 res = xmlXPathCastNumberToString(val->floatval); 5673 break; 5674 case XPATH_USERS: 5675 case XPATH_POINT: 5676 case XPATH_RANGE: 5677 case XPATH_LOCATIONSET: 5678 TODO; 5679 break; 5680 } 5681 xmlXPathFreeObject(val); 5682 if (res == NULL) 5683 return(xmlXPathNewCString("")); 5684 return(xmlXPathWrapString(res)); 5685} 5686 5687/** 5688 * xmlXPathCastBooleanToNumber: 5689 * @val: a boolean 5690 * 5691 * Converts a boolean to its number value 5692 * 5693 * Returns the number value 5694 */ 5695double 5696xmlXPathCastBooleanToNumber(int val) { 5697 if (val) 5698 return(1.0); 5699 return(0.0); 5700} 5701 5702/** 5703 * xmlXPathCastStringToNumber: 5704 * @val: a string 5705 * 5706 * Converts a string to its number value 5707 * 5708 * Returns the number value 5709 */ 5710double 5711xmlXPathCastStringToNumber(const xmlChar * val) { 5712 return(xmlXPathStringEvalNumber(val)); 5713} 5714 5715/** 5716 * xmlXPathCastNodeToNumber: 5717 * @node: a node 5718 * 5719 * Converts a node to its number value 5720 * 5721 * Returns the number value 5722 */ 5723double 5724xmlXPathCastNodeToNumber (xmlNodePtr node) { 5725 xmlChar *strval; 5726 double ret; 5727 5728 if (node == NULL) 5729 return(xmlXPathNAN); 5730 strval = xmlXPathCastNodeToString(node); 5731 if (strval == NULL) 5732 return(xmlXPathNAN); 5733 ret = xmlXPathCastStringToNumber(strval); 5734 xmlFree(strval); 5735 5736 return(ret); 5737} 5738 5739/** 5740 * xmlXPathCastNodeSetToNumber: 5741 * @ns: a node-set 5742 * 5743 * Converts a node-set to its number value 5744 * 5745 * Returns the number value 5746 */ 5747double 5748xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5749 xmlChar *str; 5750 double ret; 5751 5752 if (ns == NULL) 5753 return(xmlXPathNAN); 5754 str = xmlXPathCastNodeSetToString(ns); 5755 ret = xmlXPathCastStringToNumber(str); 5756 xmlFree(str); 5757 return(ret); 5758} 5759 5760/** 5761 * xmlXPathCastToNumber: 5762 * @val: an XPath object 5763 * 5764 * Converts an XPath object to its number value 5765 * 5766 * Returns the number value 5767 */ 5768double 5769xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5770 double ret = 0.0; 5771 5772 if (val == NULL) 5773 return(xmlXPathNAN); 5774 switch (val->type) { 5775 case XPATH_UNDEFINED: 5776#ifdef DEGUB_EXPR 5777 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5778#endif 5779 ret = xmlXPathNAN; 5780 break; 5781 case XPATH_NODESET: 5782 case XPATH_XSLT_TREE: 5783 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5784 break; 5785 case XPATH_STRING: 5786 ret = xmlXPathCastStringToNumber(val->stringval); 5787 break; 5788 case XPATH_NUMBER: 5789 ret = val->floatval; 5790 break; 5791 case XPATH_BOOLEAN: 5792 ret = xmlXPathCastBooleanToNumber(val->boolval); 5793 break; 5794 case XPATH_USERS: 5795 case XPATH_POINT: 5796 case XPATH_RANGE: 5797 case XPATH_LOCATIONSET: 5798 TODO; 5799 ret = xmlXPathNAN; 5800 break; 5801 } 5802 return(ret); 5803} 5804 5805/** 5806 * xmlXPathConvertNumber: 5807 * @val: an XPath object 5808 * 5809 * Converts an existing object to its number() equivalent 5810 * 5811 * Returns the new object, the old one is freed (or the operation 5812 * is done directly on @val) 5813 */ 5814xmlXPathObjectPtr 5815xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5816 xmlXPathObjectPtr ret; 5817 5818 if (val == NULL) 5819 return(xmlXPathNewFloat(0.0)); 5820 if (val->type == XPATH_NUMBER) 5821 return(val); 5822 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5823 xmlXPathFreeObject(val); 5824 return(ret); 5825} 5826 5827/** 5828 * xmlXPathCastNumberToBoolean: 5829 * @val: a number 5830 * 5831 * Converts a number to its boolean value 5832 * 5833 * Returns the boolean value 5834 */ 5835int 5836xmlXPathCastNumberToBoolean (double val) { 5837 if (xmlXPathIsNaN(val) || (val == 0.0)) 5838 return(0); 5839 return(1); 5840} 5841 5842/** 5843 * xmlXPathCastStringToBoolean: 5844 * @val: a string 5845 * 5846 * Converts a string to its boolean value 5847 * 5848 * Returns the boolean value 5849 */ 5850int 5851xmlXPathCastStringToBoolean (const xmlChar *val) { 5852 if ((val == NULL) || (xmlStrlen(val) == 0)) 5853 return(0); 5854 return(1); 5855} 5856 5857/** 5858 * xmlXPathCastNodeSetToBoolean: 5859 * @ns: a node-set 5860 * 5861 * Converts a node-set to its boolean value 5862 * 5863 * Returns the boolean value 5864 */ 5865int 5866xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 5867 if ((ns == NULL) || (ns->nodeNr == 0)) 5868 return(0); 5869 return(1); 5870} 5871 5872/** 5873 * xmlXPathCastToBoolean: 5874 * @val: an XPath object 5875 * 5876 * Converts an XPath object to its boolean value 5877 * 5878 * Returns the boolean value 5879 */ 5880int 5881xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 5882 int ret = 0; 5883 5884 if (val == NULL) 5885 return(0); 5886 switch (val->type) { 5887 case XPATH_UNDEFINED: 5888#ifdef DEBUG_EXPR 5889 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 5890#endif 5891 ret = 0; 5892 break; 5893 case XPATH_NODESET: 5894 case XPATH_XSLT_TREE: 5895 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 5896 break; 5897 case XPATH_STRING: 5898 ret = xmlXPathCastStringToBoolean(val->stringval); 5899 break; 5900 case XPATH_NUMBER: 5901 ret = xmlXPathCastNumberToBoolean(val->floatval); 5902 break; 5903 case XPATH_BOOLEAN: 5904 ret = val->boolval; 5905 break; 5906 case XPATH_USERS: 5907 case XPATH_POINT: 5908 case XPATH_RANGE: 5909 case XPATH_LOCATIONSET: 5910 TODO; 5911 ret = 0; 5912 break; 5913 } 5914 return(ret); 5915} 5916 5917 5918/** 5919 * xmlXPathConvertBoolean: 5920 * @val: an XPath object 5921 * 5922 * Converts an existing object to its boolean() equivalent 5923 * 5924 * Returns the new object, the old one is freed (or the operation 5925 * is done directly on @val) 5926 */ 5927xmlXPathObjectPtr 5928xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 5929 xmlXPathObjectPtr ret; 5930 5931 if (val == NULL) 5932 return(xmlXPathNewBoolean(0)); 5933 if (val->type == XPATH_BOOLEAN) 5934 return(val); 5935 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 5936 xmlXPathFreeObject(val); 5937 return(ret); 5938} 5939 5940/************************************************************************ 5941 * * 5942 * Routines to handle XPath contexts * 5943 * * 5944 ************************************************************************/ 5945 5946/** 5947 * xmlXPathNewContext: 5948 * @doc: the XML document 5949 * 5950 * Create a new xmlXPathContext 5951 * 5952 * Returns the xmlXPathContext just allocated. The caller will need to free it. 5953 */ 5954xmlXPathContextPtr 5955xmlXPathNewContext(xmlDocPtr doc) { 5956 xmlXPathContextPtr ret; 5957 5958 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 5959 if (ret == NULL) { 5960 xmlXPathErrMemory(NULL, "creating context\n"); 5961 return(NULL); 5962 } 5963 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 5964 ret->doc = doc; 5965 ret->node = NULL; 5966 5967 ret->varHash = NULL; 5968 5969 ret->nb_types = 0; 5970 ret->max_types = 0; 5971 ret->types = NULL; 5972 5973 ret->funcHash = xmlHashCreate(0); 5974 5975 ret->nb_axis = 0; 5976 ret->max_axis = 0; 5977 ret->axis = NULL; 5978 5979 ret->nsHash = NULL; 5980 ret->user = NULL; 5981 5982 ret->contextSize = -1; 5983 ret->proximityPosition = -1; 5984 5985#ifdef XP_DEFAULT_CACHE_ON 5986 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 5987 xmlXPathFreeContext(ret); 5988 return(NULL); 5989 } 5990#endif 5991 5992 xmlXPathRegisterAllFunctions(ret); 5993 5994 return(ret); 5995} 5996 5997/** 5998 * xmlXPathFreeContext: 5999 * @ctxt: the context to free 6000 * 6001 * Free up an xmlXPathContext 6002 */ 6003void 6004xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6005 if (ctxt == NULL) return; 6006 6007 if (ctxt->cache != NULL) 6008 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6009 xmlXPathRegisteredNsCleanup(ctxt); 6010 xmlXPathRegisteredFuncsCleanup(ctxt); 6011 xmlXPathRegisteredVariablesCleanup(ctxt); 6012 xmlResetError(&ctxt->lastError); 6013 xmlFree(ctxt); 6014} 6015 6016/************************************************************************ 6017 * * 6018 * Routines to handle XPath parser contexts * 6019 * * 6020 ************************************************************************/ 6021 6022#define CHECK_CTXT(ctxt) \ 6023 if (ctxt == NULL) { \ 6024 __xmlRaiseError(NULL, NULL, NULL, \ 6025 NULL, NULL, XML_FROM_XPATH, \ 6026 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6027 __FILE__, __LINE__, \ 6028 NULL, NULL, NULL, 0, 0, \ 6029 "NULL context pointer\n"); \ 6030 return(NULL); \ 6031 } \ 6032 6033#define CHECK_CTXT_NEG(ctxt) \ 6034 if (ctxt == NULL) { \ 6035 __xmlRaiseError(NULL, NULL, NULL, \ 6036 NULL, NULL, XML_FROM_XPATH, \ 6037 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6038 __FILE__, __LINE__, \ 6039 NULL, NULL, NULL, 0, 0, \ 6040 "NULL context pointer\n"); \ 6041 return(-1); \ 6042 } \ 6043 6044 6045#define CHECK_CONTEXT(ctxt) \ 6046 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6047 (ctxt->doc->children == NULL)) { \ 6048 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6049 return(NULL); \ 6050 } 6051 6052 6053/** 6054 * xmlXPathNewParserContext: 6055 * @str: the XPath expression 6056 * @ctxt: the XPath context 6057 * 6058 * Create a new xmlXPathParserContext 6059 * 6060 * Returns the xmlXPathParserContext just allocated. 6061 */ 6062xmlXPathParserContextPtr 6063xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6064 xmlXPathParserContextPtr ret; 6065 6066 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6067 if (ret == NULL) { 6068 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6069 return(NULL); 6070 } 6071 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6072 ret->cur = ret->base = str; 6073 ret->context = ctxt; 6074 6075 ret->comp = xmlXPathNewCompExpr(); 6076 if (ret->comp == NULL) { 6077 xmlFree(ret->valueTab); 6078 xmlFree(ret); 6079 return(NULL); 6080 } 6081 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6082 ret->comp->dict = ctxt->dict; 6083 xmlDictReference(ret->comp->dict); 6084 } 6085 6086 return(ret); 6087} 6088 6089/** 6090 * xmlXPathCompParserContext: 6091 * @comp: the XPath compiled expression 6092 * @ctxt: the XPath context 6093 * 6094 * Create a new xmlXPathParserContext when processing a compiled expression 6095 * 6096 * Returns the xmlXPathParserContext just allocated. 6097 */ 6098static xmlXPathParserContextPtr 6099xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6100 xmlXPathParserContextPtr ret; 6101 6102 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6103 if (ret == NULL) { 6104 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6105 return(NULL); 6106 } 6107 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6108 6109 /* Allocate the value stack */ 6110 ret->valueTab = (xmlXPathObjectPtr *) 6111 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6112 if (ret->valueTab == NULL) { 6113 xmlFree(ret); 6114 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6115 return(NULL); 6116 } 6117 ret->valueNr = 0; 6118 ret->valueMax = 10; 6119 ret->value = NULL; 6120 6121 ret->context = ctxt; 6122 ret->comp = comp; 6123 6124 return(ret); 6125} 6126 6127/** 6128 * xmlXPathFreeParserContext: 6129 * @ctxt: the context to free 6130 * 6131 * Free up an xmlXPathParserContext 6132 */ 6133void 6134xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6135 if (ctxt->valueTab != NULL) { 6136 xmlFree(ctxt->valueTab); 6137 } 6138 if (ctxt->comp != NULL) { 6139#ifdef XPATH_STREAMING 6140 if (ctxt->comp->stream != NULL) { 6141 xmlFreePatternList(ctxt->comp->stream); 6142 ctxt->comp->stream = NULL; 6143 } 6144#endif 6145 xmlXPathFreeCompExpr(ctxt->comp); 6146 } 6147 xmlFree(ctxt); 6148} 6149 6150/************************************************************************ 6151 * * 6152 * The implicit core function library * 6153 * * 6154 ************************************************************************/ 6155 6156/** 6157 * xmlXPathNodeValHash: 6158 * @node: a node pointer 6159 * 6160 * Function computing the beginning of the string value of the node, 6161 * used to speed up comparisons 6162 * 6163 * Returns an int usable as a hash 6164 */ 6165static unsigned int 6166xmlXPathNodeValHash(xmlNodePtr node) { 6167 int len = 2; 6168 const xmlChar * string = NULL; 6169 xmlNodePtr tmp = NULL; 6170 unsigned int ret = 0; 6171 6172 if (node == NULL) 6173 return(0); 6174 6175 if (node->type == XML_DOCUMENT_NODE) { 6176 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6177 if (tmp == NULL) 6178 node = node->children; 6179 else 6180 node = tmp; 6181 6182 if (node == NULL) 6183 return(0); 6184 } 6185 6186 switch (node->type) { 6187 case XML_COMMENT_NODE: 6188 case XML_PI_NODE: 6189 case XML_CDATA_SECTION_NODE: 6190 case XML_TEXT_NODE: 6191 string = node->content; 6192 if (string == NULL) 6193 return(0); 6194 if (string[0] == 0) 6195 return(0); 6196 return(((unsigned int) string[0]) + 6197 (((unsigned int) string[1]) << 8)); 6198 case XML_NAMESPACE_DECL: 6199 string = ((xmlNsPtr)node)->href; 6200 if (string == NULL) 6201 return(0); 6202 if (string[0] == 0) 6203 return(0); 6204 return(((unsigned int) string[0]) + 6205 (((unsigned int) string[1]) << 8)); 6206 case XML_ATTRIBUTE_NODE: 6207 tmp = ((xmlAttrPtr) node)->children; 6208 break; 6209 case XML_ELEMENT_NODE: 6210 tmp = node->children; 6211 break; 6212 default: 6213 return(0); 6214 } 6215 while (tmp != NULL) { 6216 switch (tmp->type) { 6217 case XML_COMMENT_NODE: 6218 case XML_PI_NODE: 6219 case XML_CDATA_SECTION_NODE: 6220 case XML_TEXT_NODE: 6221 string = tmp->content; 6222 break; 6223 case XML_NAMESPACE_DECL: 6224 string = ((xmlNsPtr)tmp)->href; 6225 break; 6226 default: 6227 break; 6228 } 6229 if ((string != NULL) && (string[0] != 0)) { 6230 if (len == 1) { 6231 return(ret + (((unsigned int) string[0]) << 8)); 6232 } 6233 if (string[1] == 0) { 6234 len = 1; 6235 ret = (unsigned int) string[0]; 6236 } else { 6237 return(((unsigned int) string[0]) + 6238 (((unsigned int) string[1]) << 8)); 6239 } 6240 } 6241 /* 6242 * Skip to next node 6243 */ 6244 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6245 if (tmp->children->type != XML_ENTITY_DECL) { 6246 tmp = tmp->children; 6247 continue; 6248 } 6249 } 6250 if (tmp == node) 6251 break; 6252 6253 if (tmp->next != NULL) { 6254 tmp = tmp->next; 6255 continue; 6256 } 6257 6258 do { 6259 tmp = tmp->parent; 6260 if (tmp == NULL) 6261 break; 6262 if (tmp == node) { 6263 tmp = NULL; 6264 break; 6265 } 6266 if (tmp->next != NULL) { 6267 tmp = tmp->next; 6268 break; 6269 } 6270 } while (tmp != NULL); 6271 } 6272 return(ret); 6273} 6274 6275/** 6276 * xmlXPathStringHash: 6277 * @string: a string 6278 * 6279 * Function computing the beginning of the string value of the node, 6280 * used to speed up comparisons 6281 * 6282 * Returns an int usable as a hash 6283 */ 6284static unsigned int 6285xmlXPathStringHash(const xmlChar * string) { 6286 if (string == NULL) 6287 return((unsigned int) 0); 6288 if (string[0] == 0) 6289 return(0); 6290 return(((unsigned int) string[0]) + 6291 (((unsigned int) string[1]) << 8)); 6292} 6293 6294/** 6295 * xmlXPathCompareNodeSetFloat: 6296 * @ctxt: the XPath Parser context 6297 * @inf: less than (1) or greater than (0) 6298 * @strict: is the comparison strict 6299 * @arg: the node set 6300 * @f: the value 6301 * 6302 * Implement the compare operation between a nodeset and a number 6303 * @ns < @val (1, 1, ... 6304 * @ns <= @val (1, 0, ... 6305 * @ns > @val (0, 1, ... 6306 * @ns >= @val (0, 0, ... 6307 * 6308 * If one object to be compared is a node-set and the other is a number, 6309 * then the comparison will be true if and only if there is a node in the 6310 * node-set such that the result of performing the comparison on the number 6311 * to be compared and on the result of converting the string-value of that 6312 * node to a number using the number function is true. 6313 * 6314 * Returns 0 or 1 depending on the results of the test. 6315 */ 6316static int 6317xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6318 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6319 int i, ret = 0; 6320 xmlNodeSetPtr ns; 6321 xmlChar *str2; 6322 6323 if ((f == NULL) || (arg == NULL) || 6324 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6325 xmlXPathReleaseObject(ctxt->context, arg); 6326 xmlXPathReleaseObject(ctxt->context, f); 6327 return(0); 6328 } 6329 ns = arg->nodesetval; 6330 if (ns != NULL) { 6331 for (i = 0;i < ns->nodeNr;i++) { 6332 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6333 if (str2 != NULL) { 6334 valuePush(ctxt, 6335 xmlXPathCacheNewString(ctxt->context, str2)); 6336 xmlFree(str2); 6337 xmlXPathNumberFunction(ctxt, 1); 6338 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6339 ret = xmlXPathCompareValues(ctxt, inf, strict); 6340 if (ret) 6341 break; 6342 } 6343 } 6344 } 6345 xmlXPathReleaseObject(ctxt->context, arg); 6346 xmlXPathReleaseObject(ctxt->context, f); 6347 return(ret); 6348} 6349 6350/** 6351 * xmlXPathCompareNodeSetString: 6352 * @ctxt: the XPath Parser context 6353 * @inf: less than (1) or greater than (0) 6354 * @strict: is the comparison strict 6355 * @arg: the node set 6356 * @s: the value 6357 * 6358 * Implement the compare operation between a nodeset and a string 6359 * @ns < @val (1, 1, ... 6360 * @ns <= @val (1, 0, ... 6361 * @ns > @val (0, 1, ... 6362 * @ns >= @val (0, 0, ... 6363 * 6364 * If one object to be compared is a node-set and the other is a string, 6365 * then the comparison will be true if and only if there is a node in 6366 * the node-set such that the result of performing the comparison on the 6367 * string-value of the node and the other string is true. 6368 * 6369 * Returns 0 or 1 depending on the results of the test. 6370 */ 6371static int 6372xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6373 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6374 int i, ret = 0; 6375 xmlNodeSetPtr ns; 6376 xmlChar *str2; 6377 6378 if ((s == NULL) || (arg == NULL) || 6379 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6380 xmlXPathReleaseObject(ctxt->context, arg); 6381 xmlXPathReleaseObject(ctxt->context, s); 6382 return(0); 6383 } 6384 ns = arg->nodesetval; 6385 if (ns != NULL) { 6386 for (i = 0;i < ns->nodeNr;i++) { 6387 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6388 if (str2 != NULL) { 6389 valuePush(ctxt, 6390 xmlXPathCacheNewString(ctxt->context, str2)); 6391 xmlFree(str2); 6392 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6393 ret = xmlXPathCompareValues(ctxt, inf, strict); 6394 if (ret) 6395 break; 6396 } 6397 } 6398 } 6399 xmlXPathReleaseObject(ctxt->context, arg); 6400 xmlXPathReleaseObject(ctxt->context, s); 6401 return(ret); 6402} 6403 6404/** 6405 * xmlXPathCompareNodeSets: 6406 * @inf: less than (1) or greater than (0) 6407 * @strict: is the comparison strict 6408 * @arg1: the first node set object 6409 * @arg2: the second node set object 6410 * 6411 * Implement the compare operation on nodesets: 6412 * 6413 * If both objects to be compared are node-sets, then the comparison 6414 * will be true if and only if there is a node in the first node-set 6415 * and a node in the second node-set such that the result of performing 6416 * the comparison on the string-values of the two nodes is true. 6417 * .... 6418 * When neither object to be compared is a node-set and the operator 6419 * is <=, <, >= or >, then the objects are compared by converting both 6420 * objects to numbers and comparing the numbers according to IEEE 754. 6421 * .... 6422 * The number function converts its argument to a number as follows: 6423 * - a string that consists of optional whitespace followed by an 6424 * optional minus sign followed by a Number followed by whitespace 6425 * is converted to the IEEE 754 number that is nearest (according 6426 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6427 * represented by the string; any other string is converted to NaN 6428 * 6429 * Conclusion all nodes need to be converted first to their string value 6430 * and then the comparison must be done when possible 6431 */ 6432static int 6433xmlXPathCompareNodeSets(int inf, int strict, 6434 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6435 int i, j, init = 0; 6436 double val1; 6437 double *values2; 6438 int ret = 0; 6439 xmlNodeSetPtr ns1; 6440 xmlNodeSetPtr ns2; 6441 6442 if ((arg1 == NULL) || 6443 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6444 xmlXPathFreeObject(arg2); 6445 return(0); 6446 } 6447 if ((arg2 == NULL) || 6448 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6449 xmlXPathFreeObject(arg1); 6450 xmlXPathFreeObject(arg2); 6451 return(0); 6452 } 6453 6454 ns1 = arg1->nodesetval; 6455 ns2 = arg2->nodesetval; 6456 6457 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6458 xmlXPathFreeObject(arg1); 6459 xmlXPathFreeObject(arg2); 6460 return(0); 6461 } 6462 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6463 xmlXPathFreeObject(arg1); 6464 xmlXPathFreeObject(arg2); 6465 return(0); 6466 } 6467 6468 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6469 if (values2 == NULL) { 6470 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6471 xmlXPathFreeObject(arg1); 6472 xmlXPathFreeObject(arg2); 6473 return(0); 6474 } 6475 for (i = 0;i < ns1->nodeNr;i++) { 6476 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6477 if (xmlXPathIsNaN(val1)) 6478 continue; 6479 for (j = 0;j < ns2->nodeNr;j++) { 6480 if (init == 0) { 6481 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6482 } 6483 if (xmlXPathIsNaN(values2[j])) 6484 continue; 6485 if (inf && strict) 6486 ret = (val1 < values2[j]); 6487 else if (inf && !strict) 6488 ret = (val1 <= values2[j]); 6489 else if (!inf && strict) 6490 ret = (val1 > values2[j]); 6491 else if (!inf && !strict) 6492 ret = (val1 >= values2[j]); 6493 if (ret) 6494 break; 6495 } 6496 if (ret) 6497 break; 6498 init = 1; 6499 } 6500 xmlFree(values2); 6501 xmlXPathFreeObject(arg1); 6502 xmlXPathFreeObject(arg2); 6503 return(ret); 6504} 6505 6506/** 6507 * xmlXPathCompareNodeSetValue: 6508 * @ctxt: the XPath Parser context 6509 * @inf: less than (1) or greater than (0) 6510 * @strict: is the comparison strict 6511 * @arg: the node set 6512 * @val: the value 6513 * 6514 * Implement the compare operation between a nodeset and a value 6515 * @ns < @val (1, 1, ... 6516 * @ns <= @val (1, 0, ... 6517 * @ns > @val (0, 1, ... 6518 * @ns >= @val (0, 0, ... 6519 * 6520 * If one object to be compared is a node-set and the other is a boolean, 6521 * then the comparison will be true if and only if the result of performing 6522 * the comparison on the boolean and on the result of converting 6523 * the node-set to a boolean using the boolean function is true. 6524 * 6525 * Returns 0 or 1 depending on the results of the test. 6526 */ 6527static int 6528xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6529 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6530 if ((val == NULL) || (arg == NULL) || 6531 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6532 return(0); 6533 6534 switch(val->type) { 6535 case XPATH_NUMBER: 6536 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6537 case XPATH_NODESET: 6538 case XPATH_XSLT_TREE: 6539 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6540 case XPATH_STRING: 6541 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6542 case XPATH_BOOLEAN: 6543 valuePush(ctxt, arg); 6544 xmlXPathBooleanFunction(ctxt, 1); 6545 valuePush(ctxt, val); 6546 return(xmlXPathCompareValues(ctxt, inf, strict)); 6547 default: 6548 TODO 6549 } 6550 return(0); 6551} 6552 6553/** 6554 * xmlXPathEqualNodeSetString: 6555 * @arg: the nodeset object argument 6556 * @str: the string to compare to. 6557 * @neq: flag to show whether for '=' (0) or '!=' (1) 6558 * 6559 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6560 * If one object to be compared is a node-set and the other is a string, 6561 * then the comparison will be true if and only if there is a node in 6562 * the node-set such that the result of performing the comparison on the 6563 * string-value of the node and the other string is true. 6564 * 6565 * Returns 0 or 1 depending on the results of the test. 6566 */ 6567static int 6568xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6569{ 6570 int i; 6571 xmlNodeSetPtr ns; 6572 xmlChar *str2; 6573 unsigned int hash; 6574 6575 if ((str == NULL) || (arg == NULL) || 6576 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6577 return (0); 6578 ns = arg->nodesetval; 6579 /* 6580 * A NULL nodeset compared with a string is always false 6581 * (since there is no node equal, and no node not equal) 6582 */ 6583 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6584 return (0); 6585 hash = xmlXPathStringHash(str); 6586 for (i = 0; i < ns->nodeNr; i++) { 6587 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6588 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6589 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6590 xmlFree(str2); 6591 if (neq) 6592 continue; 6593 return (1); 6594 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6595 if (neq) 6596 continue; 6597 return (1); 6598 } else if (neq) { 6599 if (str2 != NULL) 6600 xmlFree(str2); 6601 return (1); 6602 } 6603 if (str2 != NULL) 6604 xmlFree(str2); 6605 } else if (neq) 6606 return (1); 6607 } 6608 return (0); 6609} 6610 6611/** 6612 * xmlXPathEqualNodeSetFloat: 6613 * @arg: the nodeset object argument 6614 * @f: the float to compare to 6615 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6616 * 6617 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6618 * If one object to be compared is a node-set and the other is a number, 6619 * then the comparison will be true if and only if there is a node in 6620 * the node-set such that the result of performing the comparison on the 6621 * number to be compared and on the result of converting the string-value 6622 * of that node to a number using the number function is true. 6623 * 6624 * Returns 0 or 1 depending on the results of the test. 6625 */ 6626static int 6627xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6628 xmlXPathObjectPtr arg, double f, int neq) { 6629 int i, ret=0; 6630 xmlNodeSetPtr ns; 6631 xmlChar *str2; 6632 xmlXPathObjectPtr val; 6633 double v; 6634 6635 if ((arg == NULL) || 6636 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6637 return(0); 6638 6639 ns = arg->nodesetval; 6640 if (ns != NULL) { 6641 for (i=0;i<ns->nodeNr;i++) { 6642 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6643 if (str2 != NULL) { 6644 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6645 xmlFree(str2); 6646 xmlXPathNumberFunction(ctxt, 1); 6647 val = valuePop(ctxt); 6648 v = val->floatval; 6649 xmlXPathReleaseObject(ctxt->context, val); 6650 if (!xmlXPathIsNaN(v)) { 6651 if ((!neq) && (v==f)) { 6652 ret = 1; 6653 break; 6654 } else if ((neq) && (v!=f)) { 6655 ret = 1; 6656 break; 6657 } 6658 } else { /* NaN is unequal to any value */ 6659 if (neq) 6660 ret = 1; 6661 } 6662 } 6663 } 6664 } 6665 6666 return(ret); 6667} 6668 6669 6670/** 6671 * xmlXPathEqualNodeSets: 6672 * @arg1: first nodeset object argument 6673 * @arg2: second nodeset object argument 6674 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6675 * 6676 * Implement the equal / not equal operation on XPath nodesets: 6677 * @arg1 == @arg2 or @arg1 != @arg2 6678 * If both objects to be compared are node-sets, then the comparison 6679 * will be true if and only if there is a node in the first node-set and 6680 * a node in the second node-set such that the result of performing the 6681 * comparison on the string-values of the two nodes is true. 6682 * 6683 * (needless to say, this is a costly operation) 6684 * 6685 * Returns 0 or 1 depending on the results of the test. 6686 */ 6687static int 6688xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6689 int i, j; 6690 unsigned int *hashs1; 6691 unsigned int *hashs2; 6692 xmlChar **values1; 6693 xmlChar **values2; 6694 int ret = 0; 6695 xmlNodeSetPtr ns1; 6696 xmlNodeSetPtr ns2; 6697 6698 if ((arg1 == NULL) || 6699 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6700 return(0); 6701 if ((arg2 == NULL) || 6702 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6703 return(0); 6704 6705 ns1 = arg1->nodesetval; 6706 ns2 = arg2->nodesetval; 6707 6708 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6709 return(0); 6710 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6711 return(0); 6712 6713 /* 6714 * for equal, check if there is a node pertaining to both sets 6715 */ 6716 if (neq == 0) 6717 for (i = 0;i < ns1->nodeNr;i++) 6718 for (j = 0;j < ns2->nodeNr;j++) 6719 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6720 return(1); 6721 6722 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6723 if (values1 == NULL) { 6724 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6725 return(0); 6726 } 6727 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6728 if (hashs1 == NULL) { 6729 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6730 xmlFree(values1); 6731 return(0); 6732 } 6733 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6734 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6735 if (values2 == NULL) { 6736 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6737 xmlFree(hashs1); 6738 xmlFree(values1); 6739 return(0); 6740 } 6741 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6742 if (hashs2 == NULL) { 6743 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6744 xmlFree(hashs1); 6745 xmlFree(values1); 6746 xmlFree(values2); 6747 return(0); 6748 } 6749 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6750 for (i = 0;i < ns1->nodeNr;i++) { 6751 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6752 for (j = 0;j < ns2->nodeNr;j++) { 6753 if (i == 0) 6754 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6755 if (hashs1[i] != hashs2[j]) { 6756 if (neq) { 6757 ret = 1; 6758 break; 6759 } 6760 } 6761 else { 6762 if (values1[i] == NULL) 6763 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6764 if (values2[j] == NULL) 6765 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6766 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6767 if (ret) 6768 break; 6769 } 6770 } 6771 if (ret) 6772 break; 6773 } 6774 for (i = 0;i < ns1->nodeNr;i++) 6775 if (values1[i] != NULL) 6776 xmlFree(values1[i]); 6777 for (j = 0;j < ns2->nodeNr;j++) 6778 if (values2[j] != NULL) 6779 xmlFree(values2[j]); 6780 xmlFree(values1); 6781 xmlFree(values2); 6782 xmlFree(hashs1); 6783 xmlFree(hashs2); 6784 return(ret); 6785} 6786 6787static int 6788xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6789 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6790 int ret = 0; 6791 /* 6792 *At this point we are assured neither arg1 nor arg2 6793 *is a nodeset, so we can just pick the appropriate routine. 6794 */ 6795 switch (arg1->type) { 6796 case XPATH_UNDEFINED: 6797#ifdef DEBUG_EXPR 6798 xmlGenericError(xmlGenericErrorContext, 6799 "Equal: undefined\n"); 6800#endif 6801 break; 6802 case XPATH_BOOLEAN: 6803 switch (arg2->type) { 6804 case XPATH_UNDEFINED: 6805#ifdef DEBUG_EXPR 6806 xmlGenericError(xmlGenericErrorContext, 6807 "Equal: undefined\n"); 6808#endif 6809 break; 6810 case XPATH_BOOLEAN: 6811#ifdef DEBUG_EXPR 6812 xmlGenericError(xmlGenericErrorContext, 6813 "Equal: %d boolean %d \n", 6814 arg1->boolval, arg2->boolval); 6815#endif 6816 ret = (arg1->boolval == arg2->boolval); 6817 break; 6818 case XPATH_NUMBER: 6819 ret = (arg1->boolval == 6820 xmlXPathCastNumberToBoolean(arg2->floatval)); 6821 break; 6822 case XPATH_STRING: 6823 if ((arg2->stringval == NULL) || 6824 (arg2->stringval[0] == 0)) ret = 0; 6825 else 6826 ret = 1; 6827 ret = (arg1->boolval == ret); 6828 break; 6829 case XPATH_USERS: 6830 case XPATH_POINT: 6831 case XPATH_RANGE: 6832 case XPATH_LOCATIONSET: 6833 TODO 6834 break; 6835 case XPATH_NODESET: 6836 case XPATH_XSLT_TREE: 6837 break; 6838 } 6839 break; 6840 case XPATH_NUMBER: 6841 switch (arg2->type) { 6842 case XPATH_UNDEFINED: 6843#ifdef DEBUG_EXPR 6844 xmlGenericError(xmlGenericErrorContext, 6845 "Equal: undefined\n"); 6846#endif 6847 break; 6848 case XPATH_BOOLEAN: 6849 ret = (arg2->boolval== 6850 xmlXPathCastNumberToBoolean(arg1->floatval)); 6851 break; 6852 case XPATH_STRING: 6853 valuePush(ctxt, arg2); 6854 xmlXPathNumberFunction(ctxt, 1); 6855 arg2 = valuePop(ctxt); 6856 /* no break on purpose */ 6857 case XPATH_NUMBER: 6858 /* Hand check NaN and Infinity equalities */ 6859 if (xmlXPathIsNaN(arg1->floatval) || 6860 xmlXPathIsNaN(arg2->floatval)) { 6861 ret = 0; 6862 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 6863 if (xmlXPathIsInf(arg2->floatval) == 1) 6864 ret = 1; 6865 else 6866 ret = 0; 6867 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 6868 if (xmlXPathIsInf(arg2->floatval) == -1) 6869 ret = 1; 6870 else 6871 ret = 0; 6872 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 6873 if (xmlXPathIsInf(arg1->floatval) == 1) 6874 ret = 1; 6875 else 6876 ret = 0; 6877 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 6878 if (xmlXPathIsInf(arg1->floatval) == -1) 6879 ret = 1; 6880 else 6881 ret = 0; 6882 } else { 6883 ret = (arg1->floatval == arg2->floatval); 6884 } 6885 break; 6886 case XPATH_USERS: 6887 case XPATH_POINT: 6888 case XPATH_RANGE: 6889 case XPATH_LOCATIONSET: 6890 TODO 6891 break; 6892 case XPATH_NODESET: 6893 case XPATH_XSLT_TREE: 6894 break; 6895 } 6896 break; 6897 case XPATH_STRING: 6898 switch (arg2->type) { 6899 case XPATH_UNDEFINED: 6900#ifdef DEBUG_EXPR 6901 xmlGenericError(xmlGenericErrorContext, 6902 "Equal: undefined\n"); 6903#endif 6904 break; 6905 case XPATH_BOOLEAN: 6906 if ((arg1->stringval == NULL) || 6907 (arg1->stringval[0] == 0)) ret = 0; 6908 else 6909 ret = 1; 6910 ret = (arg2->boolval == ret); 6911 break; 6912 case XPATH_STRING: 6913 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 6914 break; 6915 case XPATH_NUMBER: 6916 valuePush(ctxt, arg1); 6917 xmlXPathNumberFunction(ctxt, 1); 6918 arg1 = valuePop(ctxt); 6919 /* Hand check NaN and Infinity equalities */ 6920 if (xmlXPathIsNaN(arg1->floatval) || 6921 xmlXPathIsNaN(arg2->floatval)) { 6922 ret = 0; 6923 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 6924 if (xmlXPathIsInf(arg2->floatval) == 1) 6925 ret = 1; 6926 else 6927 ret = 0; 6928 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 6929 if (xmlXPathIsInf(arg2->floatval) == -1) 6930 ret = 1; 6931 else 6932 ret = 0; 6933 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 6934 if (xmlXPathIsInf(arg1->floatval) == 1) 6935 ret = 1; 6936 else 6937 ret = 0; 6938 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 6939 if (xmlXPathIsInf(arg1->floatval) == -1) 6940 ret = 1; 6941 else 6942 ret = 0; 6943 } else { 6944 ret = (arg1->floatval == arg2->floatval); 6945 } 6946 break; 6947 case XPATH_USERS: 6948 case XPATH_POINT: 6949 case XPATH_RANGE: 6950 case XPATH_LOCATIONSET: 6951 TODO 6952 break; 6953 case XPATH_NODESET: 6954 case XPATH_XSLT_TREE: 6955 break; 6956 } 6957 break; 6958 case XPATH_USERS: 6959 case XPATH_POINT: 6960 case XPATH_RANGE: 6961 case XPATH_LOCATIONSET: 6962 TODO 6963 break; 6964 case XPATH_NODESET: 6965 case XPATH_XSLT_TREE: 6966 break; 6967 } 6968 xmlXPathReleaseObject(ctxt->context, arg1); 6969 xmlXPathReleaseObject(ctxt->context, arg2); 6970 return(ret); 6971} 6972 6973/** 6974 * xmlXPathEqualValues: 6975 * @ctxt: the XPath Parser context 6976 * 6977 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6978 * 6979 * Returns 0 or 1 depending on the results of the test. 6980 */ 6981int 6982xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 6983 xmlXPathObjectPtr arg1, arg2, argtmp; 6984 int ret = 0; 6985 6986 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 6987 arg2 = valuePop(ctxt); 6988 arg1 = valuePop(ctxt); 6989 if ((arg1 == NULL) || (arg2 == NULL)) { 6990 if (arg1 != NULL) 6991 xmlXPathReleaseObject(ctxt->context, arg1); 6992 else 6993 xmlXPathReleaseObject(ctxt->context, arg2); 6994 XP_ERROR0(XPATH_INVALID_OPERAND); 6995 } 6996 6997 if (arg1 == arg2) { 6998#ifdef DEBUG_EXPR 6999 xmlGenericError(xmlGenericErrorContext, 7000 "Equal: by pointer\n"); 7001#endif 7002 xmlXPathFreeObject(arg1); 7003 return(1); 7004 } 7005 7006 /* 7007 *If either argument is a nodeset, it's a 'special case' 7008 */ 7009 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7010 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7011 /* 7012 *Hack it to assure arg1 is the nodeset 7013 */ 7014 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7015 argtmp = arg2; 7016 arg2 = arg1; 7017 arg1 = argtmp; 7018 } 7019 switch (arg2->type) { 7020 case XPATH_UNDEFINED: 7021#ifdef DEBUG_EXPR 7022 xmlGenericError(xmlGenericErrorContext, 7023 "Equal: undefined\n"); 7024#endif 7025 break; 7026 case XPATH_NODESET: 7027 case XPATH_XSLT_TREE: 7028 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7029 break; 7030 case XPATH_BOOLEAN: 7031 if ((arg1->nodesetval == NULL) || 7032 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7033 else 7034 ret = 1; 7035 ret = (ret == arg2->boolval); 7036 break; 7037 case XPATH_NUMBER: 7038 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7039 break; 7040 case XPATH_STRING: 7041 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7042 break; 7043 case XPATH_USERS: 7044 case XPATH_POINT: 7045 case XPATH_RANGE: 7046 case XPATH_LOCATIONSET: 7047 TODO 7048 break; 7049 } 7050 xmlXPathReleaseObject(ctxt->context, arg1); 7051 xmlXPathReleaseObject(ctxt->context, arg2); 7052 return(ret); 7053 } 7054 7055 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7056} 7057 7058/** 7059 * xmlXPathNotEqualValues: 7060 * @ctxt: the XPath Parser context 7061 * 7062 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7063 * 7064 * Returns 0 or 1 depending on the results of the test. 7065 */ 7066int 7067xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7068 xmlXPathObjectPtr arg1, arg2, argtmp; 7069 int ret = 0; 7070 7071 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7072 arg2 = valuePop(ctxt); 7073 arg1 = valuePop(ctxt); 7074 if ((arg1 == NULL) || (arg2 == NULL)) { 7075 if (arg1 != NULL) 7076 xmlXPathReleaseObject(ctxt->context, arg1); 7077 else 7078 xmlXPathReleaseObject(ctxt->context, arg2); 7079 XP_ERROR0(XPATH_INVALID_OPERAND); 7080 } 7081 7082 if (arg1 == arg2) { 7083#ifdef DEBUG_EXPR 7084 xmlGenericError(xmlGenericErrorContext, 7085 "NotEqual: by pointer\n"); 7086#endif 7087 xmlXPathReleaseObject(ctxt->context, arg1); 7088 return(0); 7089 } 7090 7091 /* 7092 *If either argument is a nodeset, it's a 'special case' 7093 */ 7094 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7095 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7096 /* 7097 *Hack it to assure arg1 is the nodeset 7098 */ 7099 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7100 argtmp = arg2; 7101 arg2 = arg1; 7102 arg1 = argtmp; 7103 } 7104 switch (arg2->type) { 7105 case XPATH_UNDEFINED: 7106#ifdef DEBUG_EXPR 7107 xmlGenericError(xmlGenericErrorContext, 7108 "NotEqual: undefined\n"); 7109#endif 7110 break; 7111 case XPATH_NODESET: 7112 case XPATH_XSLT_TREE: 7113 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7114 break; 7115 case XPATH_BOOLEAN: 7116 if ((arg1->nodesetval == NULL) || 7117 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7118 else 7119 ret = 1; 7120 ret = (ret != arg2->boolval); 7121 break; 7122 case XPATH_NUMBER: 7123 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7124 break; 7125 case XPATH_STRING: 7126 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7127 break; 7128 case XPATH_USERS: 7129 case XPATH_POINT: 7130 case XPATH_RANGE: 7131 case XPATH_LOCATIONSET: 7132 TODO 7133 break; 7134 } 7135 xmlXPathReleaseObject(ctxt->context, arg1); 7136 xmlXPathReleaseObject(ctxt->context, arg2); 7137 return(ret); 7138 } 7139 7140 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7141} 7142 7143/** 7144 * xmlXPathCompareValues: 7145 * @ctxt: the XPath Parser context 7146 * @inf: less than (1) or greater than (0) 7147 * @strict: is the comparison strict 7148 * 7149 * Implement the compare operation on XPath objects: 7150 * @arg1 < @arg2 (1, 1, ... 7151 * @arg1 <= @arg2 (1, 0, ... 7152 * @arg1 > @arg2 (0, 1, ... 7153 * @arg1 >= @arg2 (0, 0, ... 7154 * 7155 * When neither object to be compared is a node-set and the operator is 7156 * <=, <, >=, >, then the objects are compared by converted both objects 7157 * to numbers and comparing the numbers according to IEEE 754. The < 7158 * comparison will be true if and only if the first number is less than the 7159 * second number. The <= comparison will be true if and only if the first 7160 * number is less than or equal to the second number. The > comparison 7161 * will be true if and only if the first number is greater than the second 7162 * number. The >= comparison will be true if and only if the first number 7163 * is greater than or equal to the second number. 7164 * 7165 * Returns 1 if the comparison succeeded, 0 if it failed 7166 */ 7167int 7168xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7169 int ret = 0, arg1i = 0, arg2i = 0; 7170 xmlXPathObjectPtr arg1, arg2; 7171 7172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7173 arg2 = valuePop(ctxt); 7174 arg1 = valuePop(ctxt); 7175 if ((arg1 == NULL) || (arg2 == NULL)) { 7176 if (arg1 != NULL) 7177 xmlXPathReleaseObject(ctxt->context, arg1); 7178 else 7179 xmlXPathReleaseObject(ctxt->context, arg2); 7180 XP_ERROR0(XPATH_INVALID_OPERAND); 7181 } 7182 7183 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7184 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7185 /* 7186 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7187 * are not freed from within this routine; they will be freed from the 7188 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7189 */ 7190 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7191 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7192 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7193 } else { 7194 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7195 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7196 arg1, arg2); 7197 } else { 7198 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7199 arg2, arg1); 7200 } 7201 } 7202 return(ret); 7203 } 7204 7205 if (arg1->type != XPATH_NUMBER) { 7206 valuePush(ctxt, arg1); 7207 xmlXPathNumberFunction(ctxt, 1); 7208 arg1 = valuePop(ctxt); 7209 } 7210 if (arg1->type != XPATH_NUMBER) { 7211 xmlXPathFreeObject(arg1); 7212 xmlXPathFreeObject(arg2); 7213 XP_ERROR0(XPATH_INVALID_OPERAND); 7214 } 7215 if (arg2->type != XPATH_NUMBER) { 7216 valuePush(ctxt, arg2); 7217 xmlXPathNumberFunction(ctxt, 1); 7218 arg2 = valuePop(ctxt); 7219 } 7220 if (arg2->type != XPATH_NUMBER) { 7221 xmlXPathReleaseObject(ctxt->context, arg1); 7222 xmlXPathReleaseObject(ctxt->context, arg2); 7223 XP_ERROR0(XPATH_INVALID_OPERAND); 7224 } 7225 /* 7226 * Add tests for infinity and nan 7227 * => feedback on 3.4 for Inf and NaN 7228 */ 7229 /* Hand check NaN and Infinity comparisons */ 7230 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7231 ret=0; 7232 } else { 7233 arg1i=xmlXPathIsInf(arg1->floatval); 7234 arg2i=xmlXPathIsInf(arg2->floatval); 7235 if (inf && strict) { 7236 if ((arg1i == -1 && arg2i != -1) || 7237 (arg2i == 1 && arg1i != 1)) { 7238 ret = 1; 7239 } else if (arg1i == 0 && arg2i == 0) { 7240 ret = (arg1->floatval < arg2->floatval); 7241 } else { 7242 ret = 0; 7243 } 7244 } 7245 else if (inf && !strict) { 7246 if (arg1i == -1 || arg2i == 1) { 7247 ret = 1; 7248 } else if (arg1i == 0 && arg2i == 0) { 7249 ret = (arg1->floatval <= arg2->floatval); 7250 } else { 7251 ret = 0; 7252 } 7253 } 7254 else if (!inf && strict) { 7255 if ((arg1i == 1 && arg2i != 1) || 7256 (arg2i == -1 && arg1i != -1)) { 7257 ret = 1; 7258 } else if (arg1i == 0 && arg2i == 0) { 7259 ret = (arg1->floatval > arg2->floatval); 7260 } else { 7261 ret = 0; 7262 } 7263 } 7264 else if (!inf && !strict) { 7265 if (arg1i == 1 || arg2i == -1) { 7266 ret = 1; 7267 } else if (arg1i == 0 && arg2i == 0) { 7268 ret = (arg1->floatval >= arg2->floatval); 7269 } else { 7270 ret = 0; 7271 } 7272 } 7273 } 7274 xmlXPathReleaseObject(ctxt->context, arg1); 7275 xmlXPathReleaseObject(ctxt->context, arg2); 7276 return(ret); 7277} 7278 7279/** 7280 * xmlXPathValueFlipSign: 7281 * @ctxt: the XPath Parser context 7282 * 7283 * Implement the unary - operation on an XPath object 7284 * The numeric operators convert their operands to numbers as if 7285 * by calling the number function. 7286 */ 7287void 7288xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7289 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7290 CAST_TO_NUMBER; 7291 CHECK_TYPE(XPATH_NUMBER); 7292 if (xmlXPathIsNaN(ctxt->value->floatval)) 7293 ctxt->value->floatval=xmlXPathNAN; 7294 else if (xmlXPathIsInf(ctxt->value->floatval) == 1) 7295 ctxt->value->floatval=xmlXPathNINF; 7296 else if (xmlXPathIsInf(ctxt->value->floatval) == -1) 7297 ctxt->value->floatval=xmlXPathPINF; 7298 else if (ctxt->value->floatval == 0) { 7299 if (xmlXPathGetSign(ctxt->value->floatval) == 0) 7300 ctxt->value->floatval = xmlXPathNZERO; 7301 else 7302 ctxt->value->floatval = 0; 7303 } 7304 else 7305 ctxt->value->floatval = - ctxt->value->floatval; 7306} 7307 7308/** 7309 * xmlXPathAddValues: 7310 * @ctxt: the XPath Parser context 7311 * 7312 * Implement the add operation on XPath objects: 7313 * The numeric operators convert their operands to numbers as if 7314 * by calling the number function. 7315 */ 7316void 7317xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7318 xmlXPathObjectPtr arg; 7319 double val; 7320 7321 arg = valuePop(ctxt); 7322 if (arg == NULL) 7323 XP_ERROR(XPATH_INVALID_OPERAND); 7324 val = xmlXPathCastToNumber(arg); 7325 xmlXPathReleaseObject(ctxt->context, arg); 7326 CAST_TO_NUMBER; 7327 CHECK_TYPE(XPATH_NUMBER); 7328 ctxt->value->floatval += val; 7329} 7330 7331/** 7332 * xmlXPathSubValues: 7333 * @ctxt: the XPath Parser context 7334 * 7335 * Implement the subtraction operation on XPath objects: 7336 * The numeric operators convert their operands to numbers as if 7337 * by calling the number function. 7338 */ 7339void 7340xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7341 xmlXPathObjectPtr arg; 7342 double val; 7343 7344 arg = valuePop(ctxt); 7345 if (arg == NULL) 7346 XP_ERROR(XPATH_INVALID_OPERAND); 7347 val = xmlXPathCastToNumber(arg); 7348 xmlXPathReleaseObject(ctxt->context, arg); 7349 CAST_TO_NUMBER; 7350 CHECK_TYPE(XPATH_NUMBER); 7351 ctxt->value->floatval -= val; 7352} 7353 7354/** 7355 * xmlXPathMultValues: 7356 * @ctxt: the XPath Parser context 7357 * 7358 * Implement the multiply operation on XPath objects: 7359 * The numeric operators convert their operands to numbers as if 7360 * by calling the number function. 7361 */ 7362void 7363xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7364 xmlXPathObjectPtr arg; 7365 double val; 7366 7367 arg = valuePop(ctxt); 7368 if (arg == NULL) 7369 XP_ERROR(XPATH_INVALID_OPERAND); 7370 val = xmlXPathCastToNumber(arg); 7371 xmlXPathReleaseObject(ctxt->context, arg); 7372 CAST_TO_NUMBER; 7373 CHECK_TYPE(XPATH_NUMBER); 7374 ctxt->value->floatval *= val; 7375} 7376 7377/** 7378 * xmlXPathDivValues: 7379 * @ctxt: the XPath Parser context 7380 * 7381 * Implement the div operation on XPath objects @arg1 / @arg2: 7382 * The numeric operators convert their operands to numbers as if 7383 * by calling the number function. 7384 */ 7385void 7386xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7387 xmlXPathObjectPtr arg; 7388 double val; 7389 7390 arg = valuePop(ctxt); 7391 if (arg == NULL) 7392 XP_ERROR(XPATH_INVALID_OPERAND); 7393 val = xmlXPathCastToNumber(arg); 7394 xmlXPathReleaseObject(ctxt->context, arg); 7395 CAST_TO_NUMBER; 7396 CHECK_TYPE(XPATH_NUMBER); 7397 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) 7398 ctxt->value->floatval = xmlXPathNAN; 7399 else if (val == 0 && xmlXPathGetSign(val) != 0) { 7400 if (ctxt->value->floatval == 0) 7401 ctxt->value->floatval = xmlXPathNAN; 7402 else if (ctxt->value->floatval > 0) 7403 ctxt->value->floatval = xmlXPathNINF; 7404 else if (ctxt->value->floatval < 0) 7405 ctxt->value->floatval = xmlXPathPINF; 7406 } 7407 else if (val == 0) { 7408 if (ctxt->value->floatval == 0) 7409 ctxt->value->floatval = xmlXPathNAN; 7410 else if (ctxt->value->floatval > 0) 7411 ctxt->value->floatval = xmlXPathPINF; 7412 else if (ctxt->value->floatval < 0) 7413 ctxt->value->floatval = xmlXPathNINF; 7414 } else 7415 ctxt->value->floatval /= val; 7416} 7417 7418/** 7419 * xmlXPathModValues: 7420 * @ctxt: the XPath Parser context 7421 * 7422 * Implement the mod operation on XPath objects: @arg1 / @arg2 7423 * The numeric operators convert their operands to numbers as if 7424 * by calling the number function. 7425 */ 7426void 7427xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7428 xmlXPathObjectPtr arg; 7429 double arg1, arg2; 7430 7431 arg = valuePop(ctxt); 7432 if (arg == NULL) 7433 XP_ERROR(XPATH_INVALID_OPERAND); 7434 arg2 = xmlXPathCastToNumber(arg); 7435 xmlXPathReleaseObject(ctxt->context, arg); 7436 CAST_TO_NUMBER; 7437 CHECK_TYPE(XPATH_NUMBER); 7438 arg1 = ctxt->value->floatval; 7439 if (arg2 == 0) 7440 ctxt->value->floatval = xmlXPathNAN; 7441 else { 7442 ctxt->value->floatval = fmod(arg1, arg2); 7443 } 7444} 7445 7446/************************************************************************ 7447 * * 7448 * The traversal functions * 7449 * * 7450 ************************************************************************/ 7451 7452/* 7453 * A traversal function enumerates nodes along an axis. 7454 * Initially it must be called with NULL, and it indicates 7455 * termination on the axis by returning NULL. 7456 */ 7457typedef xmlNodePtr (*xmlXPathTraversalFunction) 7458 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7459 7460/* 7461 * xmlXPathTraversalFunctionExt: 7462 * A traversal function enumerates nodes along an axis. 7463 * Initially it must be called with NULL, and it indicates 7464 * termination on the axis by returning NULL. 7465 * The context node of the traversal is specified via @contextNode. 7466 */ 7467typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7468 (xmlNodePtr cur, xmlNodePtr contextNode); 7469 7470/* 7471 * xmlXPathNodeSetMergeFunction: 7472 * Used for merging node sets in xmlXPathCollectAndTest(). 7473 */ 7474typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7475 (xmlNodeSetPtr, xmlNodeSetPtr, int); 7476 7477 7478/** 7479 * xmlXPathNextSelf: 7480 * @ctxt: the XPath Parser context 7481 * @cur: the current node in the traversal 7482 * 7483 * Traversal function for the "self" direction 7484 * The self axis contains just the context node itself 7485 * 7486 * Returns the next element following that axis 7487 */ 7488xmlNodePtr 7489xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7490 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7491 if (cur == NULL) 7492 return(ctxt->context->node); 7493 return(NULL); 7494} 7495 7496/** 7497 * xmlXPathNextChild: 7498 * @ctxt: the XPath Parser context 7499 * @cur: the current node in the traversal 7500 * 7501 * Traversal function for the "child" direction 7502 * The child axis contains the children of the context node in document order. 7503 * 7504 * Returns the next element following that axis 7505 */ 7506xmlNodePtr 7507xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7508 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7509 if (cur == NULL) { 7510 if (ctxt->context->node == NULL) return(NULL); 7511 switch (ctxt->context->node->type) { 7512 case XML_ELEMENT_NODE: 7513 case XML_TEXT_NODE: 7514 case XML_CDATA_SECTION_NODE: 7515 case XML_ENTITY_REF_NODE: 7516 case XML_ENTITY_NODE: 7517 case XML_PI_NODE: 7518 case XML_COMMENT_NODE: 7519 case XML_NOTATION_NODE: 7520 case XML_DTD_NODE: 7521 return(ctxt->context->node->children); 7522 case XML_DOCUMENT_NODE: 7523 case XML_DOCUMENT_TYPE_NODE: 7524 case XML_DOCUMENT_FRAG_NODE: 7525 case XML_HTML_DOCUMENT_NODE: 7526#ifdef LIBXML_DOCB_ENABLED 7527 case XML_DOCB_DOCUMENT_NODE: 7528#endif 7529 return(((xmlDocPtr) ctxt->context->node)->children); 7530 case XML_ELEMENT_DECL: 7531 case XML_ATTRIBUTE_DECL: 7532 case XML_ENTITY_DECL: 7533 case XML_ATTRIBUTE_NODE: 7534 case XML_NAMESPACE_DECL: 7535 case XML_XINCLUDE_START: 7536 case XML_XINCLUDE_END: 7537 return(NULL); 7538 } 7539 return(NULL); 7540 } 7541 if ((cur->type == XML_DOCUMENT_NODE) || 7542 (cur->type == XML_HTML_DOCUMENT_NODE)) 7543 return(NULL); 7544 return(cur->next); 7545} 7546 7547/** 7548 * xmlXPathNextChildElement: 7549 * @ctxt: the XPath Parser context 7550 * @cur: the current node in the traversal 7551 * 7552 * Traversal function for the "child" direction and nodes of type element. 7553 * The child axis contains the children of the context node in document order. 7554 * 7555 * Returns the next element following that axis 7556 */ 7557static xmlNodePtr 7558xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7559 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7560 if (cur == NULL) { 7561 cur = ctxt->context->node; 7562 if (cur == NULL) return(NULL); 7563 /* 7564 * Get the first element child. 7565 */ 7566 switch (cur->type) { 7567 case XML_ELEMENT_NODE: 7568 case XML_DOCUMENT_FRAG_NODE: 7569 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7570 case XML_ENTITY_NODE: 7571 cur = cur->children; 7572 if (cur != NULL) { 7573 if (cur->type == XML_ELEMENT_NODE) 7574 return(cur); 7575 do { 7576 cur = cur->next; 7577 } while ((cur != NULL) && 7578 (cur->type != XML_ELEMENT_NODE)); 7579 return(cur); 7580 } 7581 return(NULL); 7582 case XML_DOCUMENT_NODE: 7583 case XML_HTML_DOCUMENT_NODE: 7584#ifdef LIBXML_DOCB_ENABLED 7585 case XML_DOCB_DOCUMENT_NODE: 7586#endif 7587 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7588 default: 7589 return(NULL); 7590 } 7591 return(NULL); 7592 } 7593 /* 7594 * Get the next sibling element node. 7595 */ 7596 switch (cur->type) { 7597 case XML_ELEMENT_NODE: 7598 case XML_TEXT_NODE: 7599 case XML_ENTITY_REF_NODE: 7600 case XML_ENTITY_NODE: 7601 case XML_CDATA_SECTION_NODE: 7602 case XML_PI_NODE: 7603 case XML_COMMENT_NODE: 7604 case XML_XINCLUDE_END: 7605 break; 7606 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7607 default: 7608 return(NULL); 7609 } 7610 if (cur->next != NULL) { 7611 if (cur->next->type == XML_ELEMENT_NODE) 7612 return(cur->next); 7613 cur = cur->next; 7614 do { 7615 cur = cur->next; 7616 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7617 return(cur); 7618 } 7619 return(NULL); 7620} 7621 7622/** 7623 * xmlXPathNextDescendantOrSelfElemParent: 7624 * @ctxt: the XPath Parser context 7625 * @cur: the current node in the traversal 7626 * 7627 * Traversal function for the "descendant-or-self" axis. 7628 * Additionally it returns only nodes which can be parents of 7629 * element nodes. 7630 * 7631 * 7632 * Returns the next element following that axis 7633 */ 7634static xmlNodePtr 7635xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7636 xmlNodePtr contextNode) 7637{ 7638 if (cur == NULL) { 7639 if (contextNode == NULL) 7640 return(NULL); 7641 switch (contextNode->type) { 7642 case XML_ELEMENT_NODE: 7643 case XML_XINCLUDE_START: 7644 case XML_DOCUMENT_FRAG_NODE: 7645 case XML_DOCUMENT_NODE: 7646#ifdef LIBXML_DOCB_ENABLED 7647 case XML_DOCB_DOCUMENT_NODE: 7648#endif 7649 case XML_HTML_DOCUMENT_NODE: 7650 return(contextNode); 7651 default: 7652 return(NULL); 7653 } 7654 return(NULL); 7655 } else { 7656 xmlNodePtr start = cur; 7657 7658 while (cur != NULL) { 7659 switch (cur->type) { 7660 case XML_ELEMENT_NODE: 7661 /* TODO: OK to have XInclude here? */ 7662 case XML_XINCLUDE_START: 7663 case XML_DOCUMENT_FRAG_NODE: 7664 if (cur != start) 7665 return(cur); 7666 if (cur->children != NULL) { 7667 cur = cur->children; 7668 continue; 7669 } 7670 break; 7671#ifdef LIBXML_DOCB_ENABLED 7672 /* Not sure if we need those here. */ 7673 case XML_DOCUMENT_NODE: 7674 case XML_DOCB_DOCUMENT_NODE: 7675#endif 7676 case XML_HTML_DOCUMENT_NODE: 7677 if (cur != start) 7678 return(cur); 7679 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7680 default: 7681 break; 7682 } 7683 7684next_sibling: 7685 if ((cur == NULL) || (cur == contextNode)) 7686 return(NULL); 7687 if (cur->next != NULL) { 7688 cur = cur->next; 7689 } else { 7690 cur = cur->parent; 7691 goto next_sibling; 7692 } 7693 } 7694 } 7695 return(NULL); 7696} 7697 7698/** 7699 * xmlXPathNextDescendant: 7700 * @ctxt: the XPath Parser context 7701 * @cur: the current node in the traversal 7702 * 7703 * Traversal function for the "descendant" direction 7704 * the descendant axis contains the descendants of the context node in document 7705 * order; a descendant is a child or a child of a child and so on. 7706 * 7707 * Returns the next element following that axis 7708 */ 7709xmlNodePtr 7710xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7711 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7712 if (cur == NULL) { 7713 if (ctxt->context->node == NULL) 7714 return(NULL); 7715 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7716 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7717 return(NULL); 7718 7719 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7720 return(ctxt->context->doc->children); 7721 return(ctxt->context->node->children); 7722 } 7723 7724 if (cur->children != NULL) { 7725 /* 7726 * Do not descend on entities declarations 7727 */ 7728 if (cur->children->type != XML_ENTITY_DECL) { 7729 cur = cur->children; 7730 /* 7731 * Skip DTDs 7732 */ 7733 if (cur->type != XML_DTD_NODE) 7734 return(cur); 7735 } 7736 } 7737 7738 if (cur == ctxt->context->node) return(NULL); 7739 7740 while (cur->next != NULL) { 7741 cur = cur->next; 7742 if ((cur->type != XML_ENTITY_DECL) && 7743 (cur->type != XML_DTD_NODE)) 7744 return(cur); 7745 } 7746 7747 do { 7748 cur = cur->parent; 7749 if (cur == NULL) break; 7750 if (cur == ctxt->context->node) return(NULL); 7751 if (cur->next != NULL) { 7752 cur = cur->next; 7753 return(cur); 7754 } 7755 } while (cur != NULL); 7756 return(cur); 7757} 7758 7759/** 7760 * xmlXPathNextDescendantOrSelf: 7761 * @ctxt: the XPath Parser context 7762 * @cur: the current node in the traversal 7763 * 7764 * Traversal function for the "descendant-or-self" direction 7765 * the descendant-or-self axis contains the context node and the descendants 7766 * of the context node in document order; thus the context node is the first 7767 * node on the axis, and the first child of the context node is the second node 7768 * on the axis 7769 * 7770 * Returns the next element following that axis 7771 */ 7772xmlNodePtr 7773xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7774 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7775 if (cur == NULL) { 7776 if (ctxt->context->node == NULL) 7777 return(NULL); 7778 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7779 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7780 return(NULL); 7781 return(ctxt->context->node); 7782 } 7783 7784 return(xmlXPathNextDescendant(ctxt, cur)); 7785} 7786 7787/** 7788 * xmlXPathNextParent: 7789 * @ctxt: the XPath Parser context 7790 * @cur: the current node in the traversal 7791 * 7792 * Traversal function for the "parent" direction 7793 * The parent axis contains the parent of the context node, if there is one. 7794 * 7795 * Returns the next element following that axis 7796 */ 7797xmlNodePtr 7798xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7799 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7800 /* 7801 * the parent of an attribute or namespace node is the element 7802 * to which the attribute or namespace node is attached 7803 * Namespace handling !!! 7804 */ 7805 if (cur == NULL) { 7806 if (ctxt->context->node == NULL) return(NULL); 7807 switch (ctxt->context->node->type) { 7808 case XML_ELEMENT_NODE: 7809 case XML_TEXT_NODE: 7810 case XML_CDATA_SECTION_NODE: 7811 case XML_ENTITY_REF_NODE: 7812 case XML_ENTITY_NODE: 7813 case XML_PI_NODE: 7814 case XML_COMMENT_NODE: 7815 case XML_NOTATION_NODE: 7816 case XML_DTD_NODE: 7817 case XML_ELEMENT_DECL: 7818 case XML_ATTRIBUTE_DECL: 7819 case XML_XINCLUDE_START: 7820 case XML_XINCLUDE_END: 7821 case XML_ENTITY_DECL: 7822 if (ctxt->context->node->parent == NULL) 7823 return((xmlNodePtr) ctxt->context->doc); 7824 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7825 ((ctxt->context->node->parent->name[0] == ' ') || 7826 (xmlStrEqual(ctxt->context->node->parent->name, 7827 BAD_CAST "fake node libxslt")))) 7828 return(NULL); 7829 return(ctxt->context->node->parent); 7830 case XML_ATTRIBUTE_NODE: { 7831 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7832 7833 return(att->parent); 7834 } 7835 case XML_DOCUMENT_NODE: 7836 case XML_DOCUMENT_TYPE_NODE: 7837 case XML_DOCUMENT_FRAG_NODE: 7838 case XML_HTML_DOCUMENT_NODE: 7839#ifdef LIBXML_DOCB_ENABLED 7840 case XML_DOCB_DOCUMENT_NODE: 7841#endif 7842 return(NULL); 7843 case XML_NAMESPACE_DECL: { 7844 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7845 7846 if ((ns->next != NULL) && 7847 (ns->next->type != XML_NAMESPACE_DECL)) 7848 return((xmlNodePtr) ns->next); 7849 return(NULL); 7850 } 7851 } 7852 } 7853 return(NULL); 7854} 7855 7856/** 7857 * xmlXPathNextAncestor: 7858 * @ctxt: the XPath Parser context 7859 * @cur: the current node in the traversal 7860 * 7861 * Traversal function for the "ancestor" direction 7862 * the ancestor axis contains the ancestors of the context node; the ancestors 7863 * of the context node consist of the parent of context node and the parent's 7864 * parent and so on; the nodes are ordered in reverse document order; thus the 7865 * parent is the first node on the axis, and the parent's parent is the second 7866 * node on the axis 7867 * 7868 * Returns the next element following that axis 7869 */ 7870xmlNodePtr 7871xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7872 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7873 /* 7874 * the parent of an attribute or namespace node is the element 7875 * to which the attribute or namespace node is attached 7876 * !!!!!!!!!!!!! 7877 */ 7878 if (cur == NULL) { 7879 if (ctxt->context->node == NULL) return(NULL); 7880 switch (ctxt->context->node->type) { 7881 case XML_ELEMENT_NODE: 7882 case XML_TEXT_NODE: 7883 case XML_CDATA_SECTION_NODE: 7884 case XML_ENTITY_REF_NODE: 7885 case XML_ENTITY_NODE: 7886 case XML_PI_NODE: 7887 case XML_COMMENT_NODE: 7888 case XML_DTD_NODE: 7889 case XML_ELEMENT_DECL: 7890 case XML_ATTRIBUTE_DECL: 7891 case XML_ENTITY_DECL: 7892 case XML_NOTATION_NODE: 7893 case XML_XINCLUDE_START: 7894 case XML_XINCLUDE_END: 7895 if (ctxt->context->node->parent == NULL) 7896 return((xmlNodePtr) ctxt->context->doc); 7897 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7898 ((ctxt->context->node->parent->name[0] == ' ') || 7899 (xmlStrEqual(ctxt->context->node->parent->name, 7900 BAD_CAST "fake node libxslt")))) 7901 return(NULL); 7902 return(ctxt->context->node->parent); 7903 case XML_ATTRIBUTE_NODE: { 7904 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 7905 7906 return(tmp->parent); 7907 } 7908 case XML_DOCUMENT_NODE: 7909 case XML_DOCUMENT_TYPE_NODE: 7910 case XML_DOCUMENT_FRAG_NODE: 7911 case XML_HTML_DOCUMENT_NODE: 7912#ifdef LIBXML_DOCB_ENABLED 7913 case XML_DOCB_DOCUMENT_NODE: 7914#endif 7915 return(NULL); 7916 case XML_NAMESPACE_DECL: { 7917 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7918 7919 if ((ns->next != NULL) && 7920 (ns->next->type != XML_NAMESPACE_DECL)) 7921 return((xmlNodePtr) ns->next); 7922 /* Bad, how did that namespace end up here ? */ 7923 return(NULL); 7924 } 7925 } 7926 return(NULL); 7927 } 7928 if (cur == ctxt->context->doc->children) 7929 return((xmlNodePtr) ctxt->context->doc); 7930 if (cur == (xmlNodePtr) ctxt->context->doc) 7931 return(NULL); 7932 switch (cur->type) { 7933 case XML_ELEMENT_NODE: 7934 case XML_TEXT_NODE: 7935 case XML_CDATA_SECTION_NODE: 7936 case XML_ENTITY_REF_NODE: 7937 case XML_ENTITY_NODE: 7938 case XML_PI_NODE: 7939 case XML_COMMENT_NODE: 7940 case XML_NOTATION_NODE: 7941 case XML_DTD_NODE: 7942 case XML_ELEMENT_DECL: 7943 case XML_ATTRIBUTE_DECL: 7944 case XML_ENTITY_DECL: 7945 case XML_XINCLUDE_START: 7946 case XML_XINCLUDE_END: 7947 if (cur->parent == NULL) 7948 return(NULL); 7949 if ((cur->parent->type == XML_ELEMENT_NODE) && 7950 ((cur->parent->name[0] == ' ') || 7951 (xmlStrEqual(cur->parent->name, 7952 BAD_CAST "fake node libxslt")))) 7953 return(NULL); 7954 return(cur->parent); 7955 case XML_ATTRIBUTE_NODE: { 7956 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7957 7958 return(att->parent); 7959 } 7960 case XML_NAMESPACE_DECL: { 7961 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7962 7963 if ((ns->next != NULL) && 7964 (ns->next->type != XML_NAMESPACE_DECL)) 7965 return((xmlNodePtr) ns->next); 7966 /* Bad, how did that namespace end up here ? */ 7967 return(NULL); 7968 } 7969 case XML_DOCUMENT_NODE: 7970 case XML_DOCUMENT_TYPE_NODE: 7971 case XML_DOCUMENT_FRAG_NODE: 7972 case XML_HTML_DOCUMENT_NODE: 7973#ifdef LIBXML_DOCB_ENABLED 7974 case XML_DOCB_DOCUMENT_NODE: 7975#endif 7976 return(NULL); 7977 } 7978 return(NULL); 7979} 7980 7981/** 7982 * xmlXPathNextAncestorOrSelf: 7983 * @ctxt: the XPath Parser context 7984 * @cur: the current node in the traversal 7985 * 7986 * Traversal function for the "ancestor-or-self" direction 7987 * he ancestor-or-self axis contains the context node and ancestors of 7988 * the context node in reverse document order; thus the context node is 7989 * the first node on the axis, and the context node's parent the second; 7990 * parent here is defined the same as with the parent axis. 7991 * 7992 * Returns the next element following that axis 7993 */ 7994xmlNodePtr 7995xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7996 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7997 if (cur == NULL) 7998 return(ctxt->context->node); 7999 return(xmlXPathNextAncestor(ctxt, cur)); 8000} 8001 8002/** 8003 * xmlXPathNextFollowingSibling: 8004 * @ctxt: the XPath Parser context 8005 * @cur: the current node in the traversal 8006 * 8007 * Traversal function for the "following-sibling" direction 8008 * The following-sibling axis contains the following siblings of the context 8009 * node in document order. 8010 * 8011 * Returns the next element following that axis 8012 */ 8013xmlNodePtr 8014xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8015 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8016 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8017 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8018 return(NULL); 8019 if (cur == (xmlNodePtr) ctxt->context->doc) 8020 return(NULL); 8021 if (cur == NULL) 8022 return(ctxt->context->node->next); 8023 return(cur->next); 8024} 8025 8026/** 8027 * xmlXPathNextPrecedingSibling: 8028 * @ctxt: the XPath Parser context 8029 * @cur: the current node in the traversal 8030 * 8031 * Traversal function for the "preceding-sibling" direction 8032 * The preceding-sibling axis contains the preceding siblings of the context 8033 * node in reverse document order; the first preceding sibling is first on the 8034 * axis; the sibling preceding that node is the second on the axis and so on. 8035 * 8036 * Returns the next element following that axis 8037 */ 8038xmlNodePtr 8039xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8040 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8041 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8042 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8043 return(NULL); 8044 if (cur == (xmlNodePtr) ctxt->context->doc) 8045 return(NULL); 8046 if (cur == NULL) 8047 return(ctxt->context->node->prev); 8048 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8049 cur = cur->prev; 8050 if (cur == NULL) 8051 return(ctxt->context->node->prev); 8052 } 8053 return(cur->prev); 8054} 8055 8056/** 8057 * xmlXPathNextFollowing: 8058 * @ctxt: the XPath Parser context 8059 * @cur: the current node in the traversal 8060 * 8061 * Traversal function for the "following" direction 8062 * The following axis contains all nodes in the same document as the context 8063 * node that are after the context node in document order, excluding any 8064 * descendants and excluding attribute nodes and namespace nodes; the nodes 8065 * are ordered in document order 8066 * 8067 * Returns the next element following that axis 8068 */ 8069xmlNodePtr 8070xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8071 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8072 if (cur != NULL && cur->children != NULL) 8073 return cur->children ; 8074 if (cur == NULL) cur = ctxt->context->node; 8075 if (cur == NULL) return(NULL) ; /* ERROR */ 8076 if (cur->next != NULL) return(cur->next) ; 8077 do { 8078 cur = cur->parent; 8079 if (cur == NULL) break; 8080 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 8081 if (cur->next != NULL) return(cur->next); 8082 } while (cur != NULL); 8083 return(cur); 8084} 8085 8086/* 8087 * xmlXPathIsAncestor: 8088 * @ancestor: the ancestor node 8089 * @node: the current node 8090 * 8091 * Check that @ancestor is a @node's ancestor 8092 * 8093 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 8094 */ 8095static int 8096xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 8097 if ((ancestor == NULL) || (node == NULL)) return(0); 8098 /* nodes need to be in the same document */ 8099 if (ancestor->doc != node->doc) return(0); 8100 /* avoid searching if ancestor or node is the root node */ 8101 if (ancestor == (xmlNodePtr) node->doc) return(1); 8102 if (node == (xmlNodePtr) ancestor->doc) return(0); 8103 while (node->parent != NULL) { 8104 if (node->parent == ancestor) 8105 return(1); 8106 node = node->parent; 8107 } 8108 return(0); 8109} 8110 8111/** 8112 * xmlXPathNextPreceding: 8113 * @ctxt: the XPath Parser context 8114 * @cur: the current node in the traversal 8115 * 8116 * Traversal function for the "preceding" direction 8117 * the preceding axis contains all nodes in the same document as the context 8118 * node that are before the context node in document order, excluding any 8119 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8120 * ordered in reverse document order 8121 * 8122 * Returns the next element following that axis 8123 */ 8124xmlNodePtr 8125xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 8126{ 8127 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8128 if (cur == NULL) 8129 cur = ctxt->context->node; 8130 if (cur == NULL) 8131 return (NULL); 8132 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8133 cur = cur->prev; 8134 do { 8135 if (cur->prev != NULL) { 8136 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8137 return (cur); 8138 } 8139 8140 cur = cur->parent; 8141 if (cur == NULL) 8142 return (NULL); 8143 if (cur == ctxt->context->doc->children) 8144 return (NULL); 8145 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8146 return (cur); 8147} 8148 8149/** 8150 * xmlXPathNextPrecedingInternal: 8151 * @ctxt: the XPath Parser context 8152 * @cur: the current node in the traversal 8153 * 8154 * Traversal function for the "preceding" direction 8155 * the preceding axis contains all nodes in the same document as the context 8156 * node that are before the context node in document order, excluding any 8157 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8158 * ordered in reverse document order 8159 * This is a faster implementation but internal only since it requires a 8160 * state kept in the parser context: ctxt->ancestor. 8161 * 8162 * Returns the next element following that axis 8163 */ 8164static xmlNodePtr 8165xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8166 xmlNodePtr cur) 8167{ 8168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8169 if (cur == NULL) { 8170 cur = ctxt->context->node; 8171 if (cur == NULL) 8172 return (NULL); 8173 if (cur->type == XML_NAMESPACE_DECL) 8174 cur = (xmlNodePtr)((xmlNsPtr)cur)->next; 8175 ctxt->ancestor = cur->parent; 8176 } 8177 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8178 cur = cur->prev; 8179 while (cur->prev == NULL) { 8180 cur = cur->parent; 8181 if (cur == NULL) 8182 return (NULL); 8183 if (cur == ctxt->context->doc->children) 8184 return (NULL); 8185 if (cur != ctxt->ancestor) 8186 return (cur); 8187 ctxt->ancestor = cur->parent; 8188 } 8189 cur = cur->prev; 8190 while (cur->last != NULL) 8191 cur = cur->last; 8192 return (cur); 8193} 8194 8195/** 8196 * xmlXPathNextNamespace: 8197 * @ctxt: the XPath Parser context 8198 * @cur: the current attribute in the traversal 8199 * 8200 * Traversal function for the "namespace" direction 8201 * the namespace axis contains the namespace nodes of the context node; 8202 * the order of nodes on this axis is implementation-defined; the axis will 8203 * be empty unless the context node is an element 8204 * 8205 * We keep the XML namespace node at the end of the list. 8206 * 8207 * Returns the next element following that axis 8208 */ 8209xmlNodePtr 8210xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8211 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8212 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8213 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) { 8214 if (ctxt->context->tmpNsList != NULL) 8215 xmlFree(ctxt->context->tmpNsList); 8216 ctxt->context->tmpNsList = 8217 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8218 ctxt->context->tmpNsNr = 0; 8219 if (ctxt->context->tmpNsList != NULL) { 8220 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8221 ctxt->context->tmpNsNr++; 8222 } 8223 } 8224 return((xmlNodePtr) xmlXPathXMLNamespace); 8225 } 8226 if (ctxt->context->tmpNsNr > 0) { 8227 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8228 } else { 8229 if (ctxt->context->tmpNsList != NULL) 8230 xmlFree(ctxt->context->tmpNsList); 8231 ctxt->context->tmpNsList = NULL; 8232 return(NULL); 8233 } 8234} 8235 8236/** 8237 * xmlXPathNextAttribute: 8238 * @ctxt: the XPath Parser context 8239 * @cur: the current attribute in the traversal 8240 * 8241 * Traversal function for the "attribute" direction 8242 * TODO: support DTD inherited default attributes 8243 * 8244 * Returns the next element following that axis 8245 */ 8246xmlNodePtr 8247xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8248 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8249 if (ctxt->context->node == NULL) 8250 return(NULL); 8251 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8252 return(NULL); 8253 if (cur == NULL) { 8254 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8255 return(NULL); 8256 return((xmlNodePtr)ctxt->context->node->properties); 8257 } 8258 return((xmlNodePtr)cur->next); 8259} 8260 8261/************************************************************************ 8262 * * 8263 * NodeTest Functions * 8264 * * 8265 ************************************************************************/ 8266 8267#define IS_FUNCTION 200 8268 8269 8270/************************************************************************ 8271 * * 8272 * Implicit tree core function library * 8273 * * 8274 ************************************************************************/ 8275 8276/** 8277 * xmlXPathRoot: 8278 * @ctxt: the XPath Parser context 8279 * 8280 * Initialize the context to the root of the document 8281 */ 8282void 8283xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8284 if ((ctxt == NULL) || (ctxt->context == NULL)) 8285 return; 8286 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 8287 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8288 ctxt->context->node)); 8289} 8290 8291/************************************************************************ 8292 * * 8293 * The explicit core function library * 8294 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8295 * * 8296 ************************************************************************/ 8297 8298 8299/** 8300 * xmlXPathLastFunction: 8301 * @ctxt: the XPath Parser context 8302 * @nargs: the number of arguments 8303 * 8304 * Implement the last() XPath function 8305 * number last() 8306 * The last function returns the number of nodes in the context node list. 8307 */ 8308void 8309xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8310 CHECK_ARITY(0); 8311 if (ctxt->context->contextSize >= 0) { 8312 valuePush(ctxt, 8313 xmlXPathCacheNewFloat(ctxt->context, 8314 (double) ctxt->context->contextSize)); 8315#ifdef DEBUG_EXPR 8316 xmlGenericError(xmlGenericErrorContext, 8317 "last() : %d\n", ctxt->context->contextSize); 8318#endif 8319 } else { 8320 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8321 } 8322} 8323 8324/** 8325 * xmlXPathPositionFunction: 8326 * @ctxt: the XPath Parser context 8327 * @nargs: the number of arguments 8328 * 8329 * Implement the position() XPath function 8330 * number position() 8331 * The position function returns the position of the context node in the 8332 * context node list. The first position is 1, and so the last position 8333 * will be equal to last(). 8334 */ 8335void 8336xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8337 CHECK_ARITY(0); 8338 if (ctxt->context->proximityPosition >= 0) { 8339 valuePush(ctxt, 8340 xmlXPathCacheNewFloat(ctxt->context, 8341 (double) ctxt->context->proximityPosition)); 8342#ifdef DEBUG_EXPR 8343 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8344 ctxt->context->proximityPosition); 8345#endif 8346 } else { 8347 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8348 } 8349} 8350 8351/** 8352 * xmlXPathCountFunction: 8353 * @ctxt: the XPath Parser context 8354 * @nargs: the number of arguments 8355 * 8356 * Implement the count() XPath function 8357 * number count(node-set) 8358 */ 8359void 8360xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8361 xmlXPathObjectPtr cur; 8362 8363 CHECK_ARITY(1); 8364 if ((ctxt->value == NULL) || 8365 ((ctxt->value->type != XPATH_NODESET) && 8366 (ctxt->value->type != XPATH_XSLT_TREE))) 8367 XP_ERROR(XPATH_INVALID_TYPE); 8368 cur = valuePop(ctxt); 8369 8370 if ((cur == NULL) || (cur->nodesetval == NULL)) 8371 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8372 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 8373 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8374 (double) cur->nodesetval->nodeNr)); 8375 } else { 8376 if ((cur->nodesetval->nodeNr != 1) || 8377 (cur->nodesetval->nodeTab == NULL)) { 8378 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8379 } else { 8380 xmlNodePtr tmp; 8381 int i = 0; 8382 8383 tmp = cur->nodesetval->nodeTab[0]; 8384 if (tmp != NULL) { 8385 tmp = tmp->children; 8386 while (tmp != NULL) { 8387 tmp = tmp->next; 8388 i++; 8389 } 8390 } 8391 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); 8392 } 8393 } 8394 xmlXPathReleaseObject(ctxt->context, cur); 8395} 8396 8397/** 8398 * xmlXPathGetElementsByIds: 8399 * @doc: the document 8400 * @ids: a whitespace separated list of IDs 8401 * 8402 * Selects elements by their unique ID. 8403 * 8404 * Returns a node-set of selected elements. 8405 */ 8406static xmlNodeSetPtr 8407xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8408 xmlNodeSetPtr ret; 8409 const xmlChar *cur = ids; 8410 xmlChar *ID; 8411 xmlAttrPtr attr; 8412 xmlNodePtr elem = NULL; 8413 8414 if (ids == NULL) return(NULL); 8415 8416 ret = xmlXPathNodeSetCreate(NULL); 8417 8418 while (IS_BLANK_CH(*cur)) cur++; 8419 while (*cur != 0) { 8420 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8421 cur++; 8422 8423 ID = xmlStrndup(ids, cur - ids); 8424 if (ID != NULL) { 8425 /* 8426 * We used to check the fact that the value passed 8427 * was an NCName, but this generated much troubles for 8428 * me and Aleksey Sanin, people blatantly violated that 8429 * constaint, like Visa3D spec. 8430 * if (xmlValidateNCName(ID, 1) == 0) 8431 */ 8432 attr = xmlGetID(doc, ID); 8433 if (attr != NULL) { 8434 if (attr->type == XML_ATTRIBUTE_NODE) 8435 elem = attr->parent; 8436 else if (attr->type == XML_ELEMENT_NODE) 8437 elem = (xmlNodePtr) attr; 8438 else 8439 elem = NULL; 8440 if (elem != NULL) 8441 xmlXPathNodeSetAdd(ret, elem); 8442 } 8443 xmlFree(ID); 8444 } 8445 8446 while (IS_BLANK_CH(*cur)) cur++; 8447 ids = cur; 8448 } 8449 return(ret); 8450} 8451 8452/** 8453 * xmlXPathIdFunction: 8454 * @ctxt: the XPath Parser context 8455 * @nargs: the number of arguments 8456 * 8457 * Implement the id() XPath function 8458 * node-set id(object) 8459 * The id function selects elements by their unique ID 8460 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8461 * then the result is the union of the result of applying id to the 8462 * string value of each of the nodes in the argument node-set. When the 8463 * argument to id is of any other type, the argument is converted to a 8464 * string as if by a call to the string function; the string is split 8465 * into a whitespace-separated list of tokens (whitespace is any sequence 8466 * of characters matching the production S); the result is a node-set 8467 * containing the elements in the same document as the context node that 8468 * have a unique ID equal to any of the tokens in the list. 8469 */ 8470void 8471xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8472 xmlChar *tokens; 8473 xmlNodeSetPtr ret; 8474 xmlXPathObjectPtr obj; 8475 8476 CHECK_ARITY(1); 8477 obj = valuePop(ctxt); 8478 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8479 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8480 xmlNodeSetPtr ns; 8481 int i; 8482 8483 ret = xmlXPathNodeSetCreate(NULL); 8484 8485 if (obj->nodesetval != NULL) { 8486 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8487 tokens = 8488 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8489 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8490 ret = xmlXPathNodeSetMerge(ret, ns); 8491 xmlXPathFreeNodeSet(ns); 8492 if (tokens != NULL) 8493 xmlFree(tokens); 8494 } 8495 } 8496 xmlXPathReleaseObject(ctxt->context, obj); 8497 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8498 return; 8499 } 8500 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8501 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8502 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8503 xmlXPathReleaseObject(ctxt->context, obj); 8504 return; 8505} 8506 8507/** 8508 * xmlXPathLocalNameFunction: 8509 * @ctxt: the XPath Parser context 8510 * @nargs: the number of arguments 8511 * 8512 * Implement the local-name() XPath function 8513 * string local-name(node-set?) 8514 * The local-name function returns a string containing the local part 8515 * of the name of the node in the argument node-set that is first in 8516 * document order. If the node-set is empty or the first node has no 8517 * name, an empty string is returned. If the argument is omitted it 8518 * defaults to the context node. 8519 */ 8520void 8521xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8522 xmlXPathObjectPtr cur; 8523 8524 if (ctxt == NULL) return; 8525 8526 if (nargs == 0) { 8527 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8528 ctxt->context->node)); 8529 nargs = 1; 8530 } 8531 8532 CHECK_ARITY(1); 8533 if ((ctxt->value == NULL) || 8534 ((ctxt->value->type != XPATH_NODESET) && 8535 (ctxt->value->type != XPATH_XSLT_TREE))) 8536 XP_ERROR(XPATH_INVALID_TYPE); 8537 cur = valuePop(ctxt); 8538 8539 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8540 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8541 } else { 8542 int i = 0; /* Should be first in document order !!!!! */ 8543 switch (cur->nodesetval->nodeTab[i]->type) { 8544 case XML_ELEMENT_NODE: 8545 case XML_ATTRIBUTE_NODE: 8546 case XML_PI_NODE: 8547 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8548 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8549 else 8550 valuePush(ctxt, 8551 xmlXPathCacheNewString(ctxt->context, 8552 cur->nodesetval->nodeTab[i]->name)); 8553 break; 8554 case XML_NAMESPACE_DECL: 8555 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8556 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8557 break; 8558 default: 8559 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8560 } 8561 } 8562 xmlXPathReleaseObject(ctxt->context, cur); 8563} 8564 8565/** 8566 * xmlXPathNamespaceURIFunction: 8567 * @ctxt: the XPath Parser context 8568 * @nargs: the number of arguments 8569 * 8570 * Implement the namespace-uri() XPath function 8571 * string namespace-uri(node-set?) 8572 * The namespace-uri function returns a string containing the 8573 * namespace URI of the expanded name of the node in the argument 8574 * node-set that is first in document order. If the node-set is empty, 8575 * the first node has no name, or the expanded name has no namespace 8576 * URI, an empty string is returned. If the argument is omitted it 8577 * defaults to the context node. 8578 */ 8579void 8580xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8581 xmlXPathObjectPtr cur; 8582 8583 if (ctxt == NULL) return; 8584 8585 if (nargs == 0) { 8586 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8587 ctxt->context->node)); 8588 nargs = 1; 8589 } 8590 CHECK_ARITY(1); 8591 if ((ctxt->value == NULL) || 8592 ((ctxt->value->type != XPATH_NODESET) && 8593 (ctxt->value->type != XPATH_XSLT_TREE))) 8594 XP_ERROR(XPATH_INVALID_TYPE); 8595 cur = valuePop(ctxt); 8596 8597 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8598 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8599 } else { 8600 int i = 0; /* Should be first in document order !!!!! */ 8601 switch (cur->nodesetval->nodeTab[i]->type) { 8602 case XML_ELEMENT_NODE: 8603 case XML_ATTRIBUTE_NODE: 8604 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8605 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8606 else 8607 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8608 cur->nodesetval->nodeTab[i]->ns->href)); 8609 break; 8610 default: 8611 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8612 } 8613 } 8614 xmlXPathReleaseObject(ctxt->context, cur); 8615} 8616 8617/** 8618 * xmlXPathNameFunction: 8619 * @ctxt: the XPath Parser context 8620 * @nargs: the number of arguments 8621 * 8622 * Implement the name() XPath function 8623 * string name(node-set?) 8624 * The name function returns a string containing a QName representing 8625 * the name of the node in the argument node-set that is first in document 8626 * order. The QName must represent the name with respect to the namespace 8627 * declarations in effect on the node whose name is being represented. 8628 * Typically, this will be the form in which the name occurred in the XML 8629 * source. This need not be the case if there are namespace declarations 8630 * in effect on the node that associate multiple prefixes with the same 8631 * namespace. However, an implementation may include information about 8632 * the original prefix in its representation of nodes; in this case, an 8633 * implementation can ensure that the returned string is always the same 8634 * as the QName used in the XML source. If the argument it omitted it 8635 * defaults to the context node. 8636 * Libxml keep the original prefix so the "real qualified name" used is 8637 * returned. 8638 */ 8639static void 8640xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8641{ 8642 xmlXPathObjectPtr cur; 8643 8644 if (nargs == 0) { 8645 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8646 ctxt->context->node)); 8647 nargs = 1; 8648 } 8649 8650 CHECK_ARITY(1); 8651 if ((ctxt->value == NULL) || 8652 ((ctxt->value->type != XPATH_NODESET) && 8653 (ctxt->value->type != XPATH_XSLT_TREE))) 8654 XP_ERROR(XPATH_INVALID_TYPE); 8655 cur = valuePop(ctxt); 8656 8657 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8658 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8659 } else { 8660 int i = 0; /* Should be first in document order !!!!! */ 8661 8662 switch (cur->nodesetval->nodeTab[i]->type) { 8663 case XML_ELEMENT_NODE: 8664 case XML_ATTRIBUTE_NODE: 8665 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8666 valuePush(ctxt, 8667 xmlXPathCacheNewCString(ctxt->context, "")); 8668 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8669 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8670 valuePush(ctxt, 8671 xmlXPathCacheNewString(ctxt->context, 8672 cur->nodesetval->nodeTab[i]->name)); 8673 } else { 8674 xmlChar *fullname; 8675 8676 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8677 cur->nodesetval->nodeTab[i]->ns->prefix, 8678 NULL, 0); 8679 if (fullname == cur->nodesetval->nodeTab[i]->name) 8680 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8681 if (fullname == NULL) { 8682 XP_ERROR(XPATH_MEMORY_ERROR); 8683 } 8684 valuePush(ctxt, xmlXPathCacheWrapString( 8685 ctxt->context, fullname)); 8686 } 8687 break; 8688 default: 8689 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8690 cur->nodesetval->nodeTab[i])); 8691 xmlXPathLocalNameFunction(ctxt, 1); 8692 } 8693 } 8694 xmlXPathReleaseObject(ctxt->context, cur); 8695} 8696 8697 8698/** 8699 * xmlXPathStringFunction: 8700 * @ctxt: the XPath Parser context 8701 * @nargs: the number of arguments 8702 * 8703 * Implement the string() XPath function 8704 * string string(object?) 8705 * The string function converts an object to a string as follows: 8706 * - A node-set is converted to a string by returning the value of 8707 * the node in the node-set that is first in document order. 8708 * If the node-set is empty, an empty string is returned. 8709 * - A number is converted to a string as follows 8710 * + NaN is converted to the string NaN 8711 * + positive zero is converted to the string 0 8712 * + negative zero is converted to the string 0 8713 * + positive infinity is converted to the string Infinity 8714 * + negative infinity is converted to the string -Infinity 8715 * + if the number is an integer, the number is represented in 8716 * decimal form as a Number with no decimal point and no leading 8717 * zeros, preceded by a minus sign (-) if the number is negative 8718 * + otherwise, the number is represented in decimal form as a 8719 * Number including a decimal point with at least one digit 8720 * before the decimal point and at least one digit after the 8721 * decimal point, preceded by a minus sign (-) if the number 8722 * is negative; there must be no leading zeros before the decimal 8723 * point apart possibly from the one required digit immediately 8724 * before the decimal point; beyond the one required digit 8725 * after the decimal point there must be as many, but only as 8726 * many, more digits as are needed to uniquely distinguish the 8727 * number from all other IEEE 754 numeric values. 8728 * - The boolean false value is converted to the string false. 8729 * The boolean true value is converted to the string true. 8730 * 8731 * If the argument is omitted, it defaults to a node-set with the 8732 * context node as its only member. 8733 */ 8734void 8735xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8736 xmlXPathObjectPtr cur; 8737 8738 if (ctxt == NULL) return; 8739 if (nargs == 0) { 8740 valuePush(ctxt, 8741 xmlXPathCacheWrapString(ctxt->context, 8742 xmlXPathCastNodeToString(ctxt->context->node))); 8743 return; 8744 } 8745 8746 CHECK_ARITY(1); 8747 cur = valuePop(ctxt); 8748 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8749 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8750} 8751 8752/** 8753 * xmlXPathStringLengthFunction: 8754 * @ctxt: the XPath Parser context 8755 * @nargs: the number of arguments 8756 * 8757 * Implement the string-length() XPath function 8758 * number string-length(string?) 8759 * The string-length returns the number of characters in the string 8760 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8761 * the context node converted to a string, in other words the value 8762 * of the context node. 8763 */ 8764void 8765xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8766 xmlXPathObjectPtr cur; 8767 8768 if (nargs == 0) { 8769 if ((ctxt == NULL) || (ctxt->context == NULL)) 8770 return; 8771 if (ctxt->context->node == NULL) { 8772 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8773 } else { 8774 xmlChar *content; 8775 8776 content = xmlXPathCastNodeToString(ctxt->context->node); 8777 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8778 xmlUTF8Strlen(content))); 8779 xmlFree(content); 8780 } 8781 return; 8782 } 8783 CHECK_ARITY(1); 8784 CAST_TO_STRING; 8785 CHECK_TYPE(XPATH_STRING); 8786 cur = valuePop(ctxt); 8787 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8788 xmlUTF8Strlen(cur->stringval))); 8789 xmlXPathReleaseObject(ctxt->context, cur); 8790} 8791 8792/** 8793 * xmlXPathConcatFunction: 8794 * @ctxt: the XPath Parser context 8795 * @nargs: the number of arguments 8796 * 8797 * Implement the concat() XPath function 8798 * string concat(string, string, string*) 8799 * The concat function returns the concatenation of its arguments. 8800 */ 8801void 8802xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8803 xmlXPathObjectPtr cur, newobj; 8804 xmlChar *tmp; 8805 8806 if (ctxt == NULL) return; 8807 if (nargs < 2) { 8808 CHECK_ARITY(2); 8809 } 8810 8811 CAST_TO_STRING; 8812 cur = valuePop(ctxt); 8813 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 8814 xmlXPathReleaseObject(ctxt->context, cur); 8815 return; 8816 } 8817 nargs--; 8818 8819 while (nargs > 0) { 8820 CAST_TO_STRING; 8821 newobj = valuePop(ctxt); 8822 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 8823 xmlXPathReleaseObject(ctxt->context, newobj); 8824 xmlXPathReleaseObject(ctxt->context, cur); 8825 XP_ERROR(XPATH_INVALID_TYPE); 8826 } 8827 tmp = xmlStrcat(newobj->stringval, cur->stringval); 8828 newobj->stringval = cur->stringval; 8829 cur->stringval = tmp; 8830 xmlXPathReleaseObject(ctxt->context, newobj); 8831 nargs--; 8832 } 8833 valuePush(ctxt, cur); 8834} 8835 8836/** 8837 * xmlXPathContainsFunction: 8838 * @ctxt: the XPath Parser context 8839 * @nargs: the number of arguments 8840 * 8841 * Implement the contains() XPath function 8842 * boolean contains(string, string) 8843 * The contains function returns true if the first argument string 8844 * contains the second argument string, and otherwise returns false. 8845 */ 8846void 8847xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8848 xmlXPathObjectPtr hay, needle; 8849 8850 CHECK_ARITY(2); 8851 CAST_TO_STRING; 8852 CHECK_TYPE(XPATH_STRING); 8853 needle = valuePop(ctxt); 8854 CAST_TO_STRING; 8855 hay = valuePop(ctxt); 8856 8857 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 8858 xmlXPathReleaseObject(ctxt->context, hay); 8859 xmlXPathReleaseObject(ctxt->context, needle); 8860 XP_ERROR(XPATH_INVALID_TYPE); 8861 } 8862 if (xmlStrstr(hay->stringval, needle->stringval)) 8863 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 8864 else 8865 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 8866 xmlXPathReleaseObject(ctxt->context, hay); 8867 xmlXPathReleaseObject(ctxt->context, needle); 8868} 8869 8870/** 8871 * xmlXPathStartsWithFunction: 8872 * @ctxt: the XPath Parser context 8873 * @nargs: the number of arguments 8874 * 8875 * Implement the starts-with() XPath function 8876 * boolean starts-with(string, string) 8877 * The starts-with function returns true if the first argument string 8878 * starts with the second argument string, and otherwise returns false. 8879 */ 8880void 8881xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8882 xmlXPathObjectPtr hay, needle; 8883 int n; 8884 8885 CHECK_ARITY(2); 8886 CAST_TO_STRING; 8887 CHECK_TYPE(XPATH_STRING); 8888 needle = valuePop(ctxt); 8889 CAST_TO_STRING; 8890 hay = valuePop(ctxt); 8891 8892 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 8893 xmlXPathReleaseObject(ctxt->context, hay); 8894 xmlXPathReleaseObject(ctxt->context, needle); 8895 XP_ERROR(XPATH_INVALID_TYPE); 8896 } 8897 n = xmlStrlen(needle->stringval); 8898 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 8899 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 8900 else 8901 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 8902 xmlXPathReleaseObject(ctxt->context, hay); 8903 xmlXPathReleaseObject(ctxt->context, needle); 8904} 8905 8906/** 8907 * xmlXPathSubstringFunction: 8908 * @ctxt: the XPath Parser context 8909 * @nargs: the number of arguments 8910 * 8911 * Implement the substring() XPath function 8912 * string substring(string, number, number?) 8913 * The substring function returns the substring of the first argument 8914 * starting at the position specified in the second argument with 8915 * length specified in the third argument. For example, 8916 * substring("12345",2,3) returns "234". If the third argument is not 8917 * specified, it returns the substring starting at the position specified 8918 * in the second argument and continuing to the end of the string. For 8919 * example, substring("12345",2) returns "2345". More precisely, each 8920 * character in the string (see [3.6 Strings]) is considered to have a 8921 * numeric position: the position of the first character is 1, the position 8922 * of the second character is 2 and so on. The returned substring contains 8923 * those characters for which the position of the character is greater than 8924 * or equal to the second argument and, if the third argument is specified, 8925 * less than the sum of the second and third arguments; the comparisons 8926 * and addition used for the above follow the standard IEEE 754 rules. Thus: 8927 * - substring("12345", 1.5, 2.6) returns "234" 8928 * - substring("12345", 0, 3) returns "12" 8929 * - substring("12345", 0 div 0, 3) returns "" 8930 * - substring("12345", 1, 0 div 0) returns "" 8931 * - substring("12345", -42, 1 div 0) returns "12345" 8932 * - substring("12345", -1 div 0, 1 div 0) returns "" 8933 */ 8934void 8935xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8936 xmlXPathObjectPtr str, start, len; 8937 double le=0, in; 8938 int i, l, m; 8939 xmlChar *ret; 8940 8941 if (nargs < 2) { 8942 CHECK_ARITY(2); 8943 } 8944 if (nargs > 3) { 8945 CHECK_ARITY(3); 8946 } 8947 /* 8948 * take care of possible last (position) argument 8949 */ 8950 if (nargs == 3) { 8951 CAST_TO_NUMBER; 8952 CHECK_TYPE(XPATH_NUMBER); 8953 len = valuePop(ctxt); 8954 le = len->floatval; 8955 xmlXPathReleaseObject(ctxt->context, len); 8956 } 8957 8958 CAST_TO_NUMBER; 8959 CHECK_TYPE(XPATH_NUMBER); 8960 start = valuePop(ctxt); 8961 in = start->floatval; 8962 xmlXPathReleaseObject(ctxt->context, start); 8963 CAST_TO_STRING; 8964 CHECK_TYPE(XPATH_STRING); 8965 str = valuePop(ctxt); 8966 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 8967 8968 /* 8969 * If last pos not present, calculate last position 8970 */ 8971 if (nargs != 3) { 8972 le = (double)m; 8973 if (in < 1.0) 8974 in = 1.0; 8975 } 8976 8977 /* Need to check for the special cases where either 8978 * the index is NaN, the length is NaN, or both 8979 * arguments are infinity (relying on Inf + -Inf = NaN) 8980 */ 8981 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) { 8982 /* 8983 * To meet the requirements of the spec, the arguments 8984 * must be converted to integer format before 8985 * initial index calculations are done 8986 * 8987 * First we go to integer form, rounding up 8988 * and checking for special cases 8989 */ 8990 i = (int) in; 8991 if (((double)i)+0.5 <= in) i++; 8992 8993 if (xmlXPathIsInf(le) == 1) { 8994 l = m; 8995 if (i < 1) 8996 i = 1; 8997 } 8998 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 8999 l = 0; 9000 else { 9001 l = (int) le; 9002 if (((double)l)+0.5 <= le) l++; 9003 } 9004 9005 /* Now we normalize inidices */ 9006 i -= 1; 9007 l += i; 9008 if (i < 0) 9009 i = 0; 9010 if (l > m) 9011 l = m; 9012 9013 /* number of chars to copy */ 9014 l -= i; 9015 9016 ret = xmlUTF8Strsub(str->stringval, i, l); 9017 } 9018 else { 9019 ret = NULL; 9020 } 9021 if (ret == NULL) 9022 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9023 else { 9024 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9025 xmlFree(ret); 9026 } 9027 xmlXPathReleaseObject(ctxt->context, str); 9028} 9029 9030/** 9031 * xmlXPathSubstringBeforeFunction: 9032 * @ctxt: the XPath Parser context 9033 * @nargs: the number of arguments 9034 * 9035 * Implement the substring-before() XPath function 9036 * string substring-before(string, string) 9037 * The substring-before function returns the substring of the first 9038 * argument string that precedes the first occurrence of the second 9039 * argument string in the first argument string, or the empty string 9040 * if the first argument string does not contain the second argument 9041 * string. For example, substring-before("1999/04/01","/") returns 1999. 9042 */ 9043void 9044xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9045 xmlXPathObjectPtr str; 9046 xmlXPathObjectPtr find; 9047 xmlBufferPtr target; 9048 const xmlChar *point; 9049 int offset; 9050 9051 CHECK_ARITY(2); 9052 CAST_TO_STRING; 9053 find = valuePop(ctxt); 9054 CAST_TO_STRING; 9055 str = valuePop(ctxt); 9056 9057 target = xmlBufferCreate(); 9058 if (target) { 9059 point = xmlStrstr(str->stringval, find->stringval); 9060 if (point) { 9061 offset = (int)(point - str->stringval); 9062 xmlBufferAdd(target, str->stringval, offset); 9063 } 9064 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9065 xmlBufferContent(target))); 9066 xmlBufferFree(target); 9067 } 9068 xmlXPathReleaseObject(ctxt->context, str); 9069 xmlXPathReleaseObject(ctxt->context, find); 9070} 9071 9072/** 9073 * xmlXPathSubstringAfterFunction: 9074 * @ctxt: the XPath Parser context 9075 * @nargs: the number of arguments 9076 * 9077 * Implement the substring-after() XPath function 9078 * string substring-after(string, string) 9079 * The substring-after function returns the substring of the first 9080 * argument string that follows the first occurrence of the second 9081 * argument string in the first argument string, or the empty stringi 9082 * if the first argument string does not contain the second argument 9083 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9084 * and substring-after("1999/04/01","19") returns 99/04/01. 9085 */ 9086void 9087xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9088 xmlXPathObjectPtr str; 9089 xmlXPathObjectPtr find; 9090 xmlBufferPtr target; 9091 const xmlChar *point; 9092 int offset; 9093 9094 CHECK_ARITY(2); 9095 CAST_TO_STRING; 9096 find = valuePop(ctxt); 9097 CAST_TO_STRING; 9098 str = valuePop(ctxt); 9099 9100 target = xmlBufferCreate(); 9101 if (target) { 9102 point = xmlStrstr(str->stringval, find->stringval); 9103 if (point) { 9104 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9105 xmlBufferAdd(target, &str->stringval[offset], 9106 xmlStrlen(str->stringval) - offset); 9107 } 9108 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9109 xmlBufferContent(target))); 9110 xmlBufferFree(target); 9111 } 9112 xmlXPathReleaseObject(ctxt->context, str); 9113 xmlXPathReleaseObject(ctxt->context, find); 9114} 9115 9116/** 9117 * xmlXPathNormalizeFunction: 9118 * @ctxt: the XPath Parser context 9119 * @nargs: the number of arguments 9120 * 9121 * Implement the normalize-space() XPath function 9122 * string normalize-space(string?) 9123 * The normalize-space function returns the argument string with white 9124 * space normalized by stripping leading and trailing whitespace 9125 * and replacing sequences of whitespace characters by a single 9126 * space. Whitespace characters are the same allowed by the S production 9127 * in XML. If the argument is omitted, it defaults to the context 9128 * node converted to a string, in other words the value of the context node. 9129 */ 9130void 9131xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9132 xmlXPathObjectPtr obj = NULL; 9133 xmlChar *source = NULL; 9134 xmlBufferPtr target; 9135 xmlChar blank; 9136 9137 if (ctxt == NULL) return; 9138 if (nargs == 0) { 9139 /* Use current context node */ 9140 valuePush(ctxt, 9141 xmlXPathCacheWrapString(ctxt->context, 9142 xmlXPathCastNodeToString(ctxt->context->node))); 9143 nargs = 1; 9144 } 9145 9146 CHECK_ARITY(1); 9147 CAST_TO_STRING; 9148 CHECK_TYPE(XPATH_STRING); 9149 obj = valuePop(ctxt); 9150 source = obj->stringval; 9151 9152 target = xmlBufferCreate(); 9153 if (target && source) { 9154 9155 /* Skip leading whitespaces */ 9156 while (IS_BLANK_CH(*source)) 9157 source++; 9158 9159 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9160 blank = 0; 9161 while (*source) { 9162 if (IS_BLANK_CH(*source)) { 9163 blank = 0x20; 9164 } else { 9165 if (blank) { 9166 xmlBufferAdd(target, &blank, 1); 9167 blank = 0; 9168 } 9169 xmlBufferAdd(target, source, 1); 9170 } 9171 source++; 9172 } 9173 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9174 xmlBufferContent(target))); 9175 xmlBufferFree(target); 9176 } 9177 xmlXPathReleaseObject(ctxt->context, obj); 9178} 9179 9180/** 9181 * xmlXPathTranslateFunction: 9182 * @ctxt: the XPath Parser context 9183 * @nargs: the number of arguments 9184 * 9185 * Implement the translate() XPath function 9186 * string translate(string, string, string) 9187 * The translate function returns the first argument string with 9188 * occurrences of characters in the second argument string replaced 9189 * by the character at the corresponding position in the third argument 9190 * string. For example, translate("bar","abc","ABC") returns the string 9191 * BAr. If there is a character in the second argument string with no 9192 * character at a corresponding position in the third argument string 9193 * (because the second argument string is longer than the third argument 9194 * string), then occurrences of that character in the first argument 9195 * string are removed. For example, translate("--aaa--","abc-","ABC") 9196 * returns "AAA". If a character occurs more than once in second 9197 * argument string, then the first occurrence determines the replacement 9198 * character. If the third argument string is longer than the second 9199 * argument string, then excess characters are ignored. 9200 */ 9201void 9202xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9203 xmlXPathObjectPtr str; 9204 xmlXPathObjectPtr from; 9205 xmlXPathObjectPtr to; 9206 xmlBufferPtr target; 9207 int offset, max; 9208 xmlChar ch; 9209 const xmlChar *point; 9210 xmlChar *cptr; 9211 9212 CHECK_ARITY(3); 9213 9214 CAST_TO_STRING; 9215 to = valuePop(ctxt); 9216 CAST_TO_STRING; 9217 from = valuePop(ctxt); 9218 CAST_TO_STRING; 9219 str = valuePop(ctxt); 9220 9221 target = xmlBufferCreate(); 9222 if (target) { 9223 max = xmlUTF8Strlen(to->stringval); 9224 for (cptr = str->stringval; (ch=*cptr); ) { 9225 offset = xmlUTF8Strloc(from->stringval, cptr); 9226 if (offset >= 0) { 9227 if (offset < max) { 9228 point = xmlUTF8Strpos(to->stringval, offset); 9229 if (point) 9230 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1)); 9231 } 9232 } else 9233 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 9234 9235 /* Step to next character in input */ 9236 cptr++; 9237 if ( ch & 0x80 ) { 9238 /* if not simple ascii, verify proper format */ 9239 if ( (ch & 0xc0) != 0xc0 ) { 9240 xmlGenericError(xmlGenericErrorContext, 9241 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9242 break; 9243 } 9244 /* then skip over remaining bytes for this char */ 9245 while ( (ch <<= 1) & 0x80 ) 9246 if ( (*cptr++ & 0xc0) != 0x80 ) { 9247 xmlGenericError(xmlGenericErrorContext, 9248 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9249 break; 9250 } 9251 if (ch & 0x80) /* must have had error encountered */ 9252 break; 9253 } 9254 } 9255 } 9256 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9257 xmlBufferContent(target))); 9258 xmlBufferFree(target); 9259 xmlXPathReleaseObject(ctxt->context, str); 9260 xmlXPathReleaseObject(ctxt->context, from); 9261 xmlXPathReleaseObject(ctxt->context, to); 9262} 9263 9264/** 9265 * xmlXPathBooleanFunction: 9266 * @ctxt: the XPath Parser context 9267 * @nargs: the number of arguments 9268 * 9269 * Implement the boolean() XPath function 9270 * boolean boolean(object) 9271 * The boolean function converts its argument to a boolean as follows: 9272 * - a number is true if and only if it is neither positive or 9273 * negative zero nor NaN 9274 * - a node-set is true if and only if it is non-empty 9275 * - a string is true if and only if its length is non-zero 9276 */ 9277void 9278xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9279 xmlXPathObjectPtr cur; 9280 9281 CHECK_ARITY(1); 9282 cur = valuePop(ctxt); 9283 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9284 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9285 valuePush(ctxt, cur); 9286} 9287 9288/** 9289 * xmlXPathNotFunction: 9290 * @ctxt: the XPath Parser context 9291 * @nargs: the number of arguments 9292 * 9293 * Implement the not() XPath function 9294 * boolean not(boolean) 9295 * The not function returns true if its argument is false, 9296 * and false otherwise. 9297 */ 9298void 9299xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9300 CHECK_ARITY(1); 9301 CAST_TO_BOOLEAN; 9302 CHECK_TYPE(XPATH_BOOLEAN); 9303 ctxt->value->boolval = ! ctxt->value->boolval; 9304} 9305 9306/** 9307 * xmlXPathTrueFunction: 9308 * @ctxt: the XPath Parser context 9309 * @nargs: the number of arguments 9310 * 9311 * Implement the true() XPath function 9312 * boolean true() 9313 */ 9314void 9315xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9316 CHECK_ARITY(0); 9317 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9318} 9319 9320/** 9321 * xmlXPathFalseFunction: 9322 * @ctxt: the XPath Parser context 9323 * @nargs: the number of arguments 9324 * 9325 * Implement the false() XPath function 9326 * boolean false() 9327 */ 9328void 9329xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9330 CHECK_ARITY(0); 9331 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9332} 9333 9334/** 9335 * xmlXPathLangFunction: 9336 * @ctxt: the XPath Parser context 9337 * @nargs: the number of arguments 9338 * 9339 * Implement the lang() XPath function 9340 * boolean lang(string) 9341 * The lang function returns true or false depending on whether the 9342 * language of the context node as specified by xml:lang attributes 9343 * is the same as or is a sublanguage of the language specified by 9344 * the argument string. The language of the context node is determined 9345 * by the value of the xml:lang attribute on the context node, or, if 9346 * the context node has no xml:lang attribute, by the value of the 9347 * xml:lang attribute on the nearest ancestor of the context node that 9348 * has an xml:lang attribute. If there is no such attribute, then lang 9349 * returns false. If there is such an attribute, then lang returns 9350 * true if the attribute value is equal to the argument ignoring case, 9351 * or if there is some suffix starting with - such that the attribute 9352 * value is equal to the argument ignoring that suffix of the attribute 9353 * value and ignoring case. 9354 */ 9355void 9356xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9357 xmlXPathObjectPtr val = NULL; 9358 const xmlChar *theLang = NULL; 9359 const xmlChar *lang; 9360 int ret = 0; 9361 int i; 9362 9363 CHECK_ARITY(1); 9364 CAST_TO_STRING; 9365 CHECK_TYPE(XPATH_STRING); 9366 val = valuePop(ctxt); 9367 lang = val->stringval; 9368 theLang = xmlNodeGetLang(ctxt->context->node); 9369 if ((theLang != NULL) && (lang != NULL)) { 9370 for (i = 0;lang[i] != 0;i++) 9371 if (toupper(lang[i]) != toupper(theLang[i])) 9372 goto not_equal; 9373 if ((theLang[i] == 0) || (theLang[i] == '-')) 9374 ret = 1; 9375 } 9376not_equal: 9377 if (theLang != NULL) 9378 xmlFree((void *)theLang); 9379 9380 xmlXPathReleaseObject(ctxt->context, val); 9381 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9382} 9383 9384/** 9385 * xmlXPathNumberFunction: 9386 * @ctxt: the XPath Parser context 9387 * @nargs: the number of arguments 9388 * 9389 * Implement the number() XPath function 9390 * number number(object?) 9391 */ 9392void 9393xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9394 xmlXPathObjectPtr cur; 9395 double res; 9396 9397 if (ctxt == NULL) return; 9398 if (nargs == 0) { 9399 if (ctxt->context->node == NULL) { 9400 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9401 } else { 9402 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9403 9404 res = xmlXPathStringEvalNumber(content); 9405 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9406 xmlFree(content); 9407 } 9408 return; 9409 } 9410 9411 CHECK_ARITY(1); 9412 cur = valuePop(ctxt); 9413 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9414} 9415 9416/** 9417 * xmlXPathSumFunction: 9418 * @ctxt: the XPath Parser context 9419 * @nargs: the number of arguments 9420 * 9421 * Implement the sum() XPath function 9422 * number sum(node-set) 9423 * The sum function returns the sum of the values of the nodes in 9424 * the argument node-set. 9425 */ 9426void 9427xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9428 xmlXPathObjectPtr cur; 9429 int i; 9430 double res = 0.0; 9431 9432 CHECK_ARITY(1); 9433 if ((ctxt->value == NULL) || 9434 ((ctxt->value->type != XPATH_NODESET) && 9435 (ctxt->value->type != XPATH_XSLT_TREE))) 9436 XP_ERROR(XPATH_INVALID_TYPE); 9437 cur = valuePop(ctxt); 9438 9439 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9440 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9441 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9442 } 9443 } 9444 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9445 xmlXPathReleaseObject(ctxt->context, cur); 9446} 9447 9448/* 9449 * To assure working code on multiple platforms, we want to only depend 9450 * upon the characteristic truncation of converting a floating point value 9451 * to an integer. Unfortunately, because of the different storage sizes 9452 * of our internal floating point value (double) and integer (int), we 9453 * can't directly convert (see bug 301162). This macro is a messy 9454 * 'workaround' 9455 */ 9456#define XTRUNC(f, v) \ 9457 f = fmod((v), INT_MAX); \ 9458 f = (v) - (f) + (double)((int)(f)); 9459 9460/** 9461 * xmlXPathFloorFunction: 9462 * @ctxt: the XPath Parser context 9463 * @nargs: the number of arguments 9464 * 9465 * Implement the floor() XPath function 9466 * number floor(number) 9467 * The floor function returns the largest (closest to positive infinity) 9468 * number that is not greater than the argument and that is an integer. 9469 */ 9470void 9471xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9472 double f; 9473 9474 CHECK_ARITY(1); 9475 CAST_TO_NUMBER; 9476 CHECK_TYPE(XPATH_NUMBER); 9477 9478 XTRUNC(f, ctxt->value->floatval); 9479 if (f != ctxt->value->floatval) { 9480 if (ctxt->value->floatval > 0) 9481 ctxt->value->floatval = f; 9482 else 9483 ctxt->value->floatval = f - 1; 9484 } 9485} 9486 9487/** 9488 * xmlXPathCeilingFunction: 9489 * @ctxt: the XPath Parser context 9490 * @nargs: the number of arguments 9491 * 9492 * Implement the ceiling() XPath function 9493 * number ceiling(number) 9494 * The ceiling function returns the smallest (closest to negative infinity) 9495 * number that is not less than the argument and that is an integer. 9496 */ 9497void 9498xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9499 double f; 9500 9501 CHECK_ARITY(1); 9502 CAST_TO_NUMBER; 9503 CHECK_TYPE(XPATH_NUMBER); 9504 9505#if 0 9506 ctxt->value->floatval = ceil(ctxt->value->floatval); 9507#else 9508 XTRUNC(f, ctxt->value->floatval); 9509 if (f != ctxt->value->floatval) { 9510 if (ctxt->value->floatval > 0) 9511 ctxt->value->floatval = f + 1; 9512 else { 9513 if (ctxt->value->floatval < 0 && f == 0) 9514 ctxt->value->floatval = xmlXPathNZERO; 9515 else 9516 ctxt->value->floatval = f; 9517 } 9518 9519 } 9520#endif 9521} 9522 9523/** 9524 * xmlXPathRoundFunction: 9525 * @ctxt: the XPath Parser context 9526 * @nargs: the number of arguments 9527 * 9528 * Implement the round() XPath function 9529 * number round(number) 9530 * The round function returns the number that is closest to the 9531 * argument and that is an integer. If there are two such numbers, 9532 * then the one that is even is returned. 9533 */ 9534void 9535xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9536 double f; 9537 9538 CHECK_ARITY(1); 9539 CAST_TO_NUMBER; 9540 CHECK_TYPE(XPATH_NUMBER); 9541 9542 if ((xmlXPathIsNaN(ctxt->value->floatval)) || 9543 (xmlXPathIsInf(ctxt->value->floatval) == 1) || 9544 (xmlXPathIsInf(ctxt->value->floatval) == -1) || 9545 (ctxt->value->floatval == 0.0)) 9546 return; 9547 9548 XTRUNC(f, ctxt->value->floatval); 9549 if (ctxt->value->floatval < 0) { 9550 if (ctxt->value->floatval < f - 0.5) 9551 ctxt->value->floatval = f - 1; 9552 else 9553 ctxt->value->floatval = f; 9554 if (ctxt->value->floatval == 0) 9555 ctxt->value->floatval = xmlXPathNZERO; 9556 } else { 9557 if (ctxt->value->floatval < f + 0.5) 9558 ctxt->value->floatval = f; 9559 else 9560 ctxt->value->floatval = f + 1; 9561 } 9562} 9563 9564/************************************************************************ 9565 * * 9566 * The Parser * 9567 * * 9568 ************************************************************************/ 9569 9570/* 9571 * a few forward declarations since we use a recursive call based 9572 * implementation. 9573 */ 9574static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9575static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9576static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9577static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9578static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9579 int qualified); 9580 9581/** 9582 * xmlXPathCurrentChar: 9583 * @ctxt: the XPath parser context 9584 * @cur: pointer to the beginning of the char 9585 * @len: pointer to the length of the char read 9586 * 9587 * The current char value, if using UTF-8 this may actually span multiple 9588 * bytes in the input buffer. 9589 * 9590 * Returns the current char value and its length 9591 */ 9592 9593static int 9594xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9595 unsigned char c; 9596 unsigned int val; 9597 const xmlChar *cur; 9598 9599 if (ctxt == NULL) 9600 return(0); 9601 cur = ctxt->cur; 9602 9603 /* 9604 * We are supposed to handle UTF8, check it's valid 9605 * From rfc2044: encoding of the Unicode values on UTF-8: 9606 * 9607 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9608 * 0000 0000-0000 007F 0xxxxxxx 9609 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9610 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9611 * 9612 * Check for the 0x110000 limit too 9613 */ 9614 c = *cur; 9615 if (c & 0x80) { 9616 if ((cur[1] & 0xc0) != 0x80) 9617 goto encoding_error; 9618 if ((c & 0xe0) == 0xe0) { 9619 9620 if ((cur[2] & 0xc0) != 0x80) 9621 goto encoding_error; 9622 if ((c & 0xf0) == 0xf0) { 9623 if (((c & 0xf8) != 0xf0) || 9624 ((cur[3] & 0xc0) != 0x80)) 9625 goto encoding_error; 9626 /* 4-byte code */ 9627 *len = 4; 9628 val = (cur[0] & 0x7) << 18; 9629 val |= (cur[1] & 0x3f) << 12; 9630 val |= (cur[2] & 0x3f) << 6; 9631 val |= cur[3] & 0x3f; 9632 } else { 9633 /* 3-byte code */ 9634 *len = 3; 9635 val = (cur[0] & 0xf) << 12; 9636 val |= (cur[1] & 0x3f) << 6; 9637 val |= cur[2] & 0x3f; 9638 } 9639 } else { 9640 /* 2-byte code */ 9641 *len = 2; 9642 val = (cur[0] & 0x1f) << 6; 9643 val |= cur[1] & 0x3f; 9644 } 9645 if (!IS_CHAR(val)) { 9646 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9647 } 9648 return(val); 9649 } else { 9650 /* 1-byte code */ 9651 *len = 1; 9652 return((int) *cur); 9653 } 9654encoding_error: 9655 /* 9656 * If we detect an UTF8 error that probably means that the 9657 * input encoding didn't get properly advertised in the 9658 * declaration header. Report the error and switch the encoding 9659 * to ISO-Latin-1 (if you don't like this policy, just declare the 9660 * encoding !) 9661 */ 9662 *len = 0; 9663 XP_ERROR0(XPATH_ENCODING_ERROR); 9664} 9665 9666/** 9667 * xmlXPathParseNCName: 9668 * @ctxt: the XPath Parser context 9669 * 9670 * parse an XML namespace non qualified name. 9671 * 9672 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9673 * 9674 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9675 * CombiningChar | Extender 9676 * 9677 * Returns the namespace name or NULL 9678 */ 9679 9680xmlChar * 9681xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9682 const xmlChar *in; 9683 xmlChar *ret; 9684 int count = 0; 9685 9686 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9687 /* 9688 * Accelerator for simple ASCII names 9689 */ 9690 in = ctxt->cur; 9691 if (((*in >= 0x61) && (*in <= 0x7A)) || 9692 ((*in >= 0x41) && (*in <= 0x5A)) || 9693 (*in == '_')) { 9694 in++; 9695 while (((*in >= 0x61) && (*in <= 0x7A)) || 9696 ((*in >= 0x41) && (*in <= 0x5A)) || 9697 ((*in >= 0x30) && (*in <= 0x39)) || 9698 (*in == '_') || (*in == '.') || 9699 (*in == '-')) 9700 in++; 9701 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9702 (*in == '[') || (*in == ']') || (*in == ':') || 9703 (*in == '@') || (*in == '*')) { 9704 count = in - ctxt->cur; 9705 if (count == 0) 9706 return(NULL); 9707 ret = xmlStrndup(ctxt->cur, count); 9708 ctxt->cur = in; 9709 return(ret); 9710 } 9711 } 9712 return(xmlXPathParseNameComplex(ctxt, 0)); 9713} 9714 9715 9716/** 9717 * xmlXPathParseQName: 9718 * @ctxt: the XPath Parser context 9719 * @prefix: a xmlChar ** 9720 * 9721 * parse an XML qualified name 9722 * 9723 * [NS 5] QName ::= (Prefix ':')? LocalPart 9724 * 9725 * [NS 6] Prefix ::= NCName 9726 * 9727 * [NS 7] LocalPart ::= NCName 9728 * 9729 * Returns the function returns the local part, and prefix is updated 9730 * to get the Prefix if any. 9731 */ 9732 9733static xmlChar * 9734xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9735 xmlChar *ret = NULL; 9736 9737 *prefix = NULL; 9738 ret = xmlXPathParseNCName(ctxt); 9739 if (CUR == ':') { 9740 *prefix = ret; 9741 NEXT; 9742 ret = xmlXPathParseNCName(ctxt); 9743 } 9744 return(ret); 9745} 9746 9747/** 9748 * xmlXPathParseName: 9749 * @ctxt: the XPath Parser context 9750 * 9751 * parse an XML name 9752 * 9753 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9754 * CombiningChar | Extender 9755 * 9756 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9757 * 9758 * Returns the namespace name or NULL 9759 */ 9760 9761xmlChar * 9762xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9763 const xmlChar *in; 9764 xmlChar *ret; 9765 int count = 0; 9766 9767 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9768 /* 9769 * Accelerator for simple ASCII names 9770 */ 9771 in = ctxt->cur; 9772 if (((*in >= 0x61) && (*in <= 0x7A)) || 9773 ((*in >= 0x41) && (*in <= 0x5A)) || 9774 (*in == '_') || (*in == ':')) { 9775 in++; 9776 while (((*in >= 0x61) && (*in <= 0x7A)) || 9777 ((*in >= 0x41) && (*in <= 0x5A)) || 9778 ((*in >= 0x30) && (*in <= 0x39)) || 9779 (*in == '_') || (*in == '-') || 9780 (*in == ':') || (*in == '.')) 9781 in++; 9782 if ((*in > 0) && (*in < 0x80)) { 9783 count = in - ctxt->cur; 9784 ret = xmlStrndup(ctxt->cur, count); 9785 ctxt->cur = in; 9786 return(ret); 9787 } 9788 } 9789 return(xmlXPathParseNameComplex(ctxt, 1)); 9790} 9791 9792static xmlChar * 9793xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9794 xmlChar buf[XML_MAX_NAMELEN + 5]; 9795 int len = 0, l; 9796 int c; 9797 9798 /* 9799 * Handler for more complex cases 9800 */ 9801 c = CUR_CHAR(l); 9802 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 9803 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 9804 (c == '*') || /* accelerators */ 9805 (!IS_LETTER(c) && (c != '_') && 9806 ((qualified) && (c != ':')))) { 9807 return(NULL); 9808 } 9809 9810 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 9811 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 9812 (c == '.') || (c == '-') || 9813 (c == '_') || ((qualified) && (c == ':')) || 9814 (IS_COMBINING(c)) || 9815 (IS_EXTENDER(c)))) { 9816 COPY_BUF(l,buf,len,c); 9817 NEXTL(l); 9818 c = CUR_CHAR(l); 9819 if (len >= XML_MAX_NAMELEN) { 9820 /* 9821 * Okay someone managed to make a huge name, so he's ready to pay 9822 * for the processing speed. 9823 */ 9824 xmlChar *buffer; 9825 int max = len * 2; 9826 9827 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 9828 if (buffer == NULL) { 9829 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9830 } 9831 memcpy(buffer, buf, len); 9832 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 9833 (c == '.') || (c == '-') || 9834 (c == '_') || ((qualified) && (c == ':')) || 9835 (IS_COMBINING(c)) || 9836 (IS_EXTENDER(c))) { 9837 if (len + 10 > max) { 9838 max *= 2; 9839 buffer = (xmlChar *) xmlRealloc(buffer, 9840 max * sizeof(xmlChar)); 9841 if (buffer == NULL) { 9842 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9843 } 9844 } 9845 COPY_BUF(l,buffer,len,c); 9846 NEXTL(l); 9847 c = CUR_CHAR(l); 9848 } 9849 buffer[len] = 0; 9850 return(buffer); 9851 } 9852 } 9853 if (len == 0) 9854 return(NULL); 9855 return(xmlStrndup(buf, len)); 9856} 9857 9858#define MAX_FRAC 20 9859 9860/* 9861 * These are used as divisors for the fractional part of a number. 9862 * Since the table includes 1.0 (representing '0' fractional digits), 9863 * it must be dimensioned at MAX_FRAC+1 (bug 133921) 9864 */ 9865static double my_pow10[MAX_FRAC+1] = { 9866 1.0, 10.0, 100.0, 1000.0, 10000.0, 9867 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 9868 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 9869 100000000000000.0, 9870 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 9871 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0 9872}; 9873 9874/** 9875 * xmlXPathStringEvalNumber: 9876 * @str: A string to scan 9877 * 9878 * [30a] Float ::= Number ('e' Digits?)? 9879 * 9880 * [30] Number ::= Digits ('.' Digits?)? 9881 * | '.' Digits 9882 * [31] Digits ::= [0-9]+ 9883 * 9884 * Compile a Number in the string 9885 * In complement of the Number expression, this function also handles 9886 * negative values : '-' Number. 9887 * 9888 * Returns the double value. 9889 */ 9890double 9891xmlXPathStringEvalNumber(const xmlChar *str) { 9892 const xmlChar *cur = str; 9893 double ret; 9894 int ok = 0; 9895 int isneg = 0; 9896 int exponent = 0; 9897 int is_exponent_negative = 0; 9898#ifdef __GNUC__ 9899 unsigned long tmp = 0; 9900 double temp; 9901#endif 9902 if (cur == NULL) return(0); 9903 while (IS_BLANK_CH(*cur)) cur++; 9904 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 9905 return(xmlXPathNAN); 9906 } 9907 if (*cur == '-') { 9908 isneg = 1; 9909 cur++; 9910 } 9911 9912#ifdef __GNUC__ 9913 /* 9914 * tmp/temp is a workaround against a gcc compiler bug 9915 * http://veillard.com/gcc.bug 9916 */ 9917 ret = 0; 9918 while ((*cur >= '0') && (*cur <= '9')) { 9919 ret = ret * 10; 9920 tmp = (*cur - '0'); 9921 ok = 1; 9922 cur++; 9923 temp = (double) tmp; 9924 ret = ret + temp; 9925 } 9926#else 9927 ret = 0; 9928 while ((*cur >= '0') && (*cur <= '9')) { 9929 ret = ret * 10 + (*cur - '0'); 9930 ok = 1; 9931 cur++; 9932 } 9933#endif 9934 9935 if (*cur == '.') { 9936 int v, frac = 0; 9937 double fraction = 0; 9938 9939 cur++; 9940 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 9941 return(xmlXPathNAN); 9942 } 9943 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { 9944 v = (*cur - '0'); 9945 fraction = fraction * 10 + v; 9946 frac = frac + 1; 9947 cur++; 9948 } 9949 fraction /= my_pow10[frac]; 9950 ret = ret + fraction; 9951 while ((*cur >= '0') && (*cur <= '9')) 9952 cur++; 9953 } 9954 if ((*cur == 'e') || (*cur == 'E')) { 9955 cur++; 9956 if (*cur == '-') { 9957 is_exponent_negative = 1; 9958 cur++; 9959 } else if (*cur == '+') { 9960 cur++; 9961 } 9962 while ((*cur >= '0') && (*cur <= '9')) { 9963 exponent = exponent * 10 + (*cur - '0'); 9964 cur++; 9965 } 9966 } 9967 while (IS_BLANK_CH(*cur)) cur++; 9968 if (*cur != 0) return(xmlXPathNAN); 9969 if (isneg) ret = -ret; 9970 if (is_exponent_negative) exponent = -exponent; 9971 ret *= pow(10.0, (double)exponent); 9972 return(ret); 9973} 9974 9975/** 9976 * xmlXPathCompNumber: 9977 * @ctxt: the XPath Parser context 9978 * 9979 * [30] Number ::= Digits ('.' Digits?)? 9980 * | '.' Digits 9981 * [31] Digits ::= [0-9]+ 9982 * 9983 * Compile a Number, then push it on the stack 9984 * 9985 */ 9986static void 9987xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 9988{ 9989 double ret = 0.0; 9990 double mult = 1; 9991 int ok = 0; 9992 int exponent = 0; 9993 int is_exponent_negative = 0; 9994#ifdef __GNUC__ 9995 unsigned long tmp = 0; 9996 double temp; 9997#endif 9998 9999 CHECK_ERROR; 10000 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10001 XP_ERROR(XPATH_NUMBER_ERROR); 10002 } 10003#ifdef __GNUC__ 10004 /* 10005 * tmp/temp is a workaround against a gcc compiler bug 10006 * http://veillard.com/gcc.bug 10007 */ 10008 ret = 0; 10009 while ((CUR >= '0') && (CUR <= '9')) { 10010 ret = ret * 10; 10011 tmp = (CUR - '0'); 10012 ok = 1; 10013 NEXT; 10014 temp = (double) tmp; 10015 ret = ret + temp; 10016 } 10017#else 10018 ret = 0; 10019 while ((CUR >= '0') && (CUR <= '9')) { 10020 ret = ret * 10 + (CUR - '0'); 10021 ok = 1; 10022 NEXT; 10023 } 10024#endif 10025 if (CUR == '.') { 10026 NEXT; 10027 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10028 XP_ERROR(XPATH_NUMBER_ERROR); 10029 } 10030 while ((CUR >= '0') && (CUR <= '9')) { 10031 mult /= 10; 10032 ret = ret + (CUR - '0') * mult; 10033 NEXT; 10034 } 10035 } 10036 if ((CUR == 'e') || (CUR == 'E')) { 10037 NEXT; 10038 if (CUR == '-') { 10039 is_exponent_negative = 1; 10040 NEXT; 10041 } else if (CUR == '+') { 10042 NEXT; 10043 } 10044 while ((CUR >= '0') && (CUR <= '9')) { 10045 exponent = exponent * 10 + (CUR - '0'); 10046 NEXT; 10047 } 10048 if (is_exponent_negative) 10049 exponent = -exponent; 10050 ret *= pow(10.0, (double) exponent); 10051 } 10052 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 10053 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 10054} 10055 10056/** 10057 * xmlXPathParseLiteral: 10058 * @ctxt: the XPath Parser context 10059 * 10060 * Parse a Literal 10061 * 10062 * [29] Literal ::= '"' [^"]* '"' 10063 * | "'" [^']* "'" 10064 * 10065 * Returns the value found or NULL in case of error 10066 */ 10067static xmlChar * 10068xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10069 const xmlChar *q; 10070 xmlChar *ret = NULL; 10071 10072 if (CUR == '"') { 10073 NEXT; 10074 q = CUR_PTR; 10075 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10076 NEXT; 10077 if (!IS_CHAR_CH(CUR)) { 10078 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10079 } else { 10080 ret = xmlStrndup(q, CUR_PTR - q); 10081 NEXT; 10082 } 10083 } else if (CUR == '\'') { 10084 NEXT; 10085 q = CUR_PTR; 10086 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10087 NEXT; 10088 if (!IS_CHAR_CH(CUR)) { 10089 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10090 } else { 10091 ret = xmlStrndup(q, CUR_PTR - q); 10092 NEXT; 10093 } 10094 } else { 10095 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10096 } 10097 return(ret); 10098} 10099 10100/** 10101 * xmlXPathCompLiteral: 10102 * @ctxt: the XPath Parser context 10103 * 10104 * Parse a Literal and push it on the stack. 10105 * 10106 * [29] Literal ::= '"' [^"]* '"' 10107 * | "'" [^']* "'" 10108 * 10109 * TODO: xmlXPathCompLiteral memory allocation could be improved. 10110 */ 10111static void 10112xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10113 const xmlChar *q; 10114 xmlChar *ret = NULL; 10115 10116 if (CUR == '"') { 10117 NEXT; 10118 q = CUR_PTR; 10119 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10120 NEXT; 10121 if (!IS_CHAR_CH(CUR)) { 10122 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10123 } else { 10124 ret = xmlStrndup(q, CUR_PTR - q); 10125 NEXT; 10126 } 10127 } else if (CUR == '\'') { 10128 NEXT; 10129 q = CUR_PTR; 10130 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10131 NEXT; 10132 if (!IS_CHAR_CH(CUR)) { 10133 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10134 } else { 10135 ret = xmlStrndup(q, CUR_PTR - q); 10136 NEXT; 10137 } 10138 } else { 10139 XP_ERROR(XPATH_START_LITERAL_ERROR); 10140 } 10141 if (ret == NULL) return; 10142 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 10143 xmlXPathCacheNewString(ctxt->context, ret), NULL); 10144 xmlFree(ret); 10145} 10146 10147/** 10148 * xmlXPathCompVariableReference: 10149 * @ctxt: the XPath Parser context 10150 * 10151 * Parse a VariableReference, evaluate it and push it on the stack. 10152 * 10153 * The variable bindings consist of a mapping from variable names 10154 * to variable values. The value of a variable is an object, which can be 10155 * of any of the types that are possible for the value of an expression, 10156 * and may also be of additional types not specified here. 10157 * 10158 * Early evaluation is possible since: 10159 * The variable bindings [...] used to evaluate a subexpression are 10160 * always the same as those used to evaluate the containing expression. 10161 * 10162 * [36] VariableReference ::= '$' QName 10163 */ 10164static void 10165xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10166 xmlChar *name; 10167 xmlChar *prefix; 10168 10169 SKIP_BLANKS; 10170 if (CUR != '$') { 10171 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10172 } 10173 NEXT; 10174 name = xmlXPathParseQName(ctxt, &prefix); 10175 if (name == NULL) { 10176 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10177 } 10178 ctxt->comp->last = -1; 10179 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 10180 name, prefix); 10181 SKIP_BLANKS; 10182 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10183 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR); 10184 } 10185} 10186 10187/** 10188 * xmlXPathIsNodeType: 10189 * @name: a name string 10190 * 10191 * Is the name given a NodeType one. 10192 * 10193 * [38] NodeType ::= 'comment' 10194 * | 'text' 10195 * | 'processing-instruction' 10196 * | 'node' 10197 * 10198 * Returns 1 if true 0 otherwise 10199 */ 10200int 10201xmlXPathIsNodeType(const xmlChar *name) { 10202 if (name == NULL) 10203 return(0); 10204 10205 if (xmlStrEqual(name, BAD_CAST "node")) 10206 return(1); 10207 if (xmlStrEqual(name, BAD_CAST "text")) 10208 return(1); 10209 if (xmlStrEqual(name, BAD_CAST "comment")) 10210 return(1); 10211 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10212 return(1); 10213 return(0); 10214} 10215 10216/** 10217 * xmlXPathCompFunctionCall: 10218 * @ctxt: the XPath Parser context 10219 * 10220 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 10221 * [17] Argument ::= Expr 10222 * 10223 * Compile a function call, the evaluation of all arguments are 10224 * pushed on the stack 10225 */ 10226static void 10227xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10228 xmlChar *name; 10229 xmlChar *prefix; 10230 int nbargs = 0; 10231 int sort = 1; 10232 10233 name = xmlXPathParseQName(ctxt, &prefix); 10234 if (name == NULL) { 10235 XP_ERROR(XPATH_EXPR_ERROR); 10236 } 10237 SKIP_BLANKS; 10238#ifdef DEBUG_EXPR 10239 if (prefix == NULL) 10240 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10241 name); 10242 else 10243 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10244 prefix, name); 10245#endif 10246 10247 if (CUR != '(') { 10248 XP_ERROR(XPATH_EXPR_ERROR); 10249 } 10250 NEXT; 10251 SKIP_BLANKS; 10252 10253 /* 10254 * Optimization for count(): we don't need the node-set to be sorted. 10255 */ 10256 if ((prefix == NULL) && (name[0] == 'c') && 10257 xmlStrEqual(name, BAD_CAST "count")) 10258 { 10259 sort = 0; 10260 } 10261 ctxt->comp->last = -1; 10262 if (CUR != ')') { 10263 while (CUR != 0) { 10264 int op1 = ctxt->comp->last; 10265 ctxt->comp->last = -1; 10266 xmlXPathCompileExpr(ctxt, sort); 10267 CHECK_ERROR; 10268 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10269 nbargs++; 10270 if (CUR == ')') break; 10271 if (CUR != ',') { 10272 XP_ERROR(XPATH_EXPR_ERROR); 10273 } 10274 NEXT; 10275 SKIP_BLANKS; 10276 } 10277 } 10278 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10279 name, prefix); 10280 NEXT; 10281 SKIP_BLANKS; 10282} 10283 10284/** 10285 * xmlXPathCompPrimaryExpr: 10286 * @ctxt: the XPath Parser context 10287 * 10288 * [15] PrimaryExpr ::= VariableReference 10289 * | '(' Expr ')' 10290 * | Literal 10291 * | Number 10292 * | FunctionCall 10293 * 10294 * Compile a primary expression. 10295 */ 10296static void 10297xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10298 SKIP_BLANKS; 10299 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10300 else if (CUR == '(') { 10301 NEXT; 10302 SKIP_BLANKS; 10303 xmlXPathCompileExpr(ctxt, 1); 10304 CHECK_ERROR; 10305 if (CUR != ')') { 10306 XP_ERROR(XPATH_EXPR_ERROR); 10307 } 10308 NEXT; 10309 SKIP_BLANKS; 10310 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10311 xmlXPathCompNumber(ctxt); 10312 } else if ((CUR == '\'') || (CUR == '"')) { 10313 xmlXPathCompLiteral(ctxt); 10314 } else { 10315 xmlXPathCompFunctionCall(ctxt); 10316 } 10317 SKIP_BLANKS; 10318} 10319 10320/** 10321 * xmlXPathCompFilterExpr: 10322 * @ctxt: the XPath Parser context 10323 * 10324 * [20] FilterExpr ::= PrimaryExpr 10325 * | FilterExpr Predicate 10326 * 10327 * Compile a filter expression. 10328 * Square brackets are used to filter expressions in the same way that 10329 * they are used in location paths. It is an error if the expression to 10330 * be filtered does not evaluate to a node-set. The context node list 10331 * used for evaluating the expression in square brackets is the node-set 10332 * to be filtered listed in document order. 10333 */ 10334 10335static void 10336xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10337 xmlXPathCompPrimaryExpr(ctxt); 10338 CHECK_ERROR; 10339 SKIP_BLANKS; 10340 10341 while (CUR == '[') { 10342 xmlXPathCompPredicate(ctxt, 1); 10343 SKIP_BLANKS; 10344 } 10345 10346 10347} 10348 10349/** 10350 * xmlXPathScanName: 10351 * @ctxt: the XPath Parser context 10352 * 10353 * Trickery: parse an XML name but without consuming the input flow 10354 * Needed to avoid insanity in the parser state. 10355 * 10356 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10357 * CombiningChar | Extender 10358 * 10359 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10360 * 10361 * [6] Names ::= Name (S Name)* 10362 * 10363 * Returns the Name parsed or NULL 10364 */ 10365 10366static xmlChar * 10367xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10368 int len = 0, l; 10369 int c; 10370 const xmlChar *cur; 10371 xmlChar *ret; 10372 10373 cur = ctxt->cur; 10374 10375 c = CUR_CHAR(l); 10376 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10377 (!IS_LETTER(c) && (c != '_') && 10378 (c != ':'))) { 10379 return(NULL); 10380 } 10381 10382 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10383 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10384 (c == '.') || (c == '-') || 10385 (c == '_') || (c == ':') || 10386 (IS_COMBINING(c)) || 10387 (IS_EXTENDER(c)))) { 10388 len += l; 10389 NEXTL(l); 10390 c = CUR_CHAR(l); 10391 } 10392 ret = xmlStrndup(cur, ctxt->cur - cur); 10393 ctxt->cur = cur; 10394 return(ret); 10395} 10396 10397/** 10398 * xmlXPathCompPathExpr: 10399 * @ctxt: the XPath Parser context 10400 * 10401 * [19] PathExpr ::= LocationPath 10402 * | FilterExpr 10403 * | FilterExpr '/' RelativeLocationPath 10404 * | FilterExpr '//' RelativeLocationPath 10405 * 10406 * Compile a path expression. 10407 * The / operator and // operators combine an arbitrary expression 10408 * and a relative location path. It is an error if the expression 10409 * does not evaluate to a node-set. 10410 * The / operator does composition in the same way as when / is 10411 * used in a location path. As in location paths, // is short for 10412 * /descendant-or-self::node()/. 10413 */ 10414 10415static void 10416xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10417 int lc = 1; /* Should we branch to LocationPath ? */ 10418 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10419 10420 SKIP_BLANKS; 10421 if ((CUR == '$') || (CUR == '(') || 10422 (IS_ASCII_DIGIT(CUR)) || 10423 (CUR == '\'') || (CUR == '"') || 10424 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10425 lc = 0; 10426 } else if (CUR == '*') { 10427 /* relative or absolute location path */ 10428 lc = 1; 10429 } else if (CUR == '/') { 10430 /* relative or absolute location path */ 10431 lc = 1; 10432 } else if (CUR == '@') { 10433 /* relative abbreviated attribute location path */ 10434 lc = 1; 10435 } else if (CUR == '.') { 10436 /* relative abbreviated attribute location path */ 10437 lc = 1; 10438 } else { 10439 /* 10440 * Problem is finding if we have a name here whether it's: 10441 * - a nodetype 10442 * - a function call in which case it's followed by '(' 10443 * - an axis in which case it's followed by ':' 10444 * - a element name 10445 * We do an a priori analysis here rather than having to 10446 * maintain parsed token content through the recursive function 10447 * calls. This looks uglier but makes the code easier to 10448 * read/write/debug. 10449 */ 10450 SKIP_BLANKS; 10451 name = xmlXPathScanName(ctxt); 10452 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10453#ifdef DEBUG_STEP 10454 xmlGenericError(xmlGenericErrorContext, 10455 "PathExpr: Axis\n"); 10456#endif 10457 lc = 1; 10458 xmlFree(name); 10459 } else if (name != NULL) { 10460 int len =xmlStrlen(name); 10461 10462 10463 while (NXT(len) != 0) { 10464 if (NXT(len) == '/') { 10465 /* element name */ 10466#ifdef DEBUG_STEP 10467 xmlGenericError(xmlGenericErrorContext, 10468 "PathExpr: AbbrRelLocation\n"); 10469#endif 10470 lc = 1; 10471 break; 10472 } else if (IS_BLANK_CH(NXT(len))) { 10473 /* ignore blanks */ 10474 ; 10475 } else if (NXT(len) == ':') { 10476#ifdef DEBUG_STEP 10477 xmlGenericError(xmlGenericErrorContext, 10478 "PathExpr: AbbrRelLocation\n"); 10479#endif 10480 lc = 1; 10481 break; 10482 } else if ((NXT(len) == '(')) { 10483 /* Note Type or Function */ 10484 if (xmlXPathIsNodeType(name)) { 10485#ifdef DEBUG_STEP 10486 xmlGenericError(xmlGenericErrorContext, 10487 "PathExpr: Type search\n"); 10488#endif 10489 lc = 1; 10490 } else { 10491#ifdef DEBUG_STEP 10492 xmlGenericError(xmlGenericErrorContext, 10493 "PathExpr: function call\n"); 10494#endif 10495 lc = 0; 10496 } 10497 break; 10498 } else if ((NXT(len) == '[')) { 10499 /* element name */ 10500#ifdef DEBUG_STEP 10501 xmlGenericError(xmlGenericErrorContext, 10502 "PathExpr: AbbrRelLocation\n"); 10503#endif 10504 lc = 1; 10505 break; 10506 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10507 (NXT(len) == '=')) { 10508 lc = 1; 10509 break; 10510 } else { 10511 lc = 1; 10512 break; 10513 } 10514 len++; 10515 } 10516 if (NXT(len) == 0) { 10517#ifdef DEBUG_STEP 10518 xmlGenericError(xmlGenericErrorContext, 10519 "PathExpr: AbbrRelLocation\n"); 10520#endif 10521 /* element name */ 10522 lc = 1; 10523 } 10524 xmlFree(name); 10525 } else { 10526 /* make sure all cases are covered explicitly */ 10527 XP_ERROR(XPATH_EXPR_ERROR); 10528 } 10529 } 10530 10531 if (lc) { 10532 if (CUR == '/') { 10533 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10534 } else { 10535 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10536 } 10537 xmlXPathCompLocationPath(ctxt); 10538 } else { 10539 xmlXPathCompFilterExpr(ctxt); 10540 CHECK_ERROR; 10541 if ((CUR == '/') && (NXT(1) == '/')) { 10542 SKIP(2); 10543 SKIP_BLANKS; 10544 10545 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10546 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10547 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 10548 10549 xmlXPathCompRelativeLocationPath(ctxt); 10550 } else if (CUR == '/') { 10551 xmlXPathCompRelativeLocationPath(ctxt); 10552 } 10553 } 10554 SKIP_BLANKS; 10555} 10556 10557/** 10558 * xmlXPathCompUnionExpr: 10559 * @ctxt: the XPath Parser context 10560 * 10561 * [18] UnionExpr ::= PathExpr 10562 * | UnionExpr '|' PathExpr 10563 * 10564 * Compile an union expression. 10565 */ 10566 10567static void 10568xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10569 xmlXPathCompPathExpr(ctxt); 10570 CHECK_ERROR; 10571 SKIP_BLANKS; 10572 while (CUR == '|') { 10573 int op1 = ctxt->comp->last; 10574 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10575 10576 NEXT; 10577 SKIP_BLANKS; 10578 xmlXPathCompPathExpr(ctxt); 10579 10580 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10581 10582 SKIP_BLANKS; 10583 } 10584} 10585 10586/** 10587 * xmlXPathCompUnaryExpr: 10588 * @ctxt: the XPath Parser context 10589 * 10590 * [27] UnaryExpr ::= UnionExpr 10591 * | '-' UnaryExpr 10592 * 10593 * Compile an unary expression. 10594 */ 10595 10596static void 10597xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10598 int minus = 0; 10599 int found = 0; 10600 10601 SKIP_BLANKS; 10602 while (CUR == '-') { 10603 minus = 1 - minus; 10604 found = 1; 10605 NEXT; 10606 SKIP_BLANKS; 10607 } 10608 10609 xmlXPathCompUnionExpr(ctxt); 10610 CHECK_ERROR; 10611 if (found) { 10612 if (minus) 10613 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10614 else 10615 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10616 } 10617} 10618 10619/** 10620 * xmlXPathCompMultiplicativeExpr: 10621 * @ctxt: the XPath Parser context 10622 * 10623 * [26] MultiplicativeExpr ::= UnaryExpr 10624 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10625 * | MultiplicativeExpr 'div' UnaryExpr 10626 * | MultiplicativeExpr 'mod' UnaryExpr 10627 * [34] MultiplyOperator ::= '*' 10628 * 10629 * Compile an Additive expression. 10630 */ 10631 10632static void 10633xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10634 xmlXPathCompUnaryExpr(ctxt); 10635 CHECK_ERROR; 10636 SKIP_BLANKS; 10637 while ((CUR == '*') || 10638 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10639 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10640 int op = -1; 10641 int op1 = ctxt->comp->last; 10642 10643 if (CUR == '*') { 10644 op = 0; 10645 NEXT; 10646 } else if (CUR == 'd') { 10647 op = 1; 10648 SKIP(3); 10649 } else if (CUR == 'm') { 10650 op = 2; 10651 SKIP(3); 10652 } 10653 SKIP_BLANKS; 10654 xmlXPathCompUnaryExpr(ctxt); 10655 CHECK_ERROR; 10656 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10657 SKIP_BLANKS; 10658 } 10659} 10660 10661/** 10662 * xmlXPathCompAdditiveExpr: 10663 * @ctxt: the XPath Parser context 10664 * 10665 * [25] AdditiveExpr ::= MultiplicativeExpr 10666 * | AdditiveExpr '+' MultiplicativeExpr 10667 * | AdditiveExpr '-' MultiplicativeExpr 10668 * 10669 * Compile an Additive expression. 10670 */ 10671 10672static void 10673xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10674 10675 xmlXPathCompMultiplicativeExpr(ctxt); 10676 CHECK_ERROR; 10677 SKIP_BLANKS; 10678 while ((CUR == '+') || (CUR == '-')) { 10679 int plus; 10680 int op1 = ctxt->comp->last; 10681 10682 if (CUR == '+') plus = 1; 10683 else plus = 0; 10684 NEXT; 10685 SKIP_BLANKS; 10686 xmlXPathCompMultiplicativeExpr(ctxt); 10687 CHECK_ERROR; 10688 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10689 SKIP_BLANKS; 10690 } 10691} 10692 10693/** 10694 * xmlXPathCompRelationalExpr: 10695 * @ctxt: the XPath Parser context 10696 * 10697 * [24] RelationalExpr ::= AdditiveExpr 10698 * | RelationalExpr '<' AdditiveExpr 10699 * | RelationalExpr '>' AdditiveExpr 10700 * | RelationalExpr '<=' AdditiveExpr 10701 * | RelationalExpr '>=' AdditiveExpr 10702 * 10703 * A <= B > C is allowed ? Answer from James, yes with 10704 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10705 * which is basically what got implemented. 10706 * 10707 * Compile a Relational expression, then push the result 10708 * on the stack 10709 */ 10710 10711static void 10712xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10713 xmlXPathCompAdditiveExpr(ctxt); 10714 CHECK_ERROR; 10715 SKIP_BLANKS; 10716 while ((CUR == '<') || 10717 (CUR == '>') || 10718 ((CUR == '<') && (NXT(1) == '=')) || 10719 ((CUR == '>') && (NXT(1) == '='))) { 10720 int inf, strict; 10721 int op1 = ctxt->comp->last; 10722 10723 if (CUR == '<') inf = 1; 10724 else inf = 0; 10725 if (NXT(1) == '=') strict = 0; 10726 else strict = 1; 10727 NEXT; 10728 if (!strict) NEXT; 10729 SKIP_BLANKS; 10730 xmlXPathCompAdditiveExpr(ctxt); 10731 CHECK_ERROR; 10732 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10733 SKIP_BLANKS; 10734 } 10735} 10736 10737/** 10738 * xmlXPathCompEqualityExpr: 10739 * @ctxt: the XPath Parser context 10740 * 10741 * [23] EqualityExpr ::= RelationalExpr 10742 * | EqualityExpr '=' RelationalExpr 10743 * | EqualityExpr '!=' RelationalExpr 10744 * 10745 * A != B != C is allowed ? Answer from James, yes with 10746 * (RelationalExpr = RelationalExpr) = RelationalExpr 10747 * (RelationalExpr != RelationalExpr) != RelationalExpr 10748 * which is basically what got implemented. 10749 * 10750 * Compile an Equality expression. 10751 * 10752 */ 10753static void 10754xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10755 xmlXPathCompRelationalExpr(ctxt); 10756 CHECK_ERROR; 10757 SKIP_BLANKS; 10758 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10759 int eq; 10760 int op1 = ctxt->comp->last; 10761 10762 if (CUR == '=') eq = 1; 10763 else eq = 0; 10764 NEXT; 10765 if (!eq) NEXT; 10766 SKIP_BLANKS; 10767 xmlXPathCompRelationalExpr(ctxt); 10768 CHECK_ERROR; 10769 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10770 SKIP_BLANKS; 10771 } 10772} 10773 10774/** 10775 * xmlXPathCompAndExpr: 10776 * @ctxt: the XPath Parser context 10777 * 10778 * [22] AndExpr ::= EqualityExpr 10779 * | AndExpr 'and' EqualityExpr 10780 * 10781 * Compile an AND expression. 10782 * 10783 */ 10784static void 10785xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10786 xmlXPathCompEqualityExpr(ctxt); 10787 CHECK_ERROR; 10788 SKIP_BLANKS; 10789 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10790 int op1 = ctxt->comp->last; 10791 SKIP(3); 10792 SKIP_BLANKS; 10793 xmlXPathCompEqualityExpr(ctxt); 10794 CHECK_ERROR; 10795 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 10796 SKIP_BLANKS; 10797 } 10798} 10799 10800/** 10801 * xmlXPathCompileExpr: 10802 * @ctxt: the XPath Parser context 10803 * 10804 * [14] Expr ::= OrExpr 10805 * [21] OrExpr ::= AndExpr 10806 * | OrExpr 'or' AndExpr 10807 * 10808 * Parse and compile an expression 10809 */ 10810static void 10811xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 10812 xmlXPathCompAndExpr(ctxt); 10813 CHECK_ERROR; 10814 SKIP_BLANKS; 10815 while ((CUR == 'o') && (NXT(1) == 'r')) { 10816 int op1 = ctxt->comp->last; 10817 SKIP(2); 10818 SKIP_BLANKS; 10819 xmlXPathCompAndExpr(ctxt); 10820 CHECK_ERROR; 10821 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 10822 op1 = ctxt->comp->nbStep; 10823 SKIP_BLANKS; 10824 } 10825 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 10826 /* more ops could be optimized too */ 10827 /* 10828 * This is the main place to eliminate sorting for 10829 * operations which don't require a sorted node-set. 10830 * E.g. count(). 10831 */ 10832 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 10833 } 10834} 10835 10836/** 10837 * xmlXPathCompPredicate: 10838 * @ctxt: the XPath Parser context 10839 * @filter: act as a filter 10840 * 10841 * [8] Predicate ::= '[' PredicateExpr ']' 10842 * [9] PredicateExpr ::= Expr 10843 * 10844 * Compile a predicate expression 10845 */ 10846static void 10847xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 10848 int op1 = ctxt->comp->last; 10849 10850 SKIP_BLANKS; 10851 if (CUR != '[') { 10852 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10853 } 10854 NEXT; 10855 SKIP_BLANKS; 10856 10857 ctxt->comp->last = -1; 10858 /* 10859 * This call to xmlXPathCompileExpr() will deactivate sorting 10860 * of the predicate result. 10861 * TODO: Sorting is still activated for filters, since I'm not 10862 * sure if needed. Normally sorting should not be needed, since 10863 * a filter can only diminish the number of items in a sequence, 10864 * but won't change its order; so if the initial sequence is sorted, 10865 * subsequent sorting is not needed. 10866 */ 10867 if (! filter) 10868 xmlXPathCompileExpr(ctxt, 0); 10869 else 10870 xmlXPathCompileExpr(ctxt, 1); 10871 CHECK_ERROR; 10872 10873 if (CUR != ']') { 10874 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10875 } 10876 10877 if (filter) 10878 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 10879 else 10880 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 10881 10882 NEXT; 10883 SKIP_BLANKS; 10884} 10885 10886/** 10887 * xmlXPathCompNodeTest: 10888 * @ctxt: the XPath Parser context 10889 * @test: pointer to a xmlXPathTestVal 10890 * @type: pointer to a xmlXPathTypeVal 10891 * @prefix: placeholder for a possible name prefix 10892 * 10893 * [7] NodeTest ::= NameTest 10894 * | NodeType '(' ')' 10895 * | 'processing-instruction' '(' Literal ')' 10896 * 10897 * [37] NameTest ::= '*' 10898 * | NCName ':' '*' 10899 * | QName 10900 * [38] NodeType ::= 'comment' 10901 * | 'text' 10902 * | 'processing-instruction' 10903 * | 'node' 10904 * 10905 * Returns the name found and updates @test, @type and @prefix appropriately 10906 */ 10907static xmlChar * 10908xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 10909 xmlXPathTypeVal *type, const xmlChar **prefix, 10910 xmlChar *name) { 10911 int blanks; 10912 10913 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 10914 STRANGE; 10915 return(NULL); 10916 } 10917 *type = (xmlXPathTypeVal) 0; 10918 *test = (xmlXPathTestVal) 0; 10919 *prefix = NULL; 10920 SKIP_BLANKS; 10921 10922 if ((name == NULL) && (CUR == '*')) { 10923 /* 10924 * All elements 10925 */ 10926 NEXT; 10927 *test = NODE_TEST_ALL; 10928 return(NULL); 10929 } 10930 10931 if (name == NULL) 10932 name = xmlXPathParseNCName(ctxt); 10933 if (name == NULL) { 10934 XP_ERRORNULL(XPATH_EXPR_ERROR); 10935 } 10936 10937 blanks = IS_BLANK_CH(CUR); 10938 SKIP_BLANKS; 10939 if (CUR == '(') { 10940 NEXT; 10941 /* 10942 * NodeType or PI search 10943 */ 10944 if (xmlStrEqual(name, BAD_CAST "comment")) 10945 *type = NODE_TYPE_COMMENT; 10946 else if (xmlStrEqual(name, BAD_CAST "node")) 10947 *type = NODE_TYPE_NODE; 10948 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10949 *type = NODE_TYPE_PI; 10950 else if (xmlStrEqual(name, BAD_CAST "text")) 10951 *type = NODE_TYPE_TEXT; 10952 else { 10953 if (name != NULL) 10954 xmlFree(name); 10955 XP_ERRORNULL(XPATH_EXPR_ERROR); 10956 } 10957 10958 *test = NODE_TEST_TYPE; 10959 10960 SKIP_BLANKS; 10961 if (*type == NODE_TYPE_PI) { 10962 /* 10963 * Specific case: search a PI by name. 10964 */ 10965 if (name != NULL) 10966 xmlFree(name); 10967 name = NULL; 10968 if (CUR != ')') { 10969 name = xmlXPathParseLiteral(ctxt); 10970 CHECK_ERROR NULL; 10971 *test = NODE_TEST_PI; 10972 SKIP_BLANKS; 10973 } 10974 } 10975 if (CUR != ')') { 10976 if (name != NULL) 10977 xmlFree(name); 10978 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 10979 } 10980 NEXT; 10981 return(name); 10982 } 10983 *test = NODE_TEST_NAME; 10984 if ((!blanks) && (CUR == ':')) { 10985 NEXT; 10986 10987 /* 10988 * Since currently the parser context don't have a 10989 * namespace list associated: 10990 * The namespace name for this prefix can be computed 10991 * only at evaluation time. The compilation is done 10992 * outside of any context. 10993 */ 10994#if 0 10995 *prefix = xmlXPathNsLookup(ctxt->context, name); 10996 if (name != NULL) 10997 xmlFree(name); 10998 if (*prefix == NULL) { 10999 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11000 } 11001#else 11002 *prefix = name; 11003#endif 11004 11005 if (CUR == '*') { 11006 /* 11007 * All elements 11008 */ 11009 NEXT; 11010 *test = NODE_TEST_ALL; 11011 return(NULL); 11012 } 11013 11014 name = xmlXPathParseNCName(ctxt); 11015 if (name == NULL) { 11016 XP_ERRORNULL(XPATH_EXPR_ERROR); 11017 } 11018 } 11019 return(name); 11020} 11021 11022/** 11023 * xmlXPathIsAxisName: 11024 * @name: a preparsed name token 11025 * 11026 * [6] AxisName ::= 'ancestor' 11027 * | 'ancestor-or-self' 11028 * | 'attribute' 11029 * | 'child' 11030 * | 'descendant' 11031 * | 'descendant-or-self' 11032 * | 'following' 11033 * | 'following-sibling' 11034 * | 'namespace' 11035 * | 'parent' 11036 * | 'preceding' 11037 * | 'preceding-sibling' 11038 * | 'self' 11039 * 11040 * Returns the axis or 0 11041 */ 11042static xmlXPathAxisVal 11043xmlXPathIsAxisName(const xmlChar *name) { 11044 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11045 switch (name[0]) { 11046 case 'a': 11047 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11048 ret = AXIS_ANCESTOR; 11049 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11050 ret = AXIS_ANCESTOR_OR_SELF; 11051 if (xmlStrEqual(name, BAD_CAST "attribute")) 11052 ret = AXIS_ATTRIBUTE; 11053 break; 11054 case 'c': 11055 if (xmlStrEqual(name, BAD_CAST "child")) 11056 ret = AXIS_CHILD; 11057 break; 11058 case 'd': 11059 if (xmlStrEqual(name, BAD_CAST "descendant")) 11060 ret = AXIS_DESCENDANT; 11061 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11062 ret = AXIS_DESCENDANT_OR_SELF; 11063 break; 11064 case 'f': 11065 if (xmlStrEqual(name, BAD_CAST "following")) 11066 ret = AXIS_FOLLOWING; 11067 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11068 ret = AXIS_FOLLOWING_SIBLING; 11069 break; 11070 case 'n': 11071 if (xmlStrEqual(name, BAD_CAST "namespace")) 11072 ret = AXIS_NAMESPACE; 11073 break; 11074 case 'p': 11075 if (xmlStrEqual(name, BAD_CAST "parent")) 11076 ret = AXIS_PARENT; 11077 if (xmlStrEqual(name, BAD_CAST "preceding")) 11078 ret = AXIS_PRECEDING; 11079 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11080 ret = AXIS_PRECEDING_SIBLING; 11081 break; 11082 case 's': 11083 if (xmlStrEqual(name, BAD_CAST "self")) 11084 ret = AXIS_SELF; 11085 break; 11086 } 11087 return(ret); 11088} 11089 11090/** 11091 * xmlXPathCompStep: 11092 * @ctxt: the XPath Parser context 11093 * 11094 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11095 * | AbbreviatedStep 11096 * 11097 * [12] AbbreviatedStep ::= '.' | '..' 11098 * 11099 * [5] AxisSpecifier ::= AxisName '::' 11100 * | AbbreviatedAxisSpecifier 11101 * 11102 * [13] AbbreviatedAxisSpecifier ::= '@'? 11103 * 11104 * Modified for XPtr range support as: 11105 * 11106 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11107 * | AbbreviatedStep 11108 * | 'range-to' '(' Expr ')' Predicate* 11109 * 11110 * Compile one step in a Location Path 11111 * A location step of . is short for self::node(). This is 11112 * particularly useful in conjunction with //. For example, the 11113 * location path .//para is short for 11114 * self::node()/descendant-or-self::node()/child::para 11115 * and so will select all para descendant elements of the context 11116 * node. 11117 * Similarly, a location step of .. is short for parent::node(). 11118 * For example, ../title is short for parent::node()/child::title 11119 * and so will select the title children of the parent of the context 11120 * node. 11121 */ 11122static void 11123xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11124#ifdef LIBXML_XPTR_ENABLED 11125 int rangeto = 0; 11126 int op2 = -1; 11127#endif 11128 11129 SKIP_BLANKS; 11130 if ((CUR == '.') && (NXT(1) == '.')) { 11131 SKIP(2); 11132 SKIP_BLANKS; 11133 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11134 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11135 } else if (CUR == '.') { 11136 NEXT; 11137 SKIP_BLANKS; 11138 } else { 11139 xmlChar *name = NULL; 11140 const xmlChar *prefix = NULL; 11141 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11142 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11143 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11144 int op1; 11145 11146 /* 11147 * The modification needed for XPointer change to the production 11148 */ 11149#ifdef LIBXML_XPTR_ENABLED 11150 if (ctxt->xptr) { 11151 name = xmlXPathParseNCName(ctxt); 11152 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11153 op2 = ctxt->comp->last; 11154 xmlFree(name); 11155 SKIP_BLANKS; 11156 if (CUR != '(') { 11157 XP_ERROR(XPATH_EXPR_ERROR); 11158 } 11159 NEXT; 11160 SKIP_BLANKS; 11161 11162 xmlXPathCompileExpr(ctxt, 1); 11163 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11164 CHECK_ERROR; 11165 11166 SKIP_BLANKS; 11167 if (CUR != ')') { 11168 XP_ERROR(XPATH_EXPR_ERROR); 11169 } 11170 NEXT; 11171 rangeto = 1; 11172 goto eval_predicates; 11173 } 11174 } 11175#endif 11176 if (CUR == '*') { 11177 axis = AXIS_CHILD; 11178 } else { 11179 if (name == NULL) 11180 name = xmlXPathParseNCName(ctxt); 11181 if (name != NULL) { 11182 axis = xmlXPathIsAxisName(name); 11183 if (axis != 0) { 11184 SKIP_BLANKS; 11185 if ((CUR == ':') && (NXT(1) == ':')) { 11186 SKIP(2); 11187 xmlFree(name); 11188 name = NULL; 11189 } else { 11190 /* an element name can conflict with an axis one :-\ */ 11191 axis = AXIS_CHILD; 11192 } 11193 } else { 11194 axis = AXIS_CHILD; 11195 } 11196 } else if (CUR == '@') { 11197 NEXT; 11198 axis = AXIS_ATTRIBUTE; 11199 } else { 11200 axis = AXIS_CHILD; 11201 } 11202 } 11203 11204 CHECK_ERROR; 11205 11206 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11207 if (test == 0) 11208 return; 11209 11210 if ((prefix != NULL) && (ctxt->context != NULL) && 11211 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11212 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11213 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11214 } 11215 } 11216#ifdef DEBUG_STEP 11217 xmlGenericError(xmlGenericErrorContext, 11218 "Basis : computing new set\n"); 11219#endif 11220 11221#ifdef DEBUG_STEP 11222 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11223 if (ctxt->value == NULL) 11224 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11225 else if (ctxt->value->nodesetval == NULL) 11226 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11227 else 11228 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11229#endif 11230 11231#ifdef LIBXML_XPTR_ENABLED 11232eval_predicates: 11233#endif 11234 op1 = ctxt->comp->last; 11235 ctxt->comp->last = -1; 11236 11237 SKIP_BLANKS; 11238 while (CUR == '[') { 11239 xmlXPathCompPredicate(ctxt, 0); 11240 } 11241 11242#ifdef LIBXML_XPTR_ENABLED 11243 if (rangeto) { 11244 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11245 } else 11246#endif 11247 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11248 test, type, (void *)prefix, (void *)name); 11249 11250 } 11251#ifdef DEBUG_STEP 11252 xmlGenericError(xmlGenericErrorContext, "Step : "); 11253 if (ctxt->value == NULL) 11254 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11255 else if (ctxt->value->nodesetval == NULL) 11256 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11257 else 11258 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11259 ctxt->value->nodesetval); 11260#endif 11261} 11262 11263/** 11264 * xmlXPathCompRelativeLocationPath: 11265 * @ctxt: the XPath Parser context 11266 * 11267 * [3] RelativeLocationPath ::= Step 11268 * | RelativeLocationPath '/' Step 11269 * | AbbreviatedRelativeLocationPath 11270 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11271 * 11272 * Compile a relative location path. 11273 */ 11274static void 11275xmlXPathCompRelativeLocationPath 11276(xmlXPathParserContextPtr ctxt) { 11277 SKIP_BLANKS; 11278 if ((CUR == '/') && (NXT(1) == '/')) { 11279 SKIP(2); 11280 SKIP_BLANKS; 11281 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11282 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11283 } else if (CUR == '/') { 11284 NEXT; 11285 SKIP_BLANKS; 11286 } 11287 xmlXPathCompStep(ctxt); 11288 SKIP_BLANKS; 11289 while (CUR == '/') { 11290 if ((CUR == '/') && (NXT(1) == '/')) { 11291 SKIP(2); 11292 SKIP_BLANKS; 11293 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11294 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11295 xmlXPathCompStep(ctxt); 11296 } else if (CUR == '/') { 11297 NEXT; 11298 SKIP_BLANKS; 11299 xmlXPathCompStep(ctxt); 11300 } 11301 SKIP_BLANKS; 11302 } 11303} 11304 11305/** 11306 * xmlXPathCompLocationPath: 11307 * @ctxt: the XPath Parser context 11308 * 11309 * [1] LocationPath ::= RelativeLocationPath 11310 * | AbsoluteLocationPath 11311 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11312 * | AbbreviatedAbsoluteLocationPath 11313 * [10] AbbreviatedAbsoluteLocationPath ::= 11314 * '//' RelativeLocationPath 11315 * 11316 * Compile a location path 11317 * 11318 * // is short for /descendant-or-self::node()/. For example, 11319 * //para is short for /descendant-or-self::node()/child::para and 11320 * so will select any para element in the document (even a para element 11321 * that is a document element will be selected by //para since the 11322 * document element node is a child of the root node); div//para is 11323 * short for div/descendant-or-self::node()/child::para and so will 11324 * select all para descendants of div children. 11325 */ 11326static void 11327xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11328 SKIP_BLANKS; 11329 if (CUR != '/') { 11330 xmlXPathCompRelativeLocationPath(ctxt); 11331 } else { 11332 while (CUR == '/') { 11333 if ((CUR == '/') && (NXT(1) == '/')) { 11334 SKIP(2); 11335 SKIP_BLANKS; 11336 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11337 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11338 xmlXPathCompRelativeLocationPath(ctxt); 11339 } else if (CUR == '/') { 11340 NEXT; 11341 SKIP_BLANKS; 11342 if ((CUR != 0 ) && 11343 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11344 (CUR == '@') || (CUR == '*'))) 11345 xmlXPathCompRelativeLocationPath(ctxt); 11346 } 11347 } 11348 } 11349} 11350 11351/************************************************************************ 11352 * * 11353 * XPath precompiled expression evaluation * 11354 * * 11355 ************************************************************************/ 11356 11357static int 11358xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11359 11360#ifdef DEBUG_STEP 11361static void 11362xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis, 11363 xmlXPathTestVal test, 11364 int nbNodes) 11365{ 11366 xmlGenericError(xmlGenericErrorContext, "new step : "); 11367 switch (axis) { 11368 case AXIS_ANCESTOR: 11369 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11370 break; 11371 case AXIS_ANCESTOR_OR_SELF: 11372 xmlGenericError(xmlGenericErrorContext, 11373 "axis 'ancestors-or-self' "); 11374 break; 11375 case AXIS_ATTRIBUTE: 11376 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11377 break; 11378 case AXIS_CHILD: 11379 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11380 break; 11381 case AXIS_DESCENDANT: 11382 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11383 break; 11384 case AXIS_DESCENDANT_OR_SELF: 11385 xmlGenericError(xmlGenericErrorContext, 11386 "axis 'descendant-or-self' "); 11387 break; 11388 case AXIS_FOLLOWING: 11389 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11390 break; 11391 case AXIS_FOLLOWING_SIBLING: 11392 xmlGenericError(xmlGenericErrorContext, 11393 "axis 'following-siblings' "); 11394 break; 11395 case AXIS_NAMESPACE: 11396 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11397 break; 11398 case AXIS_PARENT: 11399 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11400 break; 11401 case AXIS_PRECEDING: 11402 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11403 break; 11404 case AXIS_PRECEDING_SIBLING: 11405 xmlGenericError(xmlGenericErrorContext, 11406 "axis 'preceding-sibling' "); 11407 break; 11408 case AXIS_SELF: 11409 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11410 break; 11411 } 11412 xmlGenericError(xmlGenericErrorContext, 11413 " context contains %d nodes\n", nbNodes); 11414 switch (test) { 11415 case NODE_TEST_NONE: 11416 xmlGenericError(xmlGenericErrorContext, 11417 " searching for none !!!\n"); 11418 break; 11419 case NODE_TEST_TYPE: 11420 xmlGenericError(xmlGenericErrorContext, 11421 " searching for type %d\n", type); 11422 break; 11423 case NODE_TEST_PI: 11424 xmlGenericError(xmlGenericErrorContext, 11425 " searching for PI !!!\n"); 11426 break; 11427 case NODE_TEST_ALL: 11428 xmlGenericError(xmlGenericErrorContext, 11429 " searching for *\n"); 11430 break; 11431 case NODE_TEST_NS: 11432 xmlGenericError(xmlGenericErrorContext, 11433 " searching for namespace %s\n", 11434 prefix); 11435 break; 11436 case NODE_TEST_NAME: 11437 xmlGenericError(xmlGenericErrorContext, 11438 " searching for name %s\n", name); 11439 if (prefix != NULL) 11440 xmlGenericError(xmlGenericErrorContext, 11441 " with namespace %s\n", prefix); 11442 break; 11443 } 11444 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11445} 11446#endif /* DEBUG_STEP */ 11447 11448static int 11449xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11450 xmlXPathStepOpPtr op, 11451 xmlNodeSetPtr set, 11452 int contextSize, 11453 int hasNsNodes) 11454{ 11455 if (op->ch1 != -1) { 11456 xmlXPathCompExprPtr comp = ctxt->comp; 11457 /* 11458 * Process inner predicates first. 11459 */ 11460 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11461 /* 11462 * TODO: raise an internal error. 11463 */ 11464 } 11465 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11466 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11467 CHECK_ERROR0; 11468 if (contextSize <= 0) 11469 return(0); 11470 } 11471 if (op->ch2 != -1) { 11472 xmlXPathContextPtr xpctxt = ctxt->context; 11473 xmlNodePtr contextNode, oldContextNode; 11474 xmlDocPtr oldContextDoc; 11475 int i, res, contextPos = 0, newContextSize; 11476 xmlXPathStepOpPtr exprOp; 11477 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11478 11479#ifdef LIBXML_XPTR_ENABLED 11480 /* 11481 * URGENT TODO: Check the following: 11482 * We don't expect location sets if evaluating prediates, right? 11483 * Only filters should expect location sets, right? 11484 */ 11485#endif 11486 /* 11487 * SPEC XPath 1.0: 11488 * "For each node in the node-set to be filtered, the 11489 * PredicateExpr is evaluated with that node as the 11490 * context node, with the number of nodes in the 11491 * node-set as the context size, and with the proximity 11492 * position of the node in the node-set with respect to 11493 * the axis as the context position;" 11494 * @oldset is the node-set" to be filtered. 11495 * 11496 * SPEC XPath 1.0: 11497 * "only predicates change the context position and 11498 * context size (see [2.4 Predicates])." 11499 * Example: 11500 * node-set context pos 11501 * nA 1 11502 * nB 2 11503 * nC 3 11504 * After applying predicate [position() > 1] : 11505 * node-set context pos 11506 * nB 1 11507 * nC 2 11508 */ 11509 oldContextNode = xpctxt->node; 11510 oldContextDoc = xpctxt->doc; 11511 /* 11512 * Get the expression of this predicate. 11513 */ 11514 exprOp = &ctxt->comp->steps[op->ch2]; 11515 newContextSize = 0; 11516 for (i = 0; i < set->nodeNr; i++) { 11517 if (set->nodeTab[i] == NULL) 11518 continue; 11519 11520 contextNode = set->nodeTab[i]; 11521 xpctxt->node = contextNode; 11522 xpctxt->contextSize = contextSize; 11523 xpctxt->proximityPosition = ++contextPos; 11524 11525 /* 11526 * Also set the xpath document in case things like 11527 * key() are evaluated in the predicate. 11528 */ 11529 if ((contextNode->type != XML_NAMESPACE_DECL) && 11530 (contextNode->doc != NULL)) 11531 xpctxt->doc = contextNode->doc; 11532 /* 11533 * Evaluate the predicate expression with 1 context node 11534 * at a time; this node is packaged into a node set; this 11535 * node set is handed over to the evaluation mechanism. 11536 */ 11537 if (contextObj == NULL) 11538 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11539 else 11540 xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11541 contextNode); 11542 11543 valuePush(ctxt, contextObj); 11544 11545 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11546 11547 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) 11548 goto evaluation_error; 11549 11550 if (res != 0) { 11551 newContextSize++; 11552 } else { 11553 /* 11554 * Remove the entry from the initial node set. 11555 */ 11556 set->nodeTab[i] = NULL; 11557 if (contextNode->type == XML_NAMESPACE_DECL) 11558 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11559 } 11560 if (ctxt->value == contextObj) { 11561 /* 11562 * Don't free the temporary XPath object holding the 11563 * context node, in order to avoid massive recreation 11564 * inside this loop. 11565 */ 11566 valuePop(ctxt); 11567 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11568 } else { 11569 /* 11570 * TODO: The object was lost in the evaluation machinery. 11571 * Can this happen? Maybe in internal-error cases. 11572 */ 11573 contextObj = NULL; 11574 } 11575 } 11576 goto evaluation_exit; 11577 11578evaluation_error: 11579 xmlXPathNodeSetClear(set, hasNsNodes); 11580 newContextSize = 0; 11581 11582evaluation_exit: 11583 if (contextObj != NULL) { 11584 if (ctxt->value == contextObj) 11585 valuePop(ctxt); 11586 xmlXPathReleaseObject(xpctxt, contextObj); 11587 } 11588 if (exprRes != NULL) 11589 xmlXPathReleaseObject(ctxt->context, exprRes); 11590 /* 11591 * Reset/invalidate the context. 11592 */ 11593 xpctxt->node = oldContextNode; 11594 xpctxt->doc = oldContextDoc; 11595 xpctxt->contextSize = -1; 11596 xpctxt->proximityPosition = -1; 11597 return(newContextSize); 11598 } 11599 return(contextSize); 11600} 11601 11602static int 11603xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, 11604 xmlXPathStepOpPtr op, 11605 xmlNodeSetPtr set, 11606 int contextSize, 11607 int minPos, 11608 int maxPos, 11609 int hasNsNodes) 11610{ 11611 if (op->ch1 != -1) { 11612 xmlXPathCompExprPtr comp = ctxt->comp; 11613 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11614 /* 11615 * TODO: raise an internal error. 11616 */ 11617 } 11618 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11619 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11620 CHECK_ERROR0; 11621 if (contextSize <= 0) 11622 return(0); 11623 } 11624 /* 11625 * Check if the node set contains a sufficient number of nodes for 11626 * the requested range. 11627 */ 11628 if (contextSize < minPos) { 11629 xmlXPathNodeSetClear(set, hasNsNodes); 11630 return(0); 11631 } 11632 if (op->ch2 == -1) { 11633 /* 11634 * TODO: Can this ever happen? 11635 */ 11636 return (contextSize); 11637 } else { 11638 xmlDocPtr oldContextDoc; 11639 int i, pos = 0, newContextSize = 0, contextPos = 0, res; 11640 xmlXPathStepOpPtr exprOp; 11641 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11642 xmlNodePtr oldContextNode, contextNode = NULL; 11643 xmlXPathContextPtr xpctxt = ctxt->context; 11644 11645#ifdef LIBXML_XPTR_ENABLED 11646 /* 11647 * URGENT TODO: Check the following: 11648 * We don't expect location sets if evaluating prediates, right? 11649 * Only filters should expect location sets, right? 11650 */ 11651#endif /* LIBXML_XPTR_ENABLED */ 11652 11653 /* 11654 * Save old context. 11655 */ 11656 oldContextNode = xpctxt->node; 11657 oldContextDoc = xpctxt->doc; 11658 /* 11659 * Get the expression of this predicate. 11660 */ 11661 exprOp = &ctxt->comp->steps[op->ch2]; 11662 for (i = 0; i < set->nodeNr; i++) { 11663 if (set->nodeTab[i] == NULL) 11664 continue; 11665 11666 contextNode = set->nodeTab[i]; 11667 xpctxt->node = contextNode; 11668 xpctxt->contextSize = contextSize; 11669 xpctxt->proximityPosition = ++contextPos; 11670 11671 /* 11672 * Initialize the new set. 11673 * Also set the xpath document in case things like 11674 * key() evaluation are attempted on the predicate 11675 */ 11676 if ((contextNode->type != XML_NAMESPACE_DECL) && 11677 (contextNode->doc != NULL)) 11678 xpctxt->doc = contextNode->doc; 11679 /* 11680 * Evaluate the predicate expression with 1 context node 11681 * at a time; this node is packaged into a node set; this 11682 * node set is handed over to the evaluation mechanism. 11683 */ 11684 if (contextObj == NULL) 11685 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11686 else 11687 xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11688 contextNode); 11689 11690 valuePush(ctxt, contextObj); 11691 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11692 11693 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) 11694 goto evaluation_error; 11695 11696 if (res) 11697 pos++; 11698 11699 if (res && (pos >= minPos) && (pos <= maxPos)) { 11700 /* 11701 * Fits in the requested range. 11702 */ 11703 newContextSize++; 11704 if (minPos == maxPos) { 11705 /* 11706 * Only 1 node was requested. 11707 */ 11708 if (contextNode->type == XML_NAMESPACE_DECL) { 11709 /* 11710 * As always: take care of those nasty 11711 * namespace nodes. 11712 */ 11713 set->nodeTab[i] = NULL; 11714 } 11715 xmlXPathNodeSetClear(set, hasNsNodes); 11716 set->nodeNr = 1; 11717 set->nodeTab[0] = contextNode; 11718 goto evaluation_exit; 11719 } 11720 if (pos == maxPos) { 11721 /* 11722 * We are done. 11723 */ 11724 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes); 11725 goto evaluation_exit; 11726 } 11727 } else { 11728 /* 11729 * Remove the entry from the initial node set. 11730 */ 11731 set->nodeTab[i] = NULL; 11732 if (contextNode->type == XML_NAMESPACE_DECL) 11733 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11734 } 11735 if (exprRes != NULL) { 11736 xmlXPathReleaseObject(ctxt->context, exprRes); 11737 exprRes = NULL; 11738 } 11739 if (ctxt->value == contextObj) { 11740 /* 11741 * Don't free the temporary XPath object holding the 11742 * context node, in order to avoid massive recreation 11743 * inside this loop. 11744 */ 11745 valuePop(ctxt); 11746 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11747 } else { 11748 /* 11749 * The object was lost in the evaluation machinery. 11750 * Can this happen? Maybe in case of internal-errors. 11751 */ 11752 contextObj = NULL; 11753 } 11754 } 11755 goto evaluation_exit; 11756 11757evaluation_error: 11758 xmlXPathNodeSetClear(set, hasNsNodes); 11759 newContextSize = 0; 11760 11761evaluation_exit: 11762 if (contextObj != NULL) { 11763 if (ctxt->value == contextObj) 11764 valuePop(ctxt); 11765 xmlXPathReleaseObject(xpctxt, contextObj); 11766 } 11767 if (exprRes != NULL) 11768 xmlXPathReleaseObject(ctxt->context, exprRes); 11769 /* 11770 * Reset/invalidate the context. 11771 */ 11772 xpctxt->node = oldContextNode; 11773 xpctxt->doc = oldContextDoc; 11774 xpctxt->contextSize = -1; 11775 xpctxt->proximityPosition = -1; 11776 return(newContextSize); 11777 } 11778 return(contextSize); 11779} 11780 11781static int 11782xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 11783 xmlXPathStepOpPtr op, 11784 int *maxPos) 11785{ 11786 11787 xmlXPathStepOpPtr exprOp; 11788 11789 /* 11790 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 11791 */ 11792 11793 /* 11794 * If not -1, then ch1 will point to: 11795 * 1) For predicates (XPATH_OP_PREDICATE): 11796 * - an inner predicate operator 11797 * 2) For filters (XPATH_OP_FILTER): 11798 * - an inner filter operater OR 11799 * - an expression selecting the node set. 11800 * E.g. "key('a', 'b')" or "(//foo | //bar)". 11801 */ 11802 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 11803 return(0); 11804 11805 if (op->ch2 != -1) { 11806 exprOp = &ctxt->comp->steps[op->ch2]; 11807 } else 11808 return(0); 11809 11810 if ((exprOp != NULL) && 11811 (exprOp->op == XPATH_OP_VALUE) && 11812 (exprOp->value4 != NULL) && 11813 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 11814 { 11815 /* 11816 * We have a "[n]" predicate here. 11817 * TODO: Unfortunately this simplistic test here is not 11818 * able to detect a position() predicate in compound 11819 * expressions like "[@attr = 'a" and position() = 1], 11820 * and even not the usage of position() in 11821 * "[position() = 1]"; thus - obviously - a position-range, 11822 * like it "[position() < 5]", is also not detected. 11823 * Maybe we could rewrite the AST to ease the optimization. 11824 */ 11825 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval; 11826 11827 if (((xmlXPathObjectPtr) exprOp->value4)->floatval == 11828 (float) *maxPos) 11829 { 11830 return(1); 11831 } 11832 } 11833 return(0); 11834} 11835 11836static int 11837xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 11838 xmlXPathStepOpPtr op, 11839 xmlNodePtr * first, xmlNodePtr * last, 11840 int toBool) 11841{ 11842 11843#define XP_TEST_HIT \ 11844 if (hasAxisRange != 0) { \ 11845 if (++pos == maxPos) { \ 11846 addNode(seq, cur); \ 11847 goto axis_range_end; } \ 11848 } else { \ 11849 addNode(seq, cur); \ 11850 if (breakOnFirstHit) goto first_hit; } 11851 11852#define XP_TEST_HIT_NS \ 11853 if (hasAxisRange != 0) { \ 11854 if (++pos == maxPos) { \ 11855 hasNsNodes = 1; \ 11856 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \ 11857 goto axis_range_end; } \ 11858 } else { \ 11859 hasNsNodes = 1; \ 11860 xmlXPathNodeSetAddNs(seq, \ 11861 xpctxt->node, (xmlNsPtr) cur); \ 11862 if (breakOnFirstHit) goto first_hit; } 11863 11864 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 11865 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 11866 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 11867 const xmlChar *prefix = op->value4; 11868 const xmlChar *name = op->value5; 11869 const xmlChar *URI = NULL; 11870 11871#ifdef DEBUG_STEP 11872 int nbMatches = 0, prevMatches = 0; 11873#endif 11874 int total = 0, hasNsNodes = 0; 11875 /* The popped object holding the context nodes */ 11876 xmlXPathObjectPtr obj; 11877 /* The set of context nodes for the node tests */ 11878 xmlNodeSetPtr contextSeq; 11879 int contextIdx; 11880 xmlNodePtr contextNode; 11881 /* The context node for a compound traversal */ 11882 xmlNodePtr outerContextNode; 11883 /* The final resulting node set wrt to all context nodes */ 11884 xmlNodeSetPtr outSeq; 11885 /* 11886 * The temporary resulting node set wrt 1 context node. 11887 * Used to feed predicate evaluation. 11888 */ 11889 xmlNodeSetPtr seq; 11890 xmlNodePtr cur; 11891 /* First predicate operator */ 11892 xmlXPathStepOpPtr predOp; 11893 int maxPos; /* The requested position() (when a "[n]" predicate) */ 11894 int hasPredicateRange, hasAxisRange, pos, size, newSize; 11895 int breakOnFirstHit; 11896 11897 xmlXPathTraversalFunction next = NULL; 11898 /* compound axis traversal */ 11899 xmlXPathTraversalFunctionExt outerNext = NULL; 11900 void (*addNode) (xmlNodeSetPtr, xmlNodePtr); 11901 xmlXPathNodeSetMergeFunction mergeAndClear; 11902 xmlNodePtr oldContextNode; 11903 xmlXPathContextPtr xpctxt = ctxt->context; 11904 11905 11906 CHECK_TYPE0(XPATH_NODESET); 11907 obj = valuePop(ctxt); 11908 /* 11909 * Setup namespaces. 11910 */ 11911 if (prefix != NULL) { 11912 URI = xmlXPathNsLookup(xpctxt, prefix); 11913 if (URI == NULL) { 11914 xmlXPathReleaseObject(xpctxt, obj); 11915 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11916 } 11917 } 11918 /* 11919 * Setup axis. 11920 * 11921 * MAYBE FUTURE TODO: merging optimizations: 11922 * - If the nodes to be traversed wrt to the initial nodes and 11923 * the current axis cannot overlap, then we could avoid searching 11924 * for duplicates during the merge. 11925 * But the question is how/when to evaluate if they cannot overlap. 11926 * Example: if we know that for two initial nodes, the one is 11927 * not in the ancestor-or-self axis of the other, then we could safely 11928 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 11929 * the descendant-or-self axis. 11930 */ 11931 addNode = xmlXPathNodeSetAdd; 11932 mergeAndClear = xmlXPathNodeSetMergeAndClear; 11933 switch (axis) { 11934 case AXIS_ANCESTOR: 11935 first = NULL; 11936 next = xmlXPathNextAncestor; 11937 break; 11938 case AXIS_ANCESTOR_OR_SELF: 11939 first = NULL; 11940 next = xmlXPathNextAncestorOrSelf; 11941 break; 11942 case AXIS_ATTRIBUTE: 11943 first = NULL; 11944 last = NULL; 11945 next = xmlXPathNextAttribute; 11946 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 11947 break; 11948 case AXIS_CHILD: 11949 last = NULL; 11950 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) { 11951 /* 11952 * This iterator will give us only nodes which can 11953 * hold element nodes. 11954 */ 11955 outerNext = xmlXPathNextDescendantOrSelfElemParent; 11956 } 11957 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 11958 (type == NODE_TYPE_NODE)) 11959 { 11960 /* 11961 * Optimization if an element node type is 'element'. 11962 */ 11963 next = xmlXPathNextChildElement; 11964 } else 11965 next = xmlXPathNextChild; 11966 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 11967 break; 11968 case AXIS_DESCENDANT: 11969 last = NULL; 11970 next = xmlXPathNextDescendant; 11971 break; 11972 case AXIS_DESCENDANT_OR_SELF: 11973 last = NULL; 11974 next = xmlXPathNextDescendantOrSelf; 11975 break; 11976 case AXIS_FOLLOWING: 11977 last = NULL; 11978 next = xmlXPathNextFollowing; 11979 break; 11980 case AXIS_FOLLOWING_SIBLING: 11981 last = NULL; 11982 next = xmlXPathNextFollowingSibling; 11983 break; 11984 case AXIS_NAMESPACE: 11985 first = NULL; 11986 last = NULL; 11987 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 11988 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 11989 break; 11990 case AXIS_PARENT: 11991 first = NULL; 11992 next = xmlXPathNextParent; 11993 break; 11994 case AXIS_PRECEDING: 11995 first = NULL; 11996 next = xmlXPathNextPrecedingInternal; 11997 break; 11998 case AXIS_PRECEDING_SIBLING: 11999 first = NULL; 12000 next = xmlXPathNextPrecedingSibling; 12001 break; 12002 case AXIS_SELF: 12003 first = NULL; 12004 last = NULL; 12005 next = xmlXPathNextSelf; 12006 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12007 break; 12008 } 12009 12010#ifdef DEBUG_STEP 12011 xmlXPathDebugDumpStepAxis(axis, test, 12012 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0); 12013#endif 12014 12015 if (next == NULL) { 12016 xmlXPathReleaseObject(xpctxt, obj); 12017 return(0); 12018 } 12019 contextSeq = obj->nodesetval; 12020 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12021 xmlXPathReleaseObject(xpctxt, obj); 12022 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12023 return(0); 12024 } 12025 /* 12026 * Predicate optimization --------------------------------------------- 12027 * If this step has a last predicate, which contains a position(), 12028 * then we'll optimize (although not exactly "position()", but only 12029 * the short-hand form, i.e., "[n]". 12030 * 12031 * Example - expression "/foo[parent::bar][1]": 12032 * 12033 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12034 * ROOT -- op->ch1 12035 * PREDICATE -- op->ch2 (predOp) 12036 * PREDICATE -- predOp->ch1 = [parent::bar] 12037 * SORT 12038 * COLLECT 'parent' 'name' 'node' bar 12039 * NODE 12040 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12041 * 12042 */ 12043 maxPos = 0; 12044 predOp = NULL; 12045 hasPredicateRange = 0; 12046 hasAxisRange = 0; 12047 if (op->ch2 != -1) { 12048 /* 12049 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12050 */ 12051 predOp = &ctxt->comp->steps[op->ch2]; 12052 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12053 if (predOp->ch1 != -1) { 12054 /* 12055 * Use the next inner predicate operator. 12056 */ 12057 predOp = &ctxt->comp->steps[predOp->ch1]; 12058 hasPredicateRange = 1; 12059 } else { 12060 /* 12061 * There's no other predicate than the [n] predicate. 12062 */ 12063 predOp = NULL; 12064 hasAxisRange = 1; 12065 } 12066 } 12067 } 12068 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12069 /* 12070 * Axis traversal ----------------------------------------------------- 12071 */ 12072 /* 12073 * 2.3 Node Tests 12074 * - For the attribute axis, the principal node type is attribute. 12075 * - For the namespace axis, the principal node type is namespace. 12076 * - For other axes, the principal node type is element. 12077 * 12078 * A node test * is true for any node of the 12079 * principal node type. For example, child::* will 12080 * select all element children of the context node 12081 */ 12082 oldContextNode = xpctxt->node; 12083 addNode = xmlXPathNodeSetAddUnique; 12084 outSeq = NULL; 12085 seq = NULL; 12086 outerContextNode = NULL; 12087 contextNode = NULL; 12088 contextIdx = 0; 12089 12090 12091 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) { 12092 if (outerNext != NULL) { 12093 /* 12094 * This is a compound traversal. 12095 */ 12096 if (contextNode == NULL) { 12097 /* 12098 * Set the context for the outer traversal. 12099 */ 12100 outerContextNode = contextSeq->nodeTab[contextIdx++]; 12101 contextNode = outerNext(NULL, outerContextNode); 12102 } else 12103 contextNode = outerNext(contextNode, outerContextNode); 12104 if (contextNode == NULL) 12105 continue; 12106 /* 12107 * Set the context for the main traversal. 12108 */ 12109 xpctxt->node = contextNode; 12110 } else 12111 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12112 12113 if (seq == NULL) { 12114 seq = xmlXPathNodeSetCreate(NULL); 12115 if (seq == NULL) { 12116 total = 0; 12117 goto error; 12118 } 12119 } 12120 /* 12121 * Traverse the axis and test the nodes. 12122 */ 12123 pos = 0; 12124 cur = NULL; 12125 hasNsNodes = 0; 12126 do { 12127 cur = next(ctxt, cur); 12128 if (cur == NULL) 12129 break; 12130 12131 /* 12132 * QUESTION TODO: What does the "first" and "last" stuff do? 12133 */ 12134 if ((first != NULL) && (*first != NULL)) { 12135 if (*first == cur) 12136 break; 12137 if (((total % 256) == 0) && 12138#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12139 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12140#else 12141 (xmlXPathCmpNodes(*first, cur) >= 0)) 12142#endif 12143 { 12144 break; 12145 } 12146 } 12147 if ((last != NULL) && (*last != NULL)) { 12148 if (*last == cur) 12149 break; 12150 if (((total % 256) == 0) && 12151#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12152 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12153#else 12154 (xmlXPathCmpNodes(cur, *last) >= 0)) 12155#endif 12156 { 12157 break; 12158 } 12159 } 12160 12161 total++; 12162 12163#ifdef DEBUG_STEP 12164 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12165#endif 12166 switch (test) { 12167 case NODE_TEST_NONE: 12168 total = 0; 12169 STRANGE 12170 goto error; 12171 case NODE_TEST_TYPE: 12172 /* 12173 * TODO: Don't we need to use 12174 * xmlXPathNodeSetAddNs() for namespace nodes here? 12175 * Surprisingly, some c14n tests fail, if we do this. 12176 */ 12177 if (type == NODE_TYPE_NODE) { 12178 switch (cur->type) { 12179 case XML_DOCUMENT_NODE: 12180 case XML_HTML_DOCUMENT_NODE: 12181#ifdef LIBXML_DOCB_ENABLED 12182 case XML_DOCB_DOCUMENT_NODE: 12183#endif 12184 case XML_ELEMENT_NODE: 12185 case XML_ATTRIBUTE_NODE: 12186 case XML_PI_NODE: 12187 case XML_COMMENT_NODE: 12188 case XML_CDATA_SECTION_NODE: 12189 case XML_TEXT_NODE: 12190 case XML_NAMESPACE_DECL: 12191 XP_TEST_HIT 12192 break; 12193 default: 12194 break; 12195 } 12196 } else if (cur->type == type) { 12197 if (type == XML_NAMESPACE_DECL) 12198 XP_TEST_HIT_NS 12199 else 12200 XP_TEST_HIT 12201 } else if ((type == NODE_TYPE_TEXT) && 12202 (cur->type == XML_CDATA_SECTION_NODE)) 12203 { 12204 XP_TEST_HIT 12205 } 12206 break; 12207 case NODE_TEST_PI: 12208 if ((cur->type == XML_PI_NODE) && 12209 ((name == NULL) || xmlStrEqual(name, cur->name))) 12210 { 12211 XP_TEST_HIT 12212 } 12213 break; 12214 case NODE_TEST_ALL: 12215 if (axis == AXIS_ATTRIBUTE) { 12216 if (cur->type == XML_ATTRIBUTE_NODE) 12217 { 12218 XP_TEST_HIT 12219 } 12220 } else if (axis == AXIS_NAMESPACE) { 12221 if (cur->type == XML_NAMESPACE_DECL) 12222 { 12223 XP_TEST_HIT_NS 12224 } 12225 } else { 12226 if (cur->type == XML_ELEMENT_NODE) { 12227 if (prefix == NULL) 12228 { 12229 XP_TEST_HIT 12230 12231 } else if ((cur->ns != NULL) && 12232 (xmlStrEqual(URI, cur->ns->href))) 12233 { 12234 XP_TEST_HIT 12235 } 12236 } 12237 } 12238 break; 12239 case NODE_TEST_NS:{ 12240 TODO; 12241 break; 12242 } 12243 case NODE_TEST_NAME: 12244 switch (cur->type) { 12245 case XML_ELEMENT_NODE: 12246 if (xmlStrEqual(name, cur->name)) { 12247 if (prefix == NULL) { 12248 if (cur->ns == NULL) 12249 { 12250 XP_TEST_HIT 12251 } 12252 } else { 12253 if ((cur->ns != NULL) && 12254 (xmlStrEqual(URI, cur->ns->href))) 12255 { 12256 XP_TEST_HIT 12257 } 12258 } 12259 } 12260 break; 12261 case XML_ATTRIBUTE_NODE:{ 12262 xmlAttrPtr attr = (xmlAttrPtr) cur; 12263 12264 if (xmlStrEqual(name, attr->name)) { 12265 if (prefix == NULL) { 12266 if ((attr->ns == NULL) || 12267 (attr->ns->prefix == NULL)) 12268 { 12269 XP_TEST_HIT 12270 } 12271 } else { 12272 if ((attr->ns != NULL) && 12273 (xmlStrEqual(URI, 12274 attr->ns->href))) 12275 { 12276 XP_TEST_HIT 12277 } 12278 } 12279 } 12280 break; 12281 } 12282 case XML_NAMESPACE_DECL: 12283 if (cur->type == XML_NAMESPACE_DECL) { 12284 xmlNsPtr ns = (xmlNsPtr) cur; 12285 12286 if ((ns->prefix != NULL) && (name != NULL) 12287 && (xmlStrEqual(ns->prefix, name))) 12288 { 12289 XP_TEST_HIT_NS 12290 } 12291 } 12292 break; 12293 default: 12294 break; 12295 } 12296 break; 12297 } /* switch(test) */ 12298 } while (cur != NULL); 12299 12300 goto apply_predicates; 12301 12302axis_range_end: /* ----------------------------------------------------- */ 12303 /* 12304 * We have a "/foo[n]", and position() = n was reached. 12305 * Note that we can have as well "/foo/::parent::foo[1]", so 12306 * a duplicate-aware merge is still needed. 12307 * Merge with the result. 12308 */ 12309 if (outSeq == NULL) { 12310 outSeq = seq; 12311 seq = NULL; 12312 } else 12313 outSeq = mergeAndClear(outSeq, seq, 0); 12314 /* 12315 * Break if only a true/false result was requested. 12316 */ 12317 if (toBool) 12318 break; 12319 continue; 12320 12321first_hit: /* ---------------------------------------------------------- */ 12322 /* 12323 * Break if only a true/false result was requested and 12324 * no predicates existed and a node test succeeded. 12325 */ 12326 if (outSeq == NULL) { 12327 outSeq = seq; 12328 seq = NULL; 12329 } else 12330 outSeq = mergeAndClear(outSeq, seq, 0); 12331 break; 12332 12333#ifdef DEBUG_STEP 12334 if (seq != NULL) 12335 nbMatches += seq->nodeNr; 12336#endif 12337 12338apply_predicates: /* --------------------------------------------------- */ 12339 /* 12340 * Apply predicates. 12341 */ 12342 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12343 /* 12344 * E.g. when we have a "/foo[some expression][n]". 12345 */ 12346 /* 12347 * QUESTION TODO: The old predicate evaluation took into 12348 * account location-sets. 12349 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12350 * Do we expect such a set here? 12351 * All what I learned now from the evaluation semantics 12352 * does not indicate that a location-set will be processed 12353 * here, so this looks OK. 12354 */ 12355 /* 12356 * Iterate over all predicates, starting with the outermost 12357 * predicate. 12358 * TODO: Problem: we cannot execute the inner predicates first 12359 * since we cannot go back *up* the operator tree! 12360 * Options we have: 12361 * 1) Use of recursive functions (like is it currently done 12362 * via xmlXPathCompOpEval()) 12363 * 2) Add a predicate evaluation information stack to the 12364 * context struct 12365 * 3) Change the way the operators are linked; we need a 12366 * "parent" field on xmlXPathStepOp 12367 * 12368 * For the moment, I'll try to solve this with a recursive 12369 * function: xmlXPathCompOpEvalPredicate(). 12370 */ 12371 size = seq->nodeNr; 12372 if (hasPredicateRange != 0) 12373 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt, 12374 predOp, seq, size, maxPos, maxPos, hasNsNodes); 12375 else 12376 newSize = xmlXPathCompOpEvalPredicate(ctxt, 12377 predOp, seq, size, hasNsNodes); 12378 12379 if (ctxt->error != XPATH_EXPRESSION_OK) { 12380 total = 0; 12381 goto error; 12382 } 12383 /* 12384 * Add the filtered set of nodes to the result node set. 12385 */ 12386 if (newSize == 0) { 12387 /* 12388 * The predicates filtered all nodes out. 12389 */ 12390 xmlXPathNodeSetClear(seq, hasNsNodes); 12391 } else if (seq->nodeNr > 0) { 12392 /* 12393 * Add to result set. 12394 */ 12395 if (outSeq == NULL) { 12396 if (size != newSize) { 12397 /* 12398 * We need to merge and clear here, since 12399 * the sequence will contained NULLed entries. 12400 */ 12401 outSeq = mergeAndClear(NULL, seq, 1); 12402 } else { 12403 outSeq = seq; 12404 seq = NULL; 12405 } 12406 } else 12407 outSeq = mergeAndClear(outSeq, seq, 12408 (size != newSize) ? 1: 0); 12409 /* 12410 * Break if only a true/false result was requested. 12411 */ 12412 if (toBool) 12413 break; 12414 } 12415 } else if (seq->nodeNr > 0) { 12416 /* 12417 * Add to result set. 12418 */ 12419 if (outSeq == NULL) { 12420 outSeq = seq; 12421 seq = NULL; 12422 } else { 12423 outSeq = mergeAndClear(outSeq, seq, 0); 12424 } 12425 } 12426 } 12427 12428error: 12429 if ((obj->boolval) && (obj->user != NULL)) { 12430 /* 12431 * QUESTION TODO: What does this do and why? 12432 * TODO: Do we have to do this also for the "error" 12433 * cleanup further down? 12434 */ 12435 ctxt->value->boolval = 1; 12436 ctxt->value->user = obj->user; 12437 obj->user = NULL; 12438 obj->boolval = 0; 12439 } 12440 xmlXPathReleaseObject(xpctxt, obj); 12441 12442 /* 12443 * Ensure we return at least an emtpy set. 12444 */ 12445 if (outSeq == NULL) { 12446 if ((seq != NULL) && (seq->nodeNr == 0)) 12447 outSeq = seq; 12448 else 12449 outSeq = xmlXPathNodeSetCreate(NULL); 12450 } 12451 if ((seq != NULL) && (seq != outSeq)) { 12452 xmlXPathFreeNodeSet(seq); 12453 } 12454 /* 12455 * Hand over the result. Better to push the set also in 12456 * case of errors. 12457 */ 12458 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12459 /* 12460 * Reset the context node. 12461 */ 12462 xpctxt->node = oldContextNode; 12463 12464#ifdef DEBUG_STEP 12465 xmlGenericError(xmlGenericErrorContext, 12466 "\nExamined %d nodes, found %d nodes at that step\n", 12467 total, nbMatches); 12468#endif 12469 12470 return(total); 12471} 12472 12473static int 12474xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12475 xmlXPathStepOpPtr op, xmlNodePtr * first); 12476 12477/** 12478 * xmlXPathCompOpEvalFirst: 12479 * @ctxt: the XPath parser context with the compiled expression 12480 * @op: an XPath compiled operation 12481 * @first: the first elem found so far 12482 * 12483 * Evaluate the Precompiled XPath operation searching only the first 12484 * element in document order 12485 * 12486 * Returns the number of examined objects. 12487 */ 12488static int 12489xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12490 xmlXPathStepOpPtr op, xmlNodePtr * first) 12491{ 12492 int total = 0, cur; 12493 xmlXPathCompExprPtr comp; 12494 xmlXPathObjectPtr arg1, arg2; 12495 12496 CHECK_ERROR0; 12497 comp = ctxt->comp; 12498 switch (op->op) { 12499 case XPATH_OP_END: 12500 return (0); 12501 case XPATH_OP_UNION: 12502 total = 12503 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12504 first); 12505 CHECK_ERROR0; 12506 if ((ctxt->value != NULL) 12507 && (ctxt->value->type == XPATH_NODESET) 12508 && (ctxt->value->nodesetval != NULL) 12509 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12510 /* 12511 * limit tree traversing to first node in the result 12512 */ 12513 /* 12514 * OPTIMIZE TODO: This implicitely sorts 12515 * the result, even if not needed. E.g. if the argument 12516 * of the count() function, no sorting is needed. 12517 * OPTIMIZE TODO: How do we know if the node-list wasn't 12518 * aready sorted? 12519 */ 12520 if (ctxt->value->nodesetval->nodeNr > 1) 12521 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12522 *first = ctxt->value->nodesetval->nodeTab[0]; 12523 } 12524 cur = 12525 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12526 first); 12527 CHECK_ERROR0; 12528 CHECK_TYPE0(XPATH_NODESET); 12529 arg2 = valuePop(ctxt); 12530 12531 CHECK_TYPE0(XPATH_NODESET); 12532 arg1 = valuePop(ctxt); 12533 12534 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12535 arg2->nodesetval); 12536 valuePush(ctxt, arg1); 12537 xmlXPathReleaseObject(ctxt->context, arg2); 12538 /* optimizer */ 12539 if (total > cur) 12540 xmlXPathCompSwap(op); 12541 return (total + cur); 12542 case XPATH_OP_ROOT: 12543 xmlXPathRoot(ctxt); 12544 return (0); 12545 case XPATH_OP_NODE: 12546 if (op->ch1 != -1) 12547 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12548 CHECK_ERROR0; 12549 if (op->ch2 != -1) 12550 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12551 CHECK_ERROR0; 12552 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12553 ctxt->context->node)); 12554 return (total); 12555 case XPATH_OP_RESET: 12556 if (op->ch1 != -1) 12557 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12558 CHECK_ERROR0; 12559 if (op->ch2 != -1) 12560 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12561 CHECK_ERROR0; 12562 ctxt->context->node = NULL; 12563 return (total); 12564 case XPATH_OP_COLLECT:{ 12565 if (op->ch1 == -1) 12566 return (total); 12567 12568 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12569 CHECK_ERROR0; 12570 12571 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12572 return (total); 12573 } 12574 case XPATH_OP_VALUE: 12575 valuePush(ctxt, 12576 xmlXPathCacheObjectCopy(ctxt->context, 12577 (xmlXPathObjectPtr) op->value4)); 12578 return (0); 12579 case XPATH_OP_SORT: 12580 if (op->ch1 != -1) 12581 total += 12582 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12583 first); 12584 CHECK_ERROR0; 12585 if ((ctxt->value != NULL) 12586 && (ctxt->value->type == XPATH_NODESET) 12587 && (ctxt->value->nodesetval != NULL) 12588 && (ctxt->value->nodesetval->nodeNr > 1)) 12589 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12590 return (total); 12591#ifdef XP_OPTIMIZED_FILTER_FIRST 12592 case XPATH_OP_FILTER: 12593 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12594 return (total); 12595#endif 12596 default: 12597 return (xmlXPathCompOpEval(ctxt, op)); 12598 } 12599} 12600 12601/** 12602 * xmlXPathCompOpEvalLast: 12603 * @ctxt: the XPath parser context with the compiled expression 12604 * @op: an XPath compiled operation 12605 * @last: the last elem found so far 12606 * 12607 * Evaluate the Precompiled XPath operation searching only the last 12608 * element in document order 12609 * 12610 * Returns the number of nodes traversed 12611 */ 12612static int 12613xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12614 xmlNodePtr * last) 12615{ 12616 int total = 0, cur; 12617 xmlXPathCompExprPtr comp; 12618 xmlXPathObjectPtr arg1, arg2; 12619 xmlNodePtr bak; 12620 xmlDocPtr bakd; 12621 int pp; 12622 int cs; 12623 12624 CHECK_ERROR0; 12625 comp = ctxt->comp; 12626 switch (op->op) { 12627 case XPATH_OP_END: 12628 return (0); 12629 case XPATH_OP_UNION: 12630 bakd = ctxt->context->doc; 12631 bak = ctxt->context->node; 12632 pp = ctxt->context->proximityPosition; 12633 cs = ctxt->context->contextSize; 12634 total = 12635 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12636 CHECK_ERROR0; 12637 if ((ctxt->value != NULL) 12638 && (ctxt->value->type == XPATH_NODESET) 12639 && (ctxt->value->nodesetval != NULL) 12640 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12641 /* 12642 * limit tree traversing to first node in the result 12643 */ 12644 if (ctxt->value->nodesetval->nodeNr > 1) 12645 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12646 *last = 12647 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12648 nodesetval->nodeNr - 12649 1]; 12650 } 12651 ctxt->context->doc = bakd; 12652 ctxt->context->node = bak; 12653 ctxt->context->proximityPosition = pp; 12654 ctxt->context->contextSize = cs; 12655 cur = 12656 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12657 CHECK_ERROR0; 12658 if ((ctxt->value != NULL) 12659 && (ctxt->value->type == XPATH_NODESET) 12660 && (ctxt->value->nodesetval != NULL) 12661 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12662 } 12663 CHECK_TYPE0(XPATH_NODESET); 12664 arg2 = valuePop(ctxt); 12665 12666 CHECK_TYPE0(XPATH_NODESET); 12667 arg1 = valuePop(ctxt); 12668 12669 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12670 arg2->nodesetval); 12671 valuePush(ctxt, arg1); 12672 xmlXPathReleaseObject(ctxt->context, arg2); 12673 /* optimizer */ 12674 if (total > cur) 12675 xmlXPathCompSwap(op); 12676 return (total + cur); 12677 case XPATH_OP_ROOT: 12678 xmlXPathRoot(ctxt); 12679 return (0); 12680 case XPATH_OP_NODE: 12681 if (op->ch1 != -1) 12682 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12683 CHECK_ERROR0; 12684 if (op->ch2 != -1) 12685 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12686 CHECK_ERROR0; 12687 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12688 ctxt->context->node)); 12689 return (total); 12690 case XPATH_OP_RESET: 12691 if (op->ch1 != -1) 12692 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12693 CHECK_ERROR0; 12694 if (op->ch2 != -1) 12695 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12696 CHECK_ERROR0; 12697 ctxt->context->node = NULL; 12698 return (total); 12699 case XPATH_OP_COLLECT:{ 12700 if (op->ch1 == -1) 12701 return (0); 12702 12703 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12704 CHECK_ERROR0; 12705 12706 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12707 return (total); 12708 } 12709 case XPATH_OP_VALUE: 12710 valuePush(ctxt, 12711 xmlXPathCacheObjectCopy(ctxt->context, 12712 (xmlXPathObjectPtr) op->value4)); 12713 return (0); 12714 case XPATH_OP_SORT: 12715 if (op->ch1 != -1) 12716 total += 12717 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12718 last); 12719 CHECK_ERROR0; 12720 if ((ctxt->value != NULL) 12721 && (ctxt->value->type == XPATH_NODESET) 12722 && (ctxt->value->nodesetval != NULL) 12723 && (ctxt->value->nodesetval->nodeNr > 1)) 12724 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12725 return (total); 12726 default: 12727 return (xmlXPathCompOpEval(ctxt, op)); 12728 } 12729} 12730 12731#ifdef XP_OPTIMIZED_FILTER_FIRST 12732static int 12733xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12734 xmlXPathStepOpPtr op, xmlNodePtr * first) 12735{ 12736 int total = 0; 12737 xmlXPathCompExprPtr comp; 12738 xmlXPathObjectPtr res; 12739 xmlXPathObjectPtr obj; 12740 xmlNodeSetPtr oldset; 12741 xmlNodePtr oldnode; 12742 xmlDocPtr oldDoc; 12743 int i; 12744 12745 CHECK_ERROR0; 12746 comp = ctxt->comp; 12747 /* 12748 * Optimization for ()[last()] selection i.e. the last elem 12749 */ 12750 if ((op->ch1 != -1) && (op->ch2 != -1) && 12751 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12752 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12753 int f = comp->steps[op->ch2].ch1; 12754 12755 if ((f != -1) && 12756 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12757 (comp->steps[f].value5 == NULL) && 12758 (comp->steps[f].value == 0) && 12759 (comp->steps[f].value4 != NULL) && 12760 (xmlStrEqual 12761 (comp->steps[f].value4, BAD_CAST "last"))) { 12762 xmlNodePtr last = NULL; 12763 12764 total += 12765 xmlXPathCompOpEvalLast(ctxt, 12766 &comp->steps[op->ch1], 12767 &last); 12768 CHECK_ERROR0; 12769 /* 12770 * The nodeset should be in document order, 12771 * Keep only the last value 12772 */ 12773 if ((ctxt->value != NULL) && 12774 (ctxt->value->type == XPATH_NODESET) && 12775 (ctxt->value->nodesetval != NULL) && 12776 (ctxt->value->nodesetval->nodeTab != NULL) && 12777 (ctxt->value->nodesetval->nodeNr > 1)) { 12778 ctxt->value->nodesetval->nodeTab[0] = 12779 ctxt->value->nodesetval->nodeTab[ctxt-> 12780 value-> 12781 nodesetval-> 12782 nodeNr - 12783 1]; 12784 ctxt->value->nodesetval->nodeNr = 1; 12785 *first = *(ctxt->value->nodesetval->nodeTab); 12786 } 12787 return (total); 12788 } 12789 } 12790 12791 if (op->ch1 != -1) 12792 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12793 CHECK_ERROR0; 12794 if (op->ch2 == -1) 12795 return (total); 12796 if (ctxt->value == NULL) 12797 return (total); 12798 12799#ifdef LIBXML_XPTR_ENABLED 12800 oldnode = ctxt->context->node; 12801 /* 12802 * Hum are we filtering the result of an XPointer expression 12803 */ 12804 if (ctxt->value->type == XPATH_LOCATIONSET) { 12805 xmlXPathObjectPtr tmp = NULL; 12806 xmlLocationSetPtr newlocset = NULL; 12807 xmlLocationSetPtr oldlocset; 12808 12809 /* 12810 * Extract the old locset, and then evaluate the result of the 12811 * expression for all the element in the locset. use it to grow 12812 * up a new locset. 12813 */ 12814 CHECK_TYPE0(XPATH_LOCATIONSET); 12815 obj = valuePop(ctxt); 12816 oldlocset = obj->user; 12817 ctxt->context->node = NULL; 12818 12819 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 12820 ctxt->context->contextSize = 0; 12821 ctxt->context->proximityPosition = 0; 12822 if (op->ch2 != -1) 12823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12824 res = valuePop(ctxt); 12825 if (res != NULL) { 12826 xmlXPathReleaseObject(ctxt->context, res); 12827 } 12828 valuePush(ctxt, obj); 12829 CHECK_ERROR0; 12830 return (total); 12831 } 12832 newlocset = xmlXPtrLocationSetCreate(NULL); 12833 12834 for (i = 0; i < oldlocset->locNr; i++) { 12835 /* 12836 * Run the evaluation with a node list made of a 12837 * single item in the nodelocset. 12838 */ 12839 ctxt->context->node = oldlocset->locTab[i]->user; 12840 ctxt->context->contextSize = oldlocset->locNr; 12841 ctxt->context->proximityPosition = i + 1; 12842 if (tmp == NULL) { 12843 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 12844 ctxt->context->node); 12845 } else { 12846 xmlXPathNodeSetAddUnique(tmp->nodesetval, 12847 ctxt->context->node); 12848 } 12849 valuePush(ctxt, tmp); 12850 if (op->ch2 != -1) 12851 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12852 if (ctxt->error != XPATH_EXPRESSION_OK) { 12853 xmlXPathFreeObject(obj); 12854 return(0); 12855 } 12856 /* 12857 * The result of the evaluation need to be tested to 12858 * decided whether the filter succeeded or not 12859 */ 12860 res = valuePop(ctxt); 12861 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 12862 xmlXPtrLocationSetAdd(newlocset, 12863 xmlXPathCacheObjectCopy(ctxt->context, 12864 oldlocset->locTab[i])); 12865 } 12866 /* 12867 * Cleanup 12868 */ 12869 if (res != NULL) { 12870 xmlXPathReleaseObject(ctxt->context, res); 12871 } 12872 if (ctxt->value == tmp) { 12873 valuePop(ctxt); 12874 xmlXPathNodeSetClear(tmp->nodesetval, 1); 12875 /* 12876 * REVISIT TODO: Don't create a temporary nodeset 12877 * for everly iteration. 12878 */ 12879 /* OLD: xmlXPathFreeObject(res); */ 12880 } else 12881 tmp = NULL; 12882 ctxt->context->node = NULL; 12883 /* 12884 * Only put the first node in the result, then leave. 12885 */ 12886 if (newlocset->locNr > 0) { 12887 *first = (xmlNodePtr) oldlocset->locTab[i]->user; 12888 break; 12889 } 12890 } 12891 if (tmp != NULL) { 12892 xmlXPathReleaseObject(ctxt->context, tmp); 12893 } 12894 /* 12895 * The result is used as the new evaluation locset. 12896 */ 12897 xmlXPathReleaseObject(ctxt->context, obj); 12898 ctxt->context->node = NULL; 12899 ctxt->context->contextSize = -1; 12900 ctxt->context->proximityPosition = -1; 12901 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 12902 ctxt->context->node = oldnode; 12903 return (total); 12904 } 12905#endif /* LIBXML_XPTR_ENABLED */ 12906 12907 /* 12908 * Extract the old set, and then evaluate the result of the 12909 * expression for all the element in the set. use it to grow 12910 * up a new set. 12911 */ 12912 CHECK_TYPE0(XPATH_NODESET); 12913 obj = valuePop(ctxt); 12914 oldset = obj->nodesetval; 12915 12916 oldnode = ctxt->context->node; 12917 oldDoc = ctxt->context->doc; 12918 ctxt->context->node = NULL; 12919 12920 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 12921 ctxt->context->contextSize = 0; 12922 ctxt->context->proximityPosition = 0; 12923 /* QUESTION TODO: Why was this code commented out? 12924 if (op->ch2 != -1) 12925 total += 12926 xmlXPathCompOpEval(ctxt, 12927 &comp->steps[op->ch2]); 12928 CHECK_ERROR0; 12929 res = valuePop(ctxt); 12930 if (res != NULL) 12931 xmlXPathFreeObject(res); 12932 */ 12933 valuePush(ctxt, obj); 12934 ctxt->context->node = oldnode; 12935 CHECK_ERROR0; 12936 } else { 12937 xmlNodeSetPtr newset; 12938 xmlXPathObjectPtr tmp = NULL; 12939 /* 12940 * Initialize the new set. 12941 * Also set the xpath document in case things like 12942 * key() evaluation are attempted on the predicate 12943 */ 12944 newset = xmlXPathNodeSetCreate(NULL); 12945 12946 for (i = 0; i < oldset->nodeNr; i++) { 12947 /* 12948 * Run the evaluation with a node list made of 12949 * a single item in the nodeset. 12950 */ 12951 ctxt->context->node = oldset->nodeTab[i]; 12952 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 12953 (oldset->nodeTab[i]->doc != NULL)) 12954 ctxt->context->doc = oldset->nodeTab[i]->doc; 12955 if (tmp == NULL) { 12956 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 12957 ctxt->context->node); 12958 } else { 12959 xmlXPathNodeSetAddUnique(tmp->nodesetval, 12960 ctxt->context->node); 12961 } 12962 valuePush(ctxt, tmp); 12963 ctxt->context->contextSize = oldset->nodeNr; 12964 ctxt->context->proximityPosition = i + 1; 12965 if (op->ch2 != -1) 12966 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12967 if (ctxt->error != XPATH_EXPRESSION_OK) { 12968 xmlXPathFreeNodeSet(newset); 12969 xmlXPathFreeObject(obj); 12970 return(0); 12971 } 12972 /* 12973 * The result of the evaluation needs to be tested to 12974 * decide whether the filter succeeded or not 12975 */ 12976 res = valuePop(ctxt); 12977 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 12978 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 12979 } 12980 /* 12981 * Cleanup 12982 */ 12983 if (res != NULL) { 12984 xmlXPathReleaseObject(ctxt->context, res); 12985 } 12986 if (ctxt->value == tmp) { 12987 valuePop(ctxt); 12988 /* 12989 * Don't free the temporary nodeset 12990 * in order to avoid massive recreation inside this 12991 * loop. 12992 */ 12993 xmlXPathNodeSetClear(tmp->nodesetval, 1); 12994 } else 12995 tmp = NULL; 12996 ctxt->context->node = NULL; 12997 /* 12998 * Only put the first node in the result, then leave. 12999 */ 13000 if (newset->nodeNr > 0) { 13001 *first = *(newset->nodeTab); 13002 break; 13003 } 13004 } 13005 if (tmp != NULL) { 13006 xmlXPathReleaseObject(ctxt->context, tmp); 13007 } 13008 /* 13009 * The result is used as the new evaluation set. 13010 */ 13011 xmlXPathReleaseObject(ctxt->context, obj); 13012 ctxt->context->node = NULL; 13013 ctxt->context->contextSize = -1; 13014 ctxt->context->proximityPosition = -1; 13015 /* may want to move this past the '}' later */ 13016 ctxt->context->doc = oldDoc; 13017 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13018 } 13019 ctxt->context->node = oldnode; 13020 return(total); 13021} 13022#endif /* XP_OPTIMIZED_FILTER_FIRST */ 13023 13024/** 13025 * xmlXPathCompOpEval: 13026 * @ctxt: the XPath parser context with the compiled expression 13027 * @op: an XPath compiled operation 13028 * 13029 * Evaluate the Precompiled XPath operation 13030 * Returns the number of nodes traversed 13031 */ 13032static int 13033xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 13034{ 13035 int total = 0; 13036 int equal, ret; 13037 xmlXPathCompExprPtr comp; 13038 xmlXPathObjectPtr arg1, arg2; 13039 xmlNodePtr bak; 13040 xmlDocPtr bakd; 13041 int pp; 13042 int cs; 13043 13044 CHECK_ERROR0; 13045 comp = ctxt->comp; 13046 switch (op->op) { 13047 case XPATH_OP_END: 13048 return (0); 13049 case XPATH_OP_AND: 13050 bakd = ctxt->context->doc; 13051 bak = ctxt->context->node; 13052 pp = ctxt->context->proximityPosition; 13053 cs = ctxt->context->contextSize; 13054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13055 CHECK_ERROR0; 13056 xmlXPathBooleanFunction(ctxt, 1); 13057 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 13058 return (total); 13059 arg2 = valuePop(ctxt); 13060 ctxt->context->doc = bakd; 13061 ctxt->context->node = bak; 13062 ctxt->context->proximityPosition = pp; 13063 ctxt->context->contextSize = cs; 13064 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13065 if (ctxt->error) { 13066 xmlXPathFreeObject(arg2); 13067 return(0); 13068 } 13069 xmlXPathBooleanFunction(ctxt, 1); 13070 arg1 = valuePop(ctxt); 13071 arg1->boolval &= arg2->boolval; 13072 valuePush(ctxt, arg1); 13073 xmlXPathReleaseObject(ctxt->context, arg2); 13074 return (total); 13075 case XPATH_OP_OR: 13076 bakd = ctxt->context->doc; 13077 bak = ctxt->context->node; 13078 pp = ctxt->context->proximityPosition; 13079 cs = ctxt->context->contextSize; 13080 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13081 CHECK_ERROR0; 13082 xmlXPathBooleanFunction(ctxt, 1); 13083 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 13084 return (total); 13085 arg2 = valuePop(ctxt); 13086 ctxt->context->doc = bakd; 13087 ctxt->context->node = bak; 13088 ctxt->context->proximityPosition = pp; 13089 ctxt->context->contextSize = cs; 13090 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13091 if (ctxt->error) { 13092 xmlXPathFreeObject(arg2); 13093 return(0); 13094 } 13095 xmlXPathBooleanFunction(ctxt, 1); 13096 arg1 = valuePop(ctxt); 13097 arg1->boolval |= arg2->boolval; 13098 valuePush(ctxt, arg1); 13099 xmlXPathReleaseObject(ctxt->context, arg2); 13100 return (total); 13101 case XPATH_OP_EQUAL: 13102 bakd = ctxt->context->doc; 13103 bak = ctxt->context->node; 13104 pp = ctxt->context->proximityPosition; 13105 cs = ctxt->context->contextSize; 13106 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13107 CHECK_ERROR0; 13108 ctxt->context->doc = bakd; 13109 ctxt->context->node = bak; 13110 ctxt->context->proximityPosition = pp; 13111 ctxt->context->contextSize = cs; 13112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13113 CHECK_ERROR0; 13114 if (op->value) 13115 equal = xmlXPathEqualValues(ctxt); 13116 else 13117 equal = xmlXPathNotEqualValues(ctxt); 13118 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13119 return (total); 13120 case XPATH_OP_CMP: 13121 bakd = ctxt->context->doc; 13122 bak = ctxt->context->node; 13123 pp = ctxt->context->proximityPosition; 13124 cs = ctxt->context->contextSize; 13125 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13126 CHECK_ERROR0; 13127 ctxt->context->doc = bakd; 13128 ctxt->context->node = bak; 13129 ctxt->context->proximityPosition = pp; 13130 ctxt->context->contextSize = cs; 13131 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13132 CHECK_ERROR0; 13133 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13134 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13135 return (total); 13136 case XPATH_OP_PLUS: 13137 bakd = ctxt->context->doc; 13138 bak = ctxt->context->node; 13139 pp = ctxt->context->proximityPosition; 13140 cs = ctxt->context->contextSize; 13141 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13142 CHECK_ERROR0; 13143 if (op->ch2 != -1) { 13144 ctxt->context->doc = bakd; 13145 ctxt->context->node = bak; 13146 ctxt->context->proximityPosition = pp; 13147 ctxt->context->contextSize = cs; 13148 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13149 } 13150 CHECK_ERROR0; 13151 if (op->value == 0) 13152 xmlXPathSubValues(ctxt); 13153 else if (op->value == 1) 13154 xmlXPathAddValues(ctxt); 13155 else if (op->value == 2) 13156 xmlXPathValueFlipSign(ctxt); 13157 else if (op->value == 3) { 13158 CAST_TO_NUMBER; 13159 CHECK_TYPE0(XPATH_NUMBER); 13160 } 13161 return (total); 13162 case XPATH_OP_MULT: 13163 bakd = ctxt->context->doc; 13164 bak = ctxt->context->node; 13165 pp = ctxt->context->proximityPosition; 13166 cs = ctxt->context->contextSize; 13167 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13168 CHECK_ERROR0; 13169 ctxt->context->doc = bakd; 13170 ctxt->context->node = bak; 13171 ctxt->context->proximityPosition = pp; 13172 ctxt->context->contextSize = cs; 13173 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13174 CHECK_ERROR0; 13175 if (op->value == 0) 13176 xmlXPathMultValues(ctxt); 13177 else if (op->value == 1) 13178 xmlXPathDivValues(ctxt); 13179 else if (op->value == 2) 13180 xmlXPathModValues(ctxt); 13181 return (total); 13182 case XPATH_OP_UNION: 13183 bakd = ctxt->context->doc; 13184 bak = ctxt->context->node; 13185 pp = ctxt->context->proximityPosition; 13186 cs = ctxt->context->contextSize; 13187 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13188 CHECK_ERROR0; 13189 ctxt->context->doc = bakd; 13190 ctxt->context->node = bak; 13191 ctxt->context->proximityPosition = pp; 13192 ctxt->context->contextSize = cs; 13193 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13194 CHECK_ERROR0; 13195 CHECK_TYPE0(XPATH_NODESET); 13196 arg2 = valuePop(ctxt); 13197 13198 CHECK_TYPE0(XPATH_NODESET); 13199 arg1 = valuePop(ctxt); 13200 13201 if ((arg1->nodesetval == NULL) || 13202 ((arg2->nodesetval != NULL) && 13203 (arg2->nodesetval->nodeNr != 0))) 13204 { 13205 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13206 arg2->nodesetval); 13207 } 13208 13209 valuePush(ctxt, arg1); 13210 xmlXPathReleaseObject(ctxt->context, arg2); 13211 return (total); 13212 case XPATH_OP_ROOT: 13213 xmlXPathRoot(ctxt); 13214 return (total); 13215 case XPATH_OP_NODE: 13216 if (op->ch1 != -1) 13217 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13218 CHECK_ERROR0; 13219 if (op->ch2 != -1) 13220 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13221 CHECK_ERROR0; 13222 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13223 ctxt->context->node)); 13224 return (total); 13225 case XPATH_OP_RESET: 13226 if (op->ch1 != -1) 13227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13228 CHECK_ERROR0; 13229 if (op->ch2 != -1) 13230 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13231 CHECK_ERROR0; 13232 ctxt->context->node = NULL; 13233 return (total); 13234 case XPATH_OP_COLLECT:{ 13235 if (op->ch1 == -1) 13236 return (total); 13237 13238 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13239 CHECK_ERROR0; 13240 13241 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13242 return (total); 13243 } 13244 case XPATH_OP_VALUE: 13245 valuePush(ctxt, 13246 xmlXPathCacheObjectCopy(ctxt->context, 13247 (xmlXPathObjectPtr) op->value4)); 13248 return (total); 13249 case XPATH_OP_VARIABLE:{ 13250 xmlXPathObjectPtr val; 13251 13252 if (op->ch1 != -1) 13253 total += 13254 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13255 if (op->value5 == NULL) { 13256 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13257 if (val == NULL) { 13258 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13259 return(0); 13260 } 13261 valuePush(ctxt, val); 13262 } else { 13263 const xmlChar *URI; 13264 13265 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13266 if (URI == NULL) { 13267 xmlGenericError(xmlGenericErrorContext, 13268 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13269 op->value4, op->value5); 13270 return (total); 13271 } 13272 val = xmlXPathVariableLookupNS(ctxt->context, 13273 op->value4, URI); 13274 if (val == NULL) { 13275 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13276 return(0); 13277 } 13278 valuePush(ctxt, val); 13279 } 13280 return (total); 13281 } 13282 case XPATH_OP_FUNCTION:{ 13283 xmlXPathFunction func; 13284 const xmlChar *oldFunc, *oldFuncURI; 13285 int i; 13286 13287 if (op->ch1 != -1) 13288 total += 13289 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13290 if (ctxt->valueNr < op->value) { 13291 xmlGenericError(xmlGenericErrorContext, 13292 "xmlXPathCompOpEval: parameter error\n"); 13293 ctxt->error = XPATH_INVALID_OPERAND; 13294 return (total); 13295 } 13296 for (i = 0; i < op->value; i++) 13297 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13298 xmlGenericError(xmlGenericErrorContext, 13299 "xmlXPathCompOpEval: parameter error\n"); 13300 ctxt->error = XPATH_INVALID_OPERAND; 13301 return (total); 13302 } 13303 if (op->cache != NULL) 13304 XML_CAST_FPTR(func) = op->cache; 13305 else { 13306 const xmlChar *URI = NULL; 13307 13308 if (op->value5 == NULL) 13309 func = 13310 xmlXPathFunctionLookup(ctxt->context, 13311 op->value4); 13312 else { 13313 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13314 if (URI == NULL) { 13315 xmlGenericError(xmlGenericErrorContext, 13316 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13317 op->value4, op->value5); 13318 return (total); 13319 } 13320 func = xmlXPathFunctionLookupNS(ctxt->context, 13321 op->value4, URI); 13322 } 13323 if (func == NULL) { 13324 xmlGenericError(xmlGenericErrorContext, 13325 "xmlXPathCompOpEval: function %s not found\n", 13326 op->value4); 13327 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13328 } 13329 op->cache = XML_CAST_FPTR(func); 13330 op->cacheURI = (void *) URI; 13331 } 13332 oldFunc = ctxt->context->function; 13333 oldFuncURI = ctxt->context->functionURI; 13334 ctxt->context->function = op->value4; 13335 ctxt->context->functionURI = op->cacheURI; 13336 func(ctxt, op->value); 13337 ctxt->context->function = oldFunc; 13338 ctxt->context->functionURI = oldFuncURI; 13339 return (total); 13340 } 13341 case XPATH_OP_ARG: 13342 bakd = ctxt->context->doc; 13343 bak = ctxt->context->node; 13344 pp = ctxt->context->proximityPosition; 13345 cs = ctxt->context->contextSize; 13346 if (op->ch1 != -1) 13347 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13348 ctxt->context->contextSize = cs; 13349 ctxt->context->proximityPosition = pp; 13350 ctxt->context->node = bak; 13351 ctxt->context->doc = bakd; 13352 CHECK_ERROR0; 13353 if (op->ch2 != -1) { 13354 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13355 ctxt->context->doc = bakd; 13356 ctxt->context->node = bak; 13357 CHECK_ERROR0; 13358 } 13359 return (total); 13360 case XPATH_OP_PREDICATE: 13361 case XPATH_OP_FILTER:{ 13362 xmlXPathObjectPtr res; 13363 xmlXPathObjectPtr obj, tmp; 13364 xmlNodeSetPtr newset = NULL; 13365 xmlNodeSetPtr oldset; 13366 xmlNodePtr oldnode; 13367 xmlDocPtr oldDoc; 13368 int i; 13369 13370 /* 13371 * Optimization for ()[1] selection i.e. the first elem 13372 */ 13373 if ((op->ch1 != -1) && (op->ch2 != -1) && 13374#ifdef XP_OPTIMIZED_FILTER_FIRST 13375 /* 13376 * FILTER TODO: Can we assume that the inner processing 13377 * will result in an ordered list if we have an 13378 * XPATH_OP_FILTER? 13379 * What about an additional field or flag on 13380 * xmlXPathObject like @sorted ? This way we wouln'd need 13381 * to assume anything, so it would be more robust and 13382 * easier to optimize. 13383 */ 13384 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13385 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13386#else 13387 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13388#endif 13389 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13390 xmlXPathObjectPtr val; 13391 13392 val = comp->steps[op->ch2].value4; 13393 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13394 (val->floatval == 1.0)) { 13395 xmlNodePtr first = NULL; 13396 13397 total += 13398 xmlXPathCompOpEvalFirst(ctxt, 13399 &comp->steps[op->ch1], 13400 &first); 13401 CHECK_ERROR0; 13402 /* 13403 * The nodeset should be in document order, 13404 * Keep only the first value 13405 */ 13406 if ((ctxt->value != NULL) && 13407 (ctxt->value->type == XPATH_NODESET) && 13408 (ctxt->value->nodesetval != NULL) && 13409 (ctxt->value->nodesetval->nodeNr > 1)) 13410 ctxt->value->nodesetval->nodeNr = 1; 13411 return (total); 13412 } 13413 } 13414 /* 13415 * Optimization for ()[last()] selection i.e. the last elem 13416 */ 13417 if ((op->ch1 != -1) && (op->ch2 != -1) && 13418 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13419 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13420 int f = comp->steps[op->ch2].ch1; 13421 13422 if ((f != -1) && 13423 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13424 (comp->steps[f].value5 == NULL) && 13425 (comp->steps[f].value == 0) && 13426 (comp->steps[f].value4 != NULL) && 13427 (xmlStrEqual 13428 (comp->steps[f].value4, BAD_CAST "last"))) { 13429 xmlNodePtr last = NULL; 13430 13431 total += 13432 xmlXPathCompOpEvalLast(ctxt, 13433 &comp->steps[op->ch1], 13434 &last); 13435 CHECK_ERROR0; 13436 /* 13437 * The nodeset should be in document order, 13438 * Keep only the last value 13439 */ 13440 if ((ctxt->value != NULL) && 13441 (ctxt->value->type == XPATH_NODESET) && 13442 (ctxt->value->nodesetval != NULL) && 13443 (ctxt->value->nodesetval->nodeTab != NULL) && 13444 (ctxt->value->nodesetval->nodeNr > 1)) { 13445 ctxt->value->nodesetval->nodeTab[0] = 13446 ctxt->value->nodesetval->nodeTab[ctxt-> 13447 value-> 13448 nodesetval-> 13449 nodeNr - 13450 1]; 13451 ctxt->value->nodesetval->nodeNr = 1; 13452 } 13453 return (total); 13454 } 13455 } 13456 /* 13457 * Process inner predicates first. 13458 * Example "index[parent::book][1]": 13459 * ... 13460 * PREDICATE <-- we are here "[1]" 13461 * PREDICATE <-- process "[parent::book]" first 13462 * SORT 13463 * COLLECT 'parent' 'name' 'node' book 13464 * NODE 13465 * ELEM Object is a number : 1 13466 */ 13467 if (op->ch1 != -1) 13468 total += 13469 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13470 CHECK_ERROR0; 13471 if (op->ch2 == -1) 13472 return (total); 13473 if (ctxt->value == NULL) 13474 return (total); 13475 13476 oldnode = ctxt->context->node; 13477 13478#ifdef LIBXML_XPTR_ENABLED 13479 /* 13480 * Hum are we filtering the result of an XPointer expression 13481 */ 13482 if (ctxt->value->type == XPATH_LOCATIONSET) { 13483 xmlLocationSetPtr newlocset = NULL; 13484 xmlLocationSetPtr oldlocset; 13485 13486 /* 13487 * Extract the old locset, and then evaluate the result of the 13488 * expression for all the element in the locset. use it to grow 13489 * up a new locset. 13490 */ 13491 CHECK_TYPE0(XPATH_LOCATIONSET); 13492 obj = valuePop(ctxt); 13493 oldlocset = obj->user; 13494 ctxt->context->node = NULL; 13495 13496 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13497 ctxt->context->contextSize = 0; 13498 ctxt->context->proximityPosition = 0; 13499 if (op->ch2 != -1) 13500 total += 13501 xmlXPathCompOpEval(ctxt, 13502 &comp->steps[op->ch2]); 13503 res = valuePop(ctxt); 13504 if (res != NULL) { 13505 xmlXPathReleaseObject(ctxt->context, res); 13506 } 13507 valuePush(ctxt, obj); 13508 CHECK_ERROR0; 13509 return (total); 13510 } 13511 newlocset = xmlXPtrLocationSetCreate(NULL); 13512 13513 for (i = 0; i < oldlocset->locNr; i++) { 13514 /* 13515 * Run the evaluation with a node list made of a 13516 * single item in the nodelocset. 13517 */ 13518 ctxt->context->node = oldlocset->locTab[i]->user; 13519 ctxt->context->contextSize = oldlocset->locNr; 13520 ctxt->context->proximityPosition = i + 1; 13521 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13522 ctxt->context->node); 13523 valuePush(ctxt, tmp); 13524 13525 if (op->ch2 != -1) 13526 total += 13527 xmlXPathCompOpEval(ctxt, 13528 &comp->steps[op->ch2]); 13529 if (ctxt->error != XPATH_EXPRESSION_OK) { 13530 xmlXPathFreeObject(obj); 13531 return(0); 13532 } 13533 13534 /* 13535 * The result of the evaluation need to be tested to 13536 * decided whether the filter succeeded or not 13537 */ 13538 res = valuePop(ctxt); 13539 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13540 xmlXPtrLocationSetAdd(newlocset, 13541 xmlXPathObjectCopy 13542 (oldlocset->locTab[i])); 13543 } 13544 13545 /* 13546 * Cleanup 13547 */ 13548 if (res != NULL) { 13549 xmlXPathReleaseObject(ctxt->context, res); 13550 } 13551 if (ctxt->value == tmp) { 13552 res = valuePop(ctxt); 13553 xmlXPathReleaseObject(ctxt->context, res); 13554 } 13555 13556 ctxt->context->node = NULL; 13557 } 13558 13559 /* 13560 * The result is used as the new evaluation locset. 13561 */ 13562 xmlXPathReleaseObject(ctxt->context, obj); 13563 ctxt->context->node = NULL; 13564 ctxt->context->contextSize = -1; 13565 ctxt->context->proximityPosition = -1; 13566 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13567 ctxt->context->node = oldnode; 13568 return (total); 13569 } 13570#endif /* LIBXML_XPTR_ENABLED */ 13571 13572 /* 13573 * Extract the old set, and then evaluate the result of the 13574 * expression for all the element in the set. use it to grow 13575 * up a new set. 13576 */ 13577 CHECK_TYPE0(XPATH_NODESET); 13578 obj = valuePop(ctxt); 13579 oldset = obj->nodesetval; 13580 13581 oldnode = ctxt->context->node; 13582 oldDoc = ctxt->context->doc; 13583 ctxt->context->node = NULL; 13584 13585 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13586 ctxt->context->contextSize = 0; 13587 ctxt->context->proximityPosition = 0; 13588/* 13589 if (op->ch2 != -1) 13590 total += 13591 xmlXPathCompOpEval(ctxt, 13592 &comp->steps[op->ch2]); 13593 CHECK_ERROR0; 13594 res = valuePop(ctxt); 13595 if (res != NULL) 13596 xmlXPathFreeObject(res); 13597*/ 13598 valuePush(ctxt, obj); 13599 ctxt->context->node = oldnode; 13600 CHECK_ERROR0; 13601 } else { 13602 tmp = NULL; 13603 /* 13604 * Initialize the new set. 13605 * Also set the xpath document in case things like 13606 * key() evaluation are attempted on the predicate 13607 */ 13608 newset = xmlXPathNodeSetCreate(NULL); 13609 /* 13610 * SPEC XPath 1.0: 13611 * "For each node in the node-set to be filtered, the 13612 * PredicateExpr is evaluated with that node as the 13613 * context node, with the number of nodes in the 13614 * node-set as the context size, and with the proximity 13615 * position of the node in the node-set with respect to 13616 * the axis as the context position;" 13617 * @oldset is the node-set" to be filtered. 13618 * 13619 * SPEC XPath 1.0: 13620 * "only predicates change the context position and 13621 * context size (see [2.4 Predicates])." 13622 * Example: 13623 * node-set context pos 13624 * nA 1 13625 * nB 2 13626 * nC 3 13627 * After applying predicate [position() > 1] : 13628 * node-set context pos 13629 * nB 1 13630 * nC 2 13631 * 13632 * removed the first node in the node-set, then 13633 * the context position of the 13634 */ 13635 for (i = 0; i < oldset->nodeNr; i++) { 13636 /* 13637 * Run the evaluation with a node list made of 13638 * a single item in the nodeset. 13639 */ 13640 ctxt->context->node = oldset->nodeTab[i]; 13641 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13642 (oldset->nodeTab[i]->doc != NULL)) 13643 ctxt->context->doc = oldset->nodeTab[i]->doc; 13644 if (tmp == NULL) { 13645 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13646 ctxt->context->node); 13647 } else { 13648 xmlXPathNodeSetAddUnique(tmp->nodesetval, 13649 ctxt->context->node); 13650 } 13651 valuePush(ctxt, tmp); 13652 ctxt->context->contextSize = oldset->nodeNr; 13653 ctxt->context->proximityPosition = i + 1; 13654 /* 13655 * Evaluate the predicate against the context node. 13656 * Can/should we optimize position() predicates 13657 * here (e.g. "[1]")? 13658 */ 13659 if (op->ch2 != -1) 13660 total += 13661 xmlXPathCompOpEval(ctxt, 13662 &comp->steps[op->ch2]); 13663 if (ctxt->error != XPATH_EXPRESSION_OK) { 13664 xmlXPathFreeNodeSet(newset); 13665 xmlXPathFreeObject(obj); 13666 return(0); 13667 } 13668 13669 /* 13670 * The result of the evaluation needs to be tested to 13671 * decide whether the filter succeeded or not 13672 */ 13673 /* 13674 * OPTIMIZE TODO: Can we use 13675 * xmlXPathNodeSetAdd*Unique()* instead? 13676 */ 13677 res = valuePop(ctxt); 13678 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13679 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 13680 } 13681 13682 /* 13683 * Cleanup 13684 */ 13685 if (res != NULL) { 13686 xmlXPathReleaseObject(ctxt->context, res); 13687 } 13688 if (ctxt->value == tmp) { 13689 valuePop(ctxt); 13690 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13691 /* 13692 * Don't free the temporary nodeset 13693 * in order to avoid massive recreation inside this 13694 * loop. 13695 */ 13696 } else 13697 tmp = NULL; 13698 ctxt->context->node = NULL; 13699 } 13700 if (tmp != NULL) 13701 xmlXPathReleaseObject(ctxt->context, tmp); 13702 /* 13703 * The result is used as the new evaluation set. 13704 */ 13705 xmlXPathReleaseObject(ctxt->context, obj); 13706 ctxt->context->node = NULL; 13707 ctxt->context->contextSize = -1; 13708 ctxt->context->proximityPosition = -1; 13709 /* may want to move this past the '}' later */ 13710 ctxt->context->doc = oldDoc; 13711 valuePush(ctxt, 13712 xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13713 } 13714 ctxt->context->node = oldnode; 13715 return (total); 13716 } 13717 case XPATH_OP_SORT: 13718 if (op->ch1 != -1) 13719 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13720 CHECK_ERROR0; 13721 if ((ctxt->value != NULL) && 13722 (ctxt->value->type == XPATH_NODESET) && 13723 (ctxt->value->nodesetval != NULL) && 13724 (ctxt->value->nodesetval->nodeNr > 1)) 13725 { 13726 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13727 } 13728 return (total); 13729#ifdef LIBXML_XPTR_ENABLED 13730 case XPATH_OP_RANGETO:{ 13731 xmlXPathObjectPtr range; 13732 xmlXPathObjectPtr res, obj; 13733 xmlXPathObjectPtr tmp; 13734 xmlLocationSetPtr newlocset = NULL; 13735 xmlLocationSetPtr oldlocset; 13736 xmlNodeSetPtr oldset; 13737 int i, j; 13738 13739 if (op->ch1 != -1) 13740 total += 13741 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13742 if (op->ch2 == -1) 13743 return (total); 13744 13745 if (ctxt->value->type == XPATH_LOCATIONSET) { 13746 /* 13747 * Extract the old locset, and then evaluate the result of the 13748 * expression for all the element in the locset. use it to grow 13749 * up a new locset. 13750 */ 13751 CHECK_TYPE0(XPATH_LOCATIONSET); 13752 obj = valuePop(ctxt); 13753 oldlocset = obj->user; 13754 13755 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13756 ctxt->context->node = NULL; 13757 ctxt->context->contextSize = 0; 13758 ctxt->context->proximityPosition = 0; 13759 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); 13760 res = valuePop(ctxt); 13761 if (res != NULL) { 13762 xmlXPathReleaseObject(ctxt->context, res); 13763 } 13764 valuePush(ctxt, obj); 13765 CHECK_ERROR0; 13766 return (total); 13767 } 13768 newlocset = xmlXPtrLocationSetCreate(NULL); 13769 13770 for (i = 0; i < oldlocset->locNr; i++) { 13771 /* 13772 * Run the evaluation with a node list made of a 13773 * single item in the nodelocset. 13774 */ 13775 ctxt->context->node = oldlocset->locTab[i]->user; 13776 ctxt->context->contextSize = oldlocset->locNr; 13777 ctxt->context->proximityPosition = i + 1; 13778 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13779 ctxt->context->node); 13780 valuePush(ctxt, tmp); 13781 13782 if (op->ch2 != -1) 13783 total += 13784 xmlXPathCompOpEval(ctxt, 13785 &comp->steps[op->ch2]); 13786 if (ctxt->error != XPATH_EXPRESSION_OK) { 13787 xmlXPathFreeObject(obj); 13788 return(0); 13789 } 13790 13791 res = valuePop(ctxt); 13792 if (res->type == XPATH_LOCATIONSET) { 13793 xmlLocationSetPtr rloc = 13794 (xmlLocationSetPtr)res->user; 13795 for (j=0; j<rloc->locNr; j++) { 13796 range = xmlXPtrNewRange( 13797 oldlocset->locTab[i]->user, 13798 oldlocset->locTab[i]->index, 13799 rloc->locTab[j]->user2, 13800 rloc->locTab[j]->index2); 13801 if (range != NULL) { 13802 xmlXPtrLocationSetAdd(newlocset, range); 13803 } 13804 } 13805 } else { 13806 range = xmlXPtrNewRangeNodeObject( 13807 (xmlNodePtr)oldlocset->locTab[i]->user, res); 13808 if (range != NULL) { 13809 xmlXPtrLocationSetAdd(newlocset,range); 13810 } 13811 } 13812 13813 /* 13814 * Cleanup 13815 */ 13816 if (res != NULL) { 13817 xmlXPathReleaseObject(ctxt->context, res); 13818 } 13819 if (ctxt->value == tmp) { 13820 res = valuePop(ctxt); 13821 xmlXPathReleaseObject(ctxt->context, res); 13822 } 13823 13824 ctxt->context->node = NULL; 13825 } 13826 } else { /* Not a location set */ 13827 CHECK_TYPE0(XPATH_NODESET); 13828 obj = valuePop(ctxt); 13829 oldset = obj->nodesetval; 13830 ctxt->context->node = NULL; 13831 13832 newlocset = xmlXPtrLocationSetCreate(NULL); 13833 13834 if (oldset != NULL) { 13835 for (i = 0; i < oldset->nodeNr; i++) { 13836 /* 13837 * Run the evaluation with a node list made of a single item 13838 * in the nodeset. 13839 */ 13840 ctxt->context->node = oldset->nodeTab[i]; 13841 /* 13842 * OPTIMIZE TODO: Avoid recreation for every iteration. 13843 */ 13844 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13845 ctxt->context->node); 13846 valuePush(ctxt, tmp); 13847 13848 if (op->ch2 != -1) 13849 total += 13850 xmlXPathCompOpEval(ctxt, 13851 &comp->steps[op->ch2]); 13852 if (ctxt->error != XPATH_EXPRESSION_OK) { 13853 xmlXPathFreeObject(obj); 13854 return(0); 13855 } 13856 13857 res = valuePop(ctxt); 13858 range = 13859 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 13860 res); 13861 if (range != NULL) { 13862 xmlXPtrLocationSetAdd(newlocset, range); 13863 } 13864 13865 /* 13866 * Cleanup 13867 */ 13868 if (res != NULL) { 13869 xmlXPathReleaseObject(ctxt->context, res); 13870 } 13871 if (ctxt->value == tmp) { 13872 res = valuePop(ctxt); 13873 xmlXPathReleaseObject(ctxt->context, res); 13874 } 13875 13876 ctxt->context->node = NULL; 13877 } 13878 } 13879 } 13880 13881 /* 13882 * The result is used as the new evaluation set. 13883 */ 13884 xmlXPathReleaseObject(ctxt->context, obj); 13885 ctxt->context->node = NULL; 13886 ctxt->context->contextSize = -1; 13887 ctxt->context->proximityPosition = -1; 13888 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13889 return (total); 13890 } 13891#endif /* LIBXML_XPTR_ENABLED */ 13892 } 13893 xmlGenericError(xmlGenericErrorContext, 13894 "XPath: unknown precompiled operation %d\n", op->op); 13895 return (total); 13896} 13897 13898/** 13899 * xmlXPathCompOpEvalToBoolean: 13900 * @ctxt: the XPath parser context 13901 * 13902 * Evaluates if the expression evaluates to true. 13903 * 13904 * Returns 1 if true, 0 if false and -1 on API or internal errors. 13905 */ 13906static int 13907xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 13908 xmlXPathStepOpPtr op, 13909 int isPredicate) 13910{ 13911 xmlXPathObjectPtr resObj = NULL; 13912 13913start: 13914 /* comp = ctxt->comp; */ 13915 switch (op->op) { 13916 case XPATH_OP_END: 13917 return (0); 13918 case XPATH_OP_VALUE: 13919 resObj = (xmlXPathObjectPtr) op->value4; 13920 if (isPredicate) 13921 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 13922 return(xmlXPathCastToBoolean(resObj)); 13923 case XPATH_OP_SORT: 13924 /* 13925 * We don't need sorting for boolean results. Skip this one. 13926 */ 13927 if (op->ch1 != -1) { 13928 op = &ctxt->comp->steps[op->ch1]; 13929 goto start; 13930 } 13931 return(0); 13932 case XPATH_OP_COLLECT: 13933 if (op->ch1 == -1) 13934 return(0); 13935 13936 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 13937 if (ctxt->error != XPATH_EXPRESSION_OK) 13938 return(-1); 13939 13940 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 13941 if (ctxt->error != XPATH_EXPRESSION_OK) 13942 return(-1); 13943 13944 resObj = valuePop(ctxt); 13945 if (resObj == NULL) 13946 return(-1); 13947 break; 13948 default: 13949 /* 13950 * Fallback to call xmlXPathCompOpEval(). 13951 */ 13952 xmlXPathCompOpEval(ctxt, op); 13953 if (ctxt->error != XPATH_EXPRESSION_OK) 13954 return(-1); 13955 13956 resObj = valuePop(ctxt); 13957 if (resObj == NULL) 13958 return(-1); 13959 break; 13960 } 13961 13962 if (resObj) { 13963 int res; 13964 13965 if (resObj->type == XPATH_BOOLEAN) { 13966 res = resObj->boolval; 13967 } else if (isPredicate) { 13968 /* 13969 * For predicates a result of type "number" is handled 13970 * differently: 13971 * SPEC XPath 1.0: 13972 * "If the result is a number, the result will be converted 13973 * to true if the number is equal to the context position 13974 * and will be converted to false otherwise;" 13975 */ 13976 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 13977 } else { 13978 res = xmlXPathCastToBoolean(resObj); 13979 } 13980 xmlXPathReleaseObject(ctxt->context, resObj); 13981 return(res); 13982 } 13983 13984 return(0); 13985} 13986 13987#ifdef XPATH_STREAMING 13988/** 13989 * xmlXPathRunStreamEval: 13990 * @ctxt: the XPath parser context with the compiled expression 13991 * 13992 * Evaluate the Precompiled Streamable XPath expression in the given context. 13993 */ 13994static int 13995xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 13996 xmlXPathObjectPtr *resultSeq, int toBool) 13997{ 13998 int max_depth, min_depth; 13999 int from_root; 14000 int ret, depth; 14001 int eval_all_nodes; 14002 xmlNodePtr cur = NULL, limit = NULL; 14003 xmlStreamCtxtPtr patstream = NULL; 14004 14005 int nb_nodes = 0; 14006 14007 if ((ctxt == NULL) || (comp == NULL)) 14008 return(-1); 14009 max_depth = xmlPatternMaxDepth(comp); 14010 if (max_depth == -1) 14011 return(-1); 14012 if (max_depth == -2) 14013 max_depth = 10000; 14014 min_depth = xmlPatternMinDepth(comp); 14015 if (min_depth == -1) 14016 return(-1); 14017 from_root = xmlPatternFromRoot(comp); 14018 if (from_root < 0) 14019 return(-1); 14020#if 0 14021 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 14022#endif 14023 14024 if (! toBool) { 14025 if (resultSeq == NULL) 14026 return(-1); 14027 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 14028 if (*resultSeq == NULL) 14029 return(-1); 14030 } 14031 14032 /* 14033 * handle the special cases of "/" amd "." being matched 14034 */ 14035 if (min_depth == 0) { 14036 if (from_root) { 14037 /* Select "/" */ 14038 if (toBool) 14039 return(1); 14040 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 14041 (xmlNodePtr) ctxt->doc); 14042 } else { 14043 /* Select "self::node()" */ 14044 if (toBool) 14045 return(1); 14046 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 14047 } 14048 } 14049 if (max_depth == 0) { 14050 return(0); 14051 } 14052 14053 if (from_root) { 14054 cur = (xmlNodePtr)ctxt->doc; 14055 } else if (ctxt->node != NULL) { 14056 switch (ctxt->node->type) { 14057 case XML_ELEMENT_NODE: 14058 case XML_DOCUMENT_NODE: 14059 case XML_DOCUMENT_FRAG_NODE: 14060 case XML_HTML_DOCUMENT_NODE: 14061#ifdef LIBXML_DOCB_ENABLED 14062 case XML_DOCB_DOCUMENT_NODE: 14063#endif 14064 cur = ctxt->node; 14065 break; 14066 case XML_ATTRIBUTE_NODE: 14067 case XML_TEXT_NODE: 14068 case XML_CDATA_SECTION_NODE: 14069 case XML_ENTITY_REF_NODE: 14070 case XML_ENTITY_NODE: 14071 case XML_PI_NODE: 14072 case XML_COMMENT_NODE: 14073 case XML_NOTATION_NODE: 14074 case XML_DTD_NODE: 14075 case XML_DOCUMENT_TYPE_NODE: 14076 case XML_ELEMENT_DECL: 14077 case XML_ATTRIBUTE_DECL: 14078 case XML_ENTITY_DECL: 14079 case XML_NAMESPACE_DECL: 14080 case XML_XINCLUDE_START: 14081 case XML_XINCLUDE_END: 14082 break; 14083 } 14084 limit = cur; 14085 } 14086 if (cur == NULL) { 14087 return(0); 14088 } 14089 14090 patstream = xmlPatternGetStreamCtxt(comp); 14091 if (patstream == NULL) { 14092 /* 14093 * QUESTION TODO: Is this an error? 14094 */ 14095 return(0); 14096 } 14097 14098 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 14099 14100 if (from_root) { 14101 ret = xmlStreamPush(patstream, NULL, NULL); 14102 if (ret < 0) { 14103 } else if (ret == 1) { 14104 if (toBool) 14105 goto return_1; 14106 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14107 } 14108 } 14109 depth = 0; 14110 goto scan_children; 14111next_node: 14112 do { 14113 nb_nodes++; 14114 14115 switch (cur->type) { 14116 case XML_ELEMENT_NODE: 14117 case XML_TEXT_NODE: 14118 case XML_CDATA_SECTION_NODE: 14119 case XML_COMMENT_NODE: 14120 case XML_PI_NODE: 14121 if (cur->type == XML_ELEMENT_NODE) { 14122 ret = xmlStreamPush(patstream, cur->name, 14123 (cur->ns ? cur->ns->href : NULL)); 14124 } else if (eval_all_nodes) 14125 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 14126 else 14127 break; 14128 14129 if (ret < 0) { 14130 /* NOP. */ 14131 } else if (ret == 1) { 14132 if (toBool) 14133 goto return_1; 14134 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14135 } 14136 if ((cur->children == NULL) || (depth >= max_depth)) { 14137 ret = xmlStreamPop(patstream); 14138 while (cur->next != NULL) { 14139 cur = cur->next; 14140 if ((cur->type != XML_ENTITY_DECL) && 14141 (cur->type != XML_DTD_NODE)) 14142 goto next_node; 14143 } 14144 } 14145 default: 14146 break; 14147 } 14148 14149scan_children: 14150 if ((cur->children != NULL) && (depth < max_depth)) { 14151 /* 14152 * Do not descend on entities declarations 14153 */ 14154 if (cur->children->type != XML_ENTITY_DECL) { 14155 cur = cur->children; 14156 depth++; 14157 /* 14158 * Skip DTDs 14159 */ 14160 if (cur->type != XML_DTD_NODE) 14161 continue; 14162 } 14163 } 14164 14165 if (cur == limit) 14166 break; 14167 14168 while (cur->next != NULL) { 14169 cur = cur->next; 14170 if ((cur->type != XML_ENTITY_DECL) && 14171 (cur->type != XML_DTD_NODE)) 14172 goto next_node; 14173 } 14174 14175 do { 14176 cur = cur->parent; 14177 depth--; 14178 if ((cur == NULL) || (cur == limit)) 14179 goto done; 14180 if (cur->type == XML_ELEMENT_NODE) { 14181 ret = xmlStreamPop(patstream); 14182 } else if ((eval_all_nodes) && 14183 ((cur->type == XML_TEXT_NODE) || 14184 (cur->type == XML_CDATA_SECTION_NODE) || 14185 (cur->type == XML_COMMENT_NODE) || 14186 (cur->type == XML_PI_NODE))) 14187 { 14188 ret = xmlStreamPop(patstream); 14189 } 14190 if (cur->next != NULL) { 14191 cur = cur->next; 14192 break; 14193 } 14194 } while (cur != NULL); 14195 14196 } while ((cur != NULL) && (depth >= 0)); 14197 14198done: 14199 14200#if 0 14201 printf("stream eval: checked %d nodes selected %d\n", 14202 nb_nodes, retObj->nodesetval->nodeNr); 14203#endif 14204 14205 if (patstream) 14206 xmlFreeStreamCtxt(patstream); 14207 return(0); 14208 14209return_1: 14210 if (patstream) 14211 xmlFreeStreamCtxt(patstream); 14212 return(1); 14213} 14214#endif /* XPATH_STREAMING */ 14215 14216/** 14217 * xmlXPathRunEval: 14218 * @ctxt: the XPath parser context with the compiled expression 14219 * @toBool: evaluate to a boolean result 14220 * 14221 * Evaluate the Precompiled XPath expression in the given context. 14222 */ 14223static int 14224xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 14225{ 14226 xmlXPathCompExprPtr comp; 14227 14228 if ((ctxt == NULL) || (ctxt->comp == NULL)) 14229 return(-1); 14230 14231 if (ctxt->valueTab == NULL) { 14232 /* Allocate the value stack */ 14233 ctxt->valueTab = (xmlXPathObjectPtr *) 14234 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 14235 if (ctxt->valueTab == NULL) { 14236 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 14237 xmlFree(ctxt); 14238 } 14239 ctxt->valueNr = 0; 14240 ctxt->valueMax = 10; 14241 ctxt->value = NULL; 14242 } 14243#ifdef XPATH_STREAMING 14244 if (ctxt->comp->stream) { 14245 int res; 14246 14247 if (toBool) { 14248 /* 14249 * Evaluation to boolean result. 14250 */ 14251 res = xmlXPathRunStreamEval(ctxt->context, 14252 ctxt->comp->stream, NULL, 1); 14253 if (res != -1) 14254 return(res); 14255 } else { 14256 xmlXPathObjectPtr resObj = NULL; 14257 14258 /* 14259 * Evaluation to a sequence. 14260 */ 14261 res = xmlXPathRunStreamEval(ctxt->context, 14262 ctxt->comp->stream, &resObj, 0); 14263 14264 if ((res != -1) && (resObj != NULL)) { 14265 valuePush(ctxt, resObj); 14266 return(0); 14267 } 14268 if (resObj != NULL) 14269 xmlXPathReleaseObject(ctxt->context, resObj); 14270 } 14271 /* 14272 * QUESTION TODO: This falls back to normal XPath evaluation 14273 * if res == -1. Is this intended? 14274 */ 14275 } 14276#endif 14277 comp = ctxt->comp; 14278 if (comp->last < 0) { 14279 xmlGenericError(xmlGenericErrorContext, 14280 "xmlXPathRunEval: last is less than zero\n"); 14281 return(-1); 14282 } 14283 if (toBool) 14284 return(xmlXPathCompOpEvalToBoolean(ctxt, 14285 &comp->steps[comp->last], 0)); 14286 else 14287 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 14288 14289 return(0); 14290} 14291 14292/************************************************************************ 14293 * * 14294 * Public interfaces * 14295 * * 14296 ************************************************************************/ 14297 14298/** 14299 * xmlXPathEvalPredicate: 14300 * @ctxt: the XPath context 14301 * @res: the Predicate Expression evaluation result 14302 * 14303 * Evaluate a predicate result for the current node. 14304 * A PredicateExpr is evaluated by evaluating the Expr and converting 14305 * the result to a boolean. If the result is a number, the result will 14306 * be converted to true if the number is equal to the position of the 14307 * context node in the context node list (as returned by the position 14308 * function) and will be converted to false otherwise; if the result 14309 * is not a number, then the result will be converted as if by a call 14310 * to the boolean function. 14311 * 14312 * Returns 1 if predicate is true, 0 otherwise 14313 */ 14314int 14315xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 14316 if ((ctxt == NULL) || (res == NULL)) return(0); 14317 switch (res->type) { 14318 case XPATH_BOOLEAN: 14319 return(res->boolval); 14320 case XPATH_NUMBER: 14321 return(res->floatval == ctxt->proximityPosition); 14322 case XPATH_NODESET: 14323 case XPATH_XSLT_TREE: 14324 if (res->nodesetval == NULL) 14325 return(0); 14326 return(res->nodesetval->nodeNr != 0); 14327 case XPATH_STRING: 14328 return((res->stringval != NULL) && 14329 (xmlStrlen(res->stringval) != 0)); 14330 default: 14331 STRANGE 14332 } 14333 return(0); 14334} 14335 14336/** 14337 * xmlXPathEvaluatePredicateResult: 14338 * @ctxt: the XPath Parser context 14339 * @res: the Predicate Expression evaluation result 14340 * 14341 * Evaluate a predicate result for the current node. 14342 * A PredicateExpr is evaluated by evaluating the Expr and converting 14343 * the result to a boolean. If the result is a number, the result will 14344 * be converted to true if the number is equal to the position of the 14345 * context node in the context node list (as returned by the position 14346 * function) and will be converted to false otherwise; if the result 14347 * is not a number, then the result will be converted as if by a call 14348 * to the boolean function. 14349 * 14350 * Returns 1 if predicate is true, 0 otherwise 14351 */ 14352int 14353xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14354 xmlXPathObjectPtr res) { 14355 if ((ctxt == NULL) || (res == NULL)) return(0); 14356 switch (res->type) { 14357 case XPATH_BOOLEAN: 14358 return(res->boolval); 14359 case XPATH_NUMBER: 14360#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14361 return((res->floatval == ctxt->context->proximityPosition) && 14362 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14363#else 14364 return(res->floatval == ctxt->context->proximityPosition); 14365#endif 14366 case XPATH_NODESET: 14367 case XPATH_XSLT_TREE: 14368 if (res->nodesetval == NULL) 14369 return(0); 14370 return(res->nodesetval->nodeNr != 0); 14371 case XPATH_STRING: 14372 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14373#ifdef LIBXML_XPTR_ENABLED 14374 case XPATH_LOCATIONSET:{ 14375 xmlLocationSetPtr ptr = res->user; 14376 if (ptr == NULL) 14377 return(0); 14378 return (ptr->locNr != 0); 14379 } 14380#endif 14381 default: 14382 STRANGE 14383 } 14384 return(0); 14385} 14386 14387#ifdef XPATH_STREAMING 14388/** 14389 * xmlXPathTryStreamCompile: 14390 * @ctxt: an XPath context 14391 * @str: the XPath expression 14392 * 14393 * Try to compile the XPath expression as a streamable subset. 14394 * 14395 * Returns the compiled expression or NULL if failed to compile. 14396 */ 14397static xmlXPathCompExprPtr 14398xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14399 /* 14400 * Optimization: use streaming patterns when the XPath expression can 14401 * be compiled to a stream lookup 14402 */ 14403 xmlPatternPtr stream; 14404 xmlXPathCompExprPtr comp; 14405 xmlDictPtr dict = NULL; 14406 const xmlChar **namespaces = NULL; 14407 xmlNsPtr ns; 14408 int i, j; 14409 14410 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14411 (!xmlStrchr(str, '@'))) { 14412 const xmlChar *tmp; 14413 14414 /* 14415 * We don't try to handle expressions using the verbose axis 14416 * specifiers ("::"), just the simplied form at this point. 14417 * Additionally, if there is no list of namespaces available and 14418 * there's a ":" in the expression, indicating a prefixed QName, 14419 * then we won't try to compile either. xmlPatterncompile() needs 14420 * to have a list of namespaces at compilation time in order to 14421 * compile prefixed name tests. 14422 */ 14423 tmp = xmlStrchr(str, ':'); 14424 if ((tmp != NULL) && 14425 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14426 return(NULL); 14427 14428 if (ctxt != NULL) { 14429 dict = ctxt->dict; 14430 if (ctxt->nsNr > 0) { 14431 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14432 if (namespaces == NULL) { 14433 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14434 return(NULL); 14435 } 14436 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14437 ns = ctxt->namespaces[j]; 14438 namespaces[i++] = ns->href; 14439 namespaces[i++] = ns->prefix; 14440 } 14441 namespaces[i++] = NULL; 14442 namespaces[i++] = NULL; 14443 } 14444 } 14445 14446 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14447 &namespaces[0]); 14448 if (namespaces != NULL) { 14449 xmlFree((xmlChar **)namespaces); 14450 } 14451 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14452 comp = xmlXPathNewCompExpr(); 14453 if (comp == NULL) { 14454 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14455 return(NULL); 14456 } 14457 comp->stream = stream; 14458 comp->dict = dict; 14459 if (comp->dict) 14460 xmlDictReference(comp->dict); 14461 return(comp); 14462 } 14463 xmlFreePattern(stream); 14464 } 14465 return(NULL); 14466} 14467#endif /* XPATH_STREAMING */ 14468 14469static int 14470xmlXPathCanRewriteDosExpression(xmlChar *expr) 14471{ 14472 if (expr == NULL) 14473 return(0); 14474 do { 14475 if ((*expr == '/') && (*(++expr) == '/')) 14476 return(1); 14477 } while (*expr++); 14478 return(0); 14479} 14480static void 14481xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) 14482{ 14483 /* 14484 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14485 * internal representation. 14486 */ 14487 if (op->ch1 != -1) { 14488 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14489 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) && 14490 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) && 14491 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */)) 14492 { 14493 /* 14494 * This is a "child::foo" 14495 */ 14496 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14497 14498 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14499 (prevop->ch1 != -1) && 14500 ((xmlXPathAxisVal) prevop->value == 14501 AXIS_DESCENDANT_OR_SELF) && 14502 (prevop->ch2 == -1) && 14503 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14504 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) && 14505 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT)) 14506 { 14507 /* 14508 * This is a "/descendant-or-self::node()" without predicates. 14509 * Eliminate it. 14510 */ 14511 op->ch1 = prevop->ch1; 14512 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM; 14513 } 14514 } 14515 if (op->ch1 != -1) 14516 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]); 14517 } 14518 if (op->ch2 != -1) 14519 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]); 14520} 14521 14522/** 14523 * xmlXPathCtxtCompile: 14524 * @ctxt: an XPath context 14525 * @str: the XPath expression 14526 * 14527 * Compile an XPath expression 14528 * 14529 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14530 * the caller has to free the object. 14531 */ 14532xmlXPathCompExprPtr 14533xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14534 xmlXPathParserContextPtr pctxt; 14535 xmlXPathCompExprPtr comp; 14536 14537#ifdef XPATH_STREAMING 14538 comp = xmlXPathTryStreamCompile(ctxt, str); 14539 if (comp != NULL) 14540 return(comp); 14541#endif 14542 14543 xmlXPathInit(); 14544 14545 pctxt = xmlXPathNewParserContext(str, ctxt); 14546 xmlXPathCompileExpr(pctxt, 1); 14547 14548 if( pctxt->error != XPATH_EXPRESSION_OK ) 14549 { 14550 xmlXPathFreeParserContext(pctxt); 14551 return(NULL); 14552 } 14553 14554 if (*pctxt->cur != 0) { 14555 /* 14556 * aleksey: in some cases this line prints *second* error message 14557 * (see bug #78858) and probably this should be fixed. 14558 * However, we are not sure that all error messages are printed 14559 * out in other places. It's not critical so we leave it as-is for now 14560 */ 14561 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14562 comp = NULL; 14563 } else { 14564 comp = pctxt->comp; 14565 pctxt->comp = NULL; 14566 } 14567 xmlXPathFreeParserContext(pctxt); 14568 14569 if (comp != NULL) { 14570 comp->expr = xmlStrdup(str); 14571#ifdef DEBUG_EVAL_COUNTS 14572 comp->string = xmlStrdup(str); 14573 comp->nb = 0; 14574#endif 14575 if ((comp->expr != NULL) && 14576 (comp->nbStep > 2) && 14577 (comp->last >= 0) && 14578 (xmlXPathCanRewriteDosExpression(comp->expr) == 1)) 14579 { 14580 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]); 14581 } 14582 } 14583 return(comp); 14584} 14585 14586/** 14587 * xmlXPathCompile: 14588 * @str: the XPath expression 14589 * 14590 * Compile an XPath expression 14591 * 14592 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14593 * the caller has to free the object. 14594 */ 14595xmlXPathCompExprPtr 14596xmlXPathCompile(const xmlChar *str) { 14597 return(xmlXPathCtxtCompile(NULL, str)); 14598} 14599 14600/** 14601 * xmlXPathCompiledEvalInternal: 14602 * @comp: the compiled XPath expression 14603 * @ctxt: the XPath context 14604 * @resObj: the resulting XPath object or NULL 14605 * @toBool: 1 if only a boolean result is requested 14606 * 14607 * Evaluate the Precompiled XPath expression in the given context. 14608 * The caller has to free @resObj. 14609 * 14610 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14611 * the caller has to free the object. 14612 */ 14613static int 14614xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14615 xmlXPathContextPtr ctxt, 14616 xmlXPathObjectPtr *resObj, 14617 int toBool) 14618{ 14619 xmlXPathParserContextPtr pctxt; 14620#ifndef LIBXML_THREAD_ENABLED 14621 static int reentance = 0; 14622#endif 14623 int res; 14624 14625 CHECK_CTXT_NEG(ctxt) 14626 14627 if (comp == NULL) 14628 return(-1); 14629 xmlXPathInit(); 14630 14631#ifndef LIBXML_THREAD_ENABLED 14632 reentance++; 14633 if (reentance > 1) 14634 xmlXPathDisableOptimizer = 1; 14635#endif 14636 14637#ifdef DEBUG_EVAL_COUNTS 14638 comp->nb++; 14639 if ((comp->string != NULL) && (comp->nb > 100)) { 14640 fprintf(stderr, "100 x %s\n", comp->string); 14641 comp->nb = 0; 14642 } 14643#endif 14644 pctxt = xmlXPathCompParserContext(comp, ctxt); 14645 res = xmlXPathRunEval(pctxt, toBool); 14646 14647 if (resObj) { 14648 if (pctxt->value == NULL) { 14649 xmlGenericError(xmlGenericErrorContext, 14650 "xmlXPathCompiledEval: evaluation failed\n"); 14651 *resObj = NULL; 14652 } else { 14653 *resObj = valuePop(pctxt); 14654 } 14655 } 14656 14657 /* 14658 * Pop all remaining objects from the stack. 14659 */ 14660 if (pctxt->valueNr > 0) { 14661 xmlXPathObjectPtr tmp; 14662 int stack = 0; 14663 14664 do { 14665 tmp = valuePop(pctxt); 14666 if (tmp != NULL) { 14667 if (tmp != NULL) 14668 stack++; 14669 xmlXPathReleaseObject(ctxt, tmp); 14670 } 14671 } while (tmp != NULL); 14672 if ((stack != 0) && 14673 ((toBool) || ((resObj) && (*resObj)))) 14674 { 14675 xmlGenericError(xmlGenericErrorContext, 14676 "xmlXPathCompiledEval: %d objects left on the stack.\n", 14677 stack); 14678 } 14679 } 14680 14681 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) { 14682 xmlXPathFreeObject(*resObj); 14683 *resObj = NULL; 14684 } 14685 pctxt->comp = NULL; 14686 xmlXPathFreeParserContext(pctxt); 14687#ifndef LIBXML_THREAD_ENABLED 14688 reentance--; 14689#endif 14690 14691 return(res); 14692} 14693 14694/** 14695 * xmlXPathCompiledEval: 14696 * @comp: the compiled XPath expression 14697 * @ctx: the XPath context 14698 * 14699 * Evaluate the Precompiled XPath expression in the given context. 14700 * 14701 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14702 * the caller has to free the object. 14703 */ 14704xmlXPathObjectPtr 14705xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14706{ 14707 xmlXPathObjectPtr res = NULL; 14708 14709 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14710 return(res); 14711} 14712 14713/** 14714 * xmlXPathCompiledEvalToBoolean: 14715 * @comp: the compiled XPath expression 14716 * @ctxt: the XPath context 14717 * 14718 * Applies the XPath boolean() function on the result of the given 14719 * compiled expression. 14720 * 14721 * Returns 1 if the expression evaluated to true, 0 if to false and 14722 * -1 in API and internal errors. 14723 */ 14724int 14725xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 14726 xmlXPathContextPtr ctxt) 14727{ 14728 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 14729} 14730 14731/** 14732 * xmlXPathEvalExpr: 14733 * @ctxt: the XPath Parser context 14734 * 14735 * Parse and evaluate an XPath expression in the given context, 14736 * then push the result on the context stack 14737 */ 14738void 14739xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14740#ifdef XPATH_STREAMING 14741 xmlXPathCompExprPtr comp; 14742#endif 14743 14744 if (ctxt == NULL) return; 14745 14746#ifdef XPATH_STREAMING 14747 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14748 if (comp != NULL) { 14749 if (ctxt->comp != NULL) 14750 xmlXPathFreeCompExpr(ctxt->comp); 14751 ctxt->comp = comp; 14752 if (ctxt->cur != NULL) 14753 while (*ctxt->cur != 0) ctxt->cur++; 14754 } else 14755#endif 14756 { 14757 xmlXPathCompileExpr(ctxt, 1); 14758 /* 14759 * In this scenario the expression string will sit in ctxt->base. 14760 */ 14761 if ((ctxt->error == XPATH_EXPRESSION_OK) && 14762 (ctxt->comp != NULL) && 14763 (ctxt->base != NULL) && 14764 (ctxt->comp->nbStep > 2) && 14765 (ctxt->comp->last >= 0) && 14766 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1)) 14767 { 14768 xmlXPathRewriteDOSExpression(ctxt->comp, 14769 &ctxt->comp->steps[ctxt->comp->last]); 14770 } 14771 } 14772 CHECK_ERROR; 14773 xmlXPathRunEval(ctxt, 0); 14774} 14775 14776/** 14777 * xmlXPathEval: 14778 * @str: the XPath expression 14779 * @ctx: the XPath context 14780 * 14781 * Evaluate the XPath Location Path in the given context. 14782 * 14783 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14784 * the caller has to free the object. 14785 */ 14786xmlXPathObjectPtr 14787xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 14788 xmlXPathParserContextPtr ctxt; 14789 xmlXPathObjectPtr res, tmp, init = NULL; 14790 int stack = 0; 14791 14792 CHECK_CTXT(ctx) 14793 14794 xmlXPathInit(); 14795 14796 ctxt = xmlXPathNewParserContext(str, ctx); 14797 xmlXPathEvalExpr(ctxt); 14798 14799 if (ctxt->value == NULL) { 14800 xmlGenericError(xmlGenericErrorContext, 14801 "xmlXPathEval: evaluation failed\n"); 14802 res = NULL; 14803 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL) 14804#ifdef XPATH_STREAMING 14805 && (ctxt->comp->stream == NULL) 14806#endif 14807 ) { 14808 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14809 res = NULL; 14810 } else { 14811 res = valuePop(ctxt); 14812 } 14813 14814 do { 14815 tmp = valuePop(ctxt); 14816 if (tmp != NULL) { 14817 if (tmp != init) 14818 stack++; 14819 xmlXPathReleaseObject(ctx, tmp); 14820 } 14821 } while (tmp != NULL); 14822 if ((stack != 0) && (res != NULL)) { 14823 xmlGenericError(xmlGenericErrorContext, 14824 "xmlXPathEval: %d object left on the stack\n", 14825 stack); 14826 } 14827 if (ctxt->error != XPATH_EXPRESSION_OK) { 14828 xmlXPathFreeObject(res); 14829 res = NULL; 14830 } 14831 14832 xmlXPathFreeParserContext(ctxt); 14833 return(res); 14834} 14835 14836/** 14837 * xmlXPathEvalExpression: 14838 * @str: the XPath expression 14839 * @ctxt: the XPath context 14840 * 14841 * Evaluate the XPath expression in the given context. 14842 * 14843 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14844 * the caller has to free the object. 14845 */ 14846xmlXPathObjectPtr 14847xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 14848 xmlXPathParserContextPtr pctxt; 14849 xmlXPathObjectPtr res, tmp; 14850 int stack = 0; 14851 14852 CHECK_CTXT(ctxt) 14853 14854 xmlXPathInit(); 14855 14856 pctxt = xmlXPathNewParserContext(str, ctxt); 14857 xmlXPathEvalExpr(pctxt); 14858 14859 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) { 14860 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14861 res = NULL; 14862 } else { 14863 res = valuePop(pctxt); 14864 } 14865 do { 14866 tmp = valuePop(pctxt); 14867 if (tmp != NULL) { 14868 xmlXPathReleaseObject(ctxt, tmp); 14869 stack++; 14870 } 14871 } while (tmp != NULL); 14872 if ((stack != 0) && (res != NULL)) { 14873 xmlGenericError(xmlGenericErrorContext, 14874 "xmlXPathEvalExpression: %d object left on the stack\n", 14875 stack); 14876 } 14877 xmlXPathFreeParserContext(pctxt); 14878 return(res); 14879} 14880 14881/************************************************************************ 14882 * * 14883 * Extra functions not pertaining to the XPath spec * 14884 * * 14885 ************************************************************************/ 14886/** 14887 * xmlXPathEscapeUriFunction: 14888 * @ctxt: the XPath Parser context 14889 * @nargs: the number of arguments 14890 * 14891 * Implement the escape-uri() XPath function 14892 * string escape-uri(string $str, bool $escape-reserved) 14893 * 14894 * This function applies the URI escaping rules defined in section 2 of [RFC 14895 * 2396] to the string supplied as $uri-part, which typically represents all 14896 * or part of a URI. The effect of the function is to replace any special 14897 * character in the string by an escape sequence of the form %xx%yy..., 14898 * where xxyy... is the hexadecimal representation of the octets used to 14899 * represent the character in UTF-8. 14900 * 14901 * The set of characters that are escaped depends on the setting of the 14902 * boolean argument $escape-reserved. 14903 * 14904 * If $escape-reserved is true, all characters are escaped other than lower 14905 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 14906 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 14907 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 14908 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 14909 * A-F). 14910 * 14911 * If $escape-reserved is false, the behavior differs in that characters 14912 * referred to in [RFC 2396] as reserved characters are not escaped. These 14913 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 14914 * 14915 * [RFC 2396] does not define whether escaped URIs should use lower case or 14916 * upper case for hexadecimal digits. To ensure that escaped URIs can be 14917 * compared using string comparison functions, this function must always use 14918 * the upper-case letters A-F. 14919 * 14920 * Generally, $escape-reserved should be set to true when escaping a string 14921 * that is to form a single part of a URI, and to false when escaping an 14922 * entire URI or URI reference. 14923 * 14924 * In the case of non-ascii characters, the string is encoded according to 14925 * utf-8 and then converted according to RFC 2396. 14926 * 14927 * Examples 14928 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 14929 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 14930 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 14931 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 14932 * 14933 */ 14934static void 14935xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 14936 xmlXPathObjectPtr str; 14937 int escape_reserved; 14938 xmlBufferPtr target; 14939 xmlChar *cptr; 14940 xmlChar escape[4]; 14941 14942 CHECK_ARITY(2); 14943 14944 escape_reserved = xmlXPathPopBoolean(ctxt); 14945 14946 CAST_TO_STRING; 14947 str = valuePop(ctxt); 14948 14949 target = xmlBufferCreate(); 14950 14951 escape[0] = '%'; 14952 escape[3] = 0; 14953 14954 if (target) { 14955 for (cptr = str->stringval; *cptr; cptr++) { 14956 if ((*cptr >= 'A' && *cptr <= 'Z') || 14957 (*cptr >= 'a' && *cptr <= 'z') || 14958 (*cptr >= '0' && *cptr <= '9') || 14959 *cptr == '-' || *cptr == '_' || *cptr == '.' || 14960 *cptr == '!' || *cptr == '~' || *cptr == '*' || 14961 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 14962 (*cptr == '%' && 14963 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 14964 (cptr[1] >= 'a' && cptr[1] <= 'f') || 14965 (cptr[1] >= '0' && cptr[1] <= '9')) && 14966 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 14967 (cptr[2] >= 'a' && cptr[2] <= 'f') || 14968 (cptr[2] >= '0' && cptr[2] <= '9'))) || 14969 (!escape_reserved && 14970 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 14971 *cptr == ':' || *cptr == '@' || *cptr == '&' || 14972 *cptr == '=' || *cptr == '+' || *cptr == '$' || 14973 *cptr == ','))) { 14974 xmlBufferAdd(target, cptr, 1); 14975 } else { 14976 if ((*cptr >> 4) < 10) 14977 escape[1] = '0' + (*cptr >> 4); 14978 else 14979 escape[1] = 'A' - 10 + (*cptr >> 4); 14980 if ((*cptr & 0xF) < 10) 14981 escape[2] = '0' + (*cptr & 0xF); 14982 else 14983 escape[2] = 'A' - 10 + (*cptr & 0xF); 14984 14985 xmlBufferAdd(target, &escape[0], 3); 14986 } 14987 } 14988 } 14989 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 14990 xmlBufferContent(target))); 14991 xmlBufferFree(target); 14992 xmlXPathReleaseObject(ctxt->context, str); 14993} 14994 14995/** 14996 * xmlXPathRegisterAllFunctions: 14997 * @ctxt: the XPath context 14998 * 14999 * Registers all default XPath functions in this context 15000 */ 15001void 15002xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 15003{ 15004 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 15005 xmlXPathBooleanFunction); 15006 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 15007 xmlXPathCeilingFunction); 15008 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 15009 xmlXPathCountFunction); 15010 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 15011 xmlXPathConcatFunction); 15012 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 15013 xmlXPathContainsFunction); 15014 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 15015 xmlXPathIdFunction); 15016 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 15017 xmlXPathFalseFunction); 15018 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 15019 xmlXPathFloorFunction); 15020 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 15021 xmlXPathLastFunction); 15022 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 15023 xmlXPathLangFunction); 15024 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 15025 xmlXPathLocalNameFunction); 15026 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 15027 xmlXPathNotFunction); 15028 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 15029 xmlXPathNameFunction); 15030 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 15031 xmlXPathNamespaceURIFunction); 15032 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 15033 xmlXPathNormalizeFunction); 15034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 15035 xmlXPathNumberFunction); 15036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 15037 xmlXPathPositionFunction); 15038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 15039 xmlXPathRoundFunction); 15040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 15041 xmlXPathStringFunction); 15042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 15043 xmlXPathStringLengthFunction); 15044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 15045 xmlXPathStartsWithFunction); 15046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 15047 xmlXPathSubstringFunction); 15048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 15049 xmlXPathSubstringBeforeFunction); 15050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 15051 xmlXPathSubstringAfterFunction); 15052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 15053 xmlXPathSumFunction); 15054 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 15055 xmlXPathTrueFunction); 15056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 15057 xmlXPathTranslateFunction); 15058 15059 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 15060 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 15061 xmlXPathEscapeUriFunction); 15062} 15063 15064#endif /* LIBXML_XPATH_ENABLED */ 15065#define bottom_xpath 15066#include "elfgcchack.h" 15067