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#ifdef DEBUG_XPATH_EXPRESSION 191#define DEBUG_STEP 192#define DEBUG_EXPR 193#define DEBUG_EVAL_COUNTS 194#endif 195 196static xmlNs xmlXPathXMLNamespaceStruct = { 197 NULL, 198 XML_NAMESPACE_DECL, 199 XML_XML_NAMESPACE, 200 BAD_CAST "xml", 201 NULL, 202 NULL 203}; 204static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 205#ifndef LIBXML_THREAD_ENABLED 206/* 207 * Optimizer is disabled only when threaded apps are detected while 208 * the library ain't compiled for thread safety. 209 */ 210static int xmlXPathDisableOptimizer = 0; 211#endif 212 213/************************************************************************ 214 * * 215 * Error handling routines * 216 * * 217 ************************************************************************/ 218 219/** 220 * XP_ERRORNULL: 221 * @X: the error code 222 * 223 * Macro to raise an XPath error and return NULL. 224 */ 225#define XP_ERRORNULL(X) \ 226 { xmlXPathErr(ctxt, X); return(NULL); } 227 228/* 229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 230 */ 231static const char *xmlXPathErrorMessages[] = { 232 "Ok\n", 233 "Number encoding\n", 234 "Unfinished literal\n", 235 "Start of literal\n", 236 "Expected $ for variable reference\n", 237 "Undefined variable\n", 238 "Invalid predicate\n", 239 "Invalid expression\n", 240 "Missing closing curly brace\n", 241 "Unregistered function\n", 242 "Invalid operand\n", 243 "Invalid type\n", 244 "Invalid number of arguments\n", 245 "Invalid context size\n", 246 "Invalid context position\n", 247 "Memory allocation error\n", 248 "Syntax error\n", 249 "Resource error\n", 250 "Sub resource error\n", 251 "Undefined namespace prefix\n", 252 "Encoding error\n", 253 "Char out of XML range\n", 254 "Invalid or incomplete context\n", 255 "?? Unknown error ??\n" /* Must be last in the list! */ 256}; 257#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 258 sizeof(xmlXPathErrorMessages[0])) - 1) 259/** 260 * xmlXPathErrMemory: 261 * @ctxt: an XPath context 262 * @extra: extra informations 263 * 264 * Handle a redefinition of attribute error 265 */ 266static void 267xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 268{ 269 if (ctxt != NULL) { 270 if (extra) { 271 xmlChar buf[200]; 272 273 xmlStrPrintf(buf, 200, 274 BAD_CAST "Memory allocation failed : %s\n", 275 extra); 276 ctxt->lastError.message = (char *) xmlStrdup(buf); 277 } else { 278 ctxt->lastError.message = (char *) 279 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 280 } 281 ctxt->lastError.domain = XML_FROM_XPATH; 282 ctxt->lastError.code = XML_ERR_NO_MEMORY; 283 if (ctxt->error != NULL) 284 ctxt->error(ctxt->userData, &ctxt->lastError); 285 } else { 286 if (extra) 287 __xmlRaiseError(NULL, NULL, NULL, 288 NULL, NULL, XML_FROM_XPATH, 289 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 290 extra, NULL, NULL, 0, 0, 291 "Memory allocation failed : %s\n", extra); 292 else 293 __xmlRaiseError(NULL, NULL, NULL, 294 NULL, NULL, XML_FROM_XPATH, 295 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 296 NULL, NULL, NULL, 0, 0, 297 "Memory allocation failed\n"); 298 } 299} 300 301/** 302 * xmlXPathPErrMemory: 303 * @ctxt: an XPath parser context 304 * @extra: extra informations 305 * 306 * Handle a redefinition of attribute error 307 */ 308static void 309xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 310{ 311 if (ctxt == NULL) 312 xmlXPathErrMemory(NULL, extra); 313 else { 314 ctxt->error = XPATH_MEMORY_ERROR; 315 xmlXPathErrMemory(ctxt->context, extra); 316 } 317} 318 319/** 320 * xmlXPathErr: 321 * @ctxt: a XPath parser context 322 * @error: the error code 323 * 324 * Handle an XPath error 325 */ 326void 327xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 328{ 329 if ((error < 0) || (error > MAXERRNO)) 330 error = MAXERRNO; 331 if (ctxt == NULL) { 332 __xmlRaiseError(NULL, NULL, NULL, 333 NULL, NULL, XML_FROM_XPATH, 334 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 335 XML_ERR_ERROR, NULL, 0, 336 NULL, NULL, NULL, 0, 0, 337 "%s", xmlXPathErrorMessages[error]); 338 return; 339 } 340 ctxt->error = error; 341 if (ctxt->context == NULL) { 342 __xmlRaiseError(NULL, NULL, NULL, 343 NULL, NULL, XML_FROM_XPATH, 344 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 345 XML_ERR_ERROR, NULL, 0, 346 (const char *) ctxt->base, NULL, NULL, 347 ctxt->cur - ctxt->base, 0, 348 "%s", xmlXPathErrorMessages[error]); 349 return; 350 } 351 352 /* cleanup current last error */ 353 xmlResetError(&ctxt->context->lastError); 354 355 ctxt->context->lastError.domain = XML_FROM_XPATH; 356 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 357 XPATH_EXPRESSION_OK; 358 ctxt->context->lastError.level = XML_ERR_ERROR; 359 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 360 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 361 ctxt->context->lastError.node = ctxt->context->debugNode; 362 if (ctxt->context->error != NULL) { 363 ctxt->context->error(ctxt->context->userData, 364 &ctxt->context->lastError); 365 } else { 366 __xmlRaiseError(NULL, NULL, NULL, 367 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 368 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 369 XML_ERR_ERROR, NULL, 0, 370 (const char *) ctxt->base, NULL, NULL, 371 ctxt->cur - ctxt->base, 0, 372 "%s", xmlXPathErrorMessages[error]); 373 } 374 375} 376 377/** 378 * xmlXPatherror: 379 * @ctxt: the XPath Parser context 380 * @file: the file name 381 * @line: the line number 382 * @no: the error number 383 * 384 * Formats an error message. 385 */ 386void 387xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 388 int line ATTRIBUTE_UNUSED, int no) { 389 xmlXPathErr(ctxt, no); 390} 391 392/************************************************************************ 393 * * 394 * Utilities * 395 * * 396 ************************************************************************/ 397 398/** 399 * xsltPointerList: 400 * 401 * Pointer-list for various purposes. 402 */ 403typedef struct _xmlPointerList xmlPointerList; 404typedef xmlPointerList *xmlPointerListPtr; 405struct _xmlPointerList { 406 void **items; 407 int number; 408 int size; 409}; 410/* 411* TODO: Since such a list-handling is used in xmlschemas.c and libxslt 412* and here, we should make the functions public. 413*/ 414static int 415xmlPointerListAddSize(xmlPointerListPtr list, 416 void *item, 417 int initialSize) 418{ 419 if (list->items == NULL) { 420 if (initialSize <= 0) 421 initialSize = 1; 422 list->items = (void **) xmlMalloc( 423 initialSize * sizeof(void *)); 424 if (list->items == NULL) { 425 xmlXPathErrMemory(NULL, 426 "xmlPointerListCreate: allocating item\n"); 427 return(-1); 428 } 429 list->number = 0; 430 list->size = initialSize; 431 } else if (list->size <= list->number) { 432 list->size *= 2; 433 list->items = (void **) xmlRealloc(list->items, 434 list->size * sizeof(void *)); 435 if (list->items == NULL) { 436 xmlXPathErrMemory(NULL, 437 "xmlPointerListCreate: re-allocating item\n"); 438 list->size = 0; 439 return(-1); 440 } 441 } 442 list->items[list->number++] = item; 443 return(0); 444} 445 446/** 447 * xsltPointerListCreate: 448 * 449 * Creates an xsltPointerList structure. 450 * 451 * Returns a xsltPointerList structure or NULL in case of an error. 452 */ 453static xmlPointerListPtr 454xmlPointerListCreate(int initialSize) 455{ 456 xmlPointerListPtr ret; 457 458 ret = xmlMalloc(sizeof(xmlPointerList)); 459 if (ret == NULL) { 460 xmlXPathErrMemory(NULL, 461 "xmlPointerListCreate: allocating item\n"); 462 return (NULL); 463 } 464 memset(ret, 0, sizeof(xmlPointerList)); 465 if (initialSize > 0) { 466 xmlPointerListAddSize(ret, NULL, initialSize); 467 ret->number = 0; 468 } 469 return (ret); 470} 471 472/** 473 * xsltPointerListFree: 474 * 475 * Frees the xsltPointerList structure. This does not free 476 * the content of the list. 477 */ 478static void 479xmlPointerListFree(xmlPointerListPtr list) 480{ 481 if (list == NULL) 482 return; 483 if (list->items != NULL) 484 xmlFree(list->items); 485 xmlFree(list); 486} 487 488/************************************************************************ 489 * * 490 * Parser Types * 491 * * 492 ************************************************************************/ 493 494/* 495 * Types are private: 496 */ 497 498typedef enum { 499 XPATH_OP_END=0, 500 XPATH_OP_AND, 501 XPATH_OP_OR, 502 XPATH_OP_EQUAL, 503 XPATH_OP_CMP, 504 XPATH_OP_PLUS, 505 XPATH_OP_MULT, 506 XPATH_OP_UNION, 507 XPATH_OP_ROOT, 508 XPATH_OP_NODE, 509 XPATH_OP_RESET, /* 10 */ 510 XPATH_OP_COLLECT, 511 XPATH_OP_VALUE, /* 12 */ 512 XPATH_OP_VARIABLE, 513 XPATH_OP_FUNCTION, 514 XPATH_OP_ARG, 515 XPATH_OP_PREDICATE, 516 XPATH_OP_FILTER, /* 17 */ 517 XPATH_OP_SORT /* 18 */ 518#ifdef LIBXML_XPTR_ENABLED 519 ,XPATH_OP_RANGETO 520#endif 521} xmlXPathOp; 522 523typedef enum { 524 AXIS_ANCESTOR = 1, 525 AXIS_ANCESTOR_OR_SELF, 526 AXIS_ATTRIBUTE, 527 AXIS_CHILD, 528 AXIS_DESCENDANT, 529 AXIS_DESCENDANT_OR_SELF, 530 AXIS_FOLLOWING, 531 AXIS_FOLLOWING_SIBLING, 532 AXIS_NAMESPACE, 533 AXIS_PARENT, 534 AXIS_PRECEDING, 535 AXIS_PRECEDING_SIBLING, 536 AXIS_SELF 537} xmlXPathAxisVal; 538 539typedef enum { 540 NODE_TEST_NONE = 0, 541 NODE_TEST_TYPE = 1, 542 NODE_TEST_PI = 2, 543 NODE_TEST_ALL = 3, 544 NODE_TEST_NS = 4, 545 NODE_TEST_NAME = 5 546} xmlXPathTestVal; 547 548typedef enum { 549 NODE_TYPE_NODE = 0, 550 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 551 NODE_TYPE_TEXT = XML_TEXT_NODE, 552 NODE_TYPE_PI = XML_PI_NODE 553} xmlXPathTypeVal; 554 555#define XP_REWRITE_DOS_CHILD_ELEM 1 556 557typedef struct _xmlXPathStepOp xmlXPathStepOp; 558typedef xmlXPathStepOp *xmlXPathStepOpPtr; 559struct _xmlXPathStepOp { 560 xmlXPathOp op; /* The identifier of the operation */ 561 int ch1; /* First child */ 562 int ch2; /* Second child */ 563 int value; 564 int value2; 565 int value3; 566 void *value4; 567 void *value5; 568 void *cache; 569 void *cacheURI; 570 int rewriteType; 571}; 572 573struct _xmlXPathCompExpr { 574 int nbStep; /* Number of steps in this expression */ 575 int maxStep; /* Maximum number of steps allocated */ 576 xmlXPathStepOp *steps; /* ops for computation of this expression */ 577 int last; /* index of last step in expression */ 578 xmlChar *expr; /* the expression being computed */ 579 xmlDictPtr dict; /* the dictionnary to use if any */ 580#ifdef DEBUG_EVAL_COUNTS 581 int nb; 582 xmlChar *string; 583#endif 584#ifdef XPATH_STREAMING 585 xmlPatternPtr stream; 586#endif 587}; 588 589/************************************************************************ 590 * * 591 * Forward declarations * 592 * * 593 ************************************************************************/ 594static void 595xmlXPathFreeValueTree(xmlNodeSetPtr obj); 596static void 597xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 598static int 599xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 600 xmlXPathStepOpPtr op, xmlNodePtr *first); 601static int 602xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 603 xmlXPathStepOpPtr op, 604 int isPredicate); 605 606/************************************************************************ 607 * * 608 * Parser Type functions * 609 * * 610 ************************************************************************/ 611 612/** 613 * xmlXPathNewCompExpr: 614 * 615 * Create a new Xpath component 616 * 617 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 618 */ 619static xmlXPathCompExprPtr 620xmlXPathNewCompExpr(void) { 621 xmlXPathCompExprPtr cur; 622 623 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 624 if (cur == NULL) { 625 xmlXPathErrMemory(NULL, "allocating component\n"); 626 return(NULL); 627 } 628 memset(cur, 0, sizeof(xmlXPathCompExpr)); 629 cur->maxStep = 10; 630 cur->nbStep = 0; 631 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 632 sizeof(xmlXPathStepOp)); 633 if (cur->steps == NULL) { 634 xmlXPathErrMemory(NULL, "allocating steps\n"); 635 xmlFree(cur); 636 return(NULL); 637 } 638 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 639 cur->last = -1; 640#ifdef DEBUG_EVAL_COUNTS 641 cur->nb = 0; 642#endif 643 return(cur); 644} 645 646/** 647 * xmlXPathFreeCompExpr: 648 * @comp: an XPATH comp 649 * 650 * Free up the memory allocated by @comp 651 */ 652void 653xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 654{ 655 xmlXPathStepOpPtr op; 656 int i; 657 658 if (comp == NULL) 659 return; 660 if (comp->dict == NULL) { 661 for (i = 0; i < comp->nbStep; i++) { 662 op = &comp->steps[i]; 663 if (op->value4 != NULL) { 664 if (op->op == XPATH_OP_VALUE) 665 xmlXPathFreeObject(op->value4); 666 else 667 xmlFree(op->value4); 668 } 669 if (op->value5 != NULL) 670 xmlFree(op->value5); 671 } 672 } else { 673 for (i = 0; i < comp->nbStep; i++) { 674 op = &comp->steps[i]; 675 if (op->value4 != NULL) { 676 if (op->op == XPATH_OP_VALUE) 677 xmlXPathFreeObject(op->value4); 678 } 679 } 680 xmlDictFree(comp->dict); 681 } 682 if (comp->steps != NULL) { 683 xmlFree(comp->steps); 684 } 685#ifdef DEBUG_EVAL_COUNTS 686 if (comp->string != NULL) { 687 xmlFree(comp->string); 688 } 689#endif 690#ifdef XPATH_STREAMING 691 if (comp->stream != NULL) { 692 xmlFreePatternList(comp->stream); 693 } 694#endif 695 if (comp->expr != NULL) { 696 xmlFree(comp->expr); 697 } 698 699 xmlFree(comp); 700} 701 702/** 703 * xmlXPathCompExprAdd: 704 * @comp: the compiled expression 705 * @ch1: first child index 706 * @ch2: second child index 707 * @op: an op 708 * @value: the first int value 709 * @value2: the second int value 710 * @value3: the third int value 711 * @value4: the first string value 712 * @value5: the second string value 713 * 714 * Add a step to an XPath Compiled Expression 715 * 716 * Returns -1 in case of failure, the index otherwise 717 */ 718static int 719xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 720 xmlXPathOp op, int value, 721 int value2, int value3, void *value4, void *value5) { 722 if (comp->nbStep >= comp->maxStep) { 723 xmlXPathStepOp *real; 724 725 comp->maxStep *= 2; 726 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 727 comp->maxStep * sizeof(xmlXPathStepOp)); 728 if (real == NULL) { 729 comp->maxStep /= 2; 730 xmlXPathErrMemory(NULL, "adding step\n"); 731 return(-1); 732 } 733 comp->steps = real; 734 } 735 comp->last = comp->nbStep; 736 comp->steps[comp->nbStep].rewriteType = 0; 737 comp->steps[comp->nbStep].ch1 = ch1; 738 comp->steps[comp->nbStep].ch2 = ch2; 739 comp->steps[comp->nbStep].op = op; 740 comp->steps[comp->nbStep].value = value; 741 comp->steps[comp->nbStep].value2 = value2; 742 comp->steps[comp->nbStep].value3 = value3; 743 if ((comp->dict != NULL) && 744 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 745 (op == XPATH_OP_COLLECT))) { 746 if (value4 != NULL) { 747 comp->steps[comp->nbStep].value4 = (xmlChar *) 748 (void *)xmlDictLookup(comp->dict, value4, -1); 749 xmlFree(value4); 750 } else 751 comp->steps[comp->nbStep].value4 = NULL; 752 if (value5 != NULL) { 753 comp->steps[comp->nbStep].value5 = (xmlChar *) 754 (void *)xmlDictLookup(comp->dict, value5, -1); 755 xmlFree(value5); 756 } else 757 comp->steps[comp->nbStep].value5 = NULL; 758 } else { 759 comp->steps[comp->nbStep].value4 = value4; 760 comp->steps[comp->nbStep].value5 = value5; 761 } 762 comp->steps[comp->nbStep].cache = NULL; 763 return(comp->nbStep++); 764} 765 766/** 767 * xmlXPathCompSwap: 768 * @comp: the compiled expression 769 * @op: operation index 770 * 771 * Swaps 2 operations in the compiled expression 772 */ 773static void 774xmlXPathCompSwap(xmlXPathStepOpPtr op) { 775 int tmp; 776 777#ifndef LIBXML_THREAD_ENABLED 778 /* 779 * Since this manipulates possibly shared variables, this is 780 * disabled if one detects that the library is used in a multithreaded 781 * application 782 */ 783 if (xmlXPathDisableOptimizer) 784 return; 785#endif 786 787 tmp = op->ch1; 788 op->ch1 = op->ch2; 789 op->ch2 = tmp; 790} 791 792#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 793 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 794 (op), (val), (val2), (val3), (val4), (val5)) 795#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 796 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 797 (op), (val), (val2), (val3), (val4), (val5)) 798 799#define PUSH_LEAVE_EXPR(op, val, val2) \ 800xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 801 802#define PUSH_UNARY_EXPR(op, ch, val, val2) \ 803xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 804 805#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 806xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 807 (val), (val2), 0 ,NULL ,NULL) 808 809/************************************************************************ 810 * * 811 * XPath object cache structures * 812 * * 813 ************************************************************************/ 814 815/* #define XP_DEFAULT_CACHE_ON */ 816 817#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 818 819typedef struct _xmlXPathContextCache xmlXPathContextCache; 820typedef xmlXPathContextCache *xmlXPathContextCachePtr; 821struct _xmlXPathContextCache { 822 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 823 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 824 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 825 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 826 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 827 int maxNodeset; 828 int maxString; 829 int maxBoolean; 830 int maxNumber; 831 int maxMisc; 832#ifdef XP_DEBUG_OBJ_USAGE 833 int dbgCachedAll; 834 int dbgCachedNodeset; 835 int dbgCachedString; 836 int dbgCachedBool; 837 int dbgCachedNumber; 838 int dbgCachedPoint; 839 int dbgCachedRange; 840 int dbgCachedLocset; 841 int dbgCachedUsers; 842 int dbgCachedXSLTTree; 843 int dbgCachedUndefined; 844 845 846 int dbgReusedAll; 847 int dbgReusedNodeset; 848 int dbgReusedString; 849 int dbgReusedBool; 850 int dbgReusedNumber; 851 int dbgReusedPoint; 852 int dbgReusedRange; 853 int dbgReusedLocset; 854 int dbgReusedUsers; 855 int dbgReusedXSLTTree; 856 int dbgReusedUndefined; 857 858#endif 859}; 860 861/************************************************************************ 862 * * 863 * Debugging related functions * 864 * * 865 ************************************************************************/ 866 867#define STRANGE \ 868 xmlGenericError(xmlGenericErrorContext, \ 869 "Internal error at %s:%d\n", \ 870 __FILE__, __LINE__); 871 872#ifdef LIBXML_DEBUG_ENABLED 873static void 874xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 875 int i; 876 char shift[100]; 877 878 for (i = 0;((i < depth) && (i < 25));i++) 879 shift[2 * i] = shift[2 * i + 1] = ' '; 880 shift[2 * i] = shift[2 * i + 1] = 0; 881 if (cur == NULL) { 882 fprintf(output, "%s", shift); 883 fprintf(output, "Node is NULL !\n"); 884 return; 885 886 } 887 888 if ((cur->type == XML_DOCUMENT_NODE) || 889 (cur->type == XML_HTML_DOCUMENT_NODE)) { 890 fprintf(output, "%s", shift); 891 fprintf(output, " /\n"); 892 } else if (cur->type == XML_ATTRIBUTE_NODE) 893 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 894 else 895 xmlDebugDumpOneNode(output, cur, depth); 896} 897static void 898xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 899 xmlNodePtr tmp; 900 int i; 901 char shift[100]; 902 903 for (i = 0;((i < depth) && (i < 25));i++) 904 shift[2 * i] = shift[2 * i + 1] = ' '; 905 shift[2 * i] = shift[2 * i + 1] = 0; 906 if (cur == NULL) { 907 fprintf(output, "%s", shift); 908 fprintf(output, "Node is NULL !\n"); 909 return; 910 911 } 912 913 while (cur != NULL) { 914 tmp = cur; 915 cur = cur->next; 916 xmlDebugDumpOneNode(output, tmp, depth); 917 } 918} 919 920static void 921xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 922 int i; 923 char shift[100]; 924 925 for (i = 0;((i < depth) && (i < 25));i++) 926 shift[2 * i] = shift[2 * i + 1] = ' '; 927 shift[2 * i] = shift[2 * i + 1] = 0; 928 929 if (cur == NULL) { 930 fprintf(output, "%s", shift); 931 fprintf(output, "NodeSet is NULL !\n"); 932 return; 933 934 } 935 936 if (cur != NULL) { 937 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 938 for (i = 0;i < cur->nodeNr;i++) { 939 fprintf(output, "%s", shift); 940 fprintf(output, "%d", i + 1); 941 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 942 } 943 } 944} 945 946static void 947xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 948 int i; 949 char shift[100]; 950 951 for (i = 0;((i < depth) && (i < 25));i++) 952 shift[2 * i] = shift[2 * i + 1] = ' '; 953 shift[2 * i] = shift[2 * i + 1] = 0; 954 955 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 956 fprintf(output, "%s", shift); 957 fprintf(output, "Value Tree is NULL !\n"); 958 return; 959 960 } 961 962 fprintf(output, "%s", shift); 963 fprintf(output, "%d", i + 1); 964 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 965} 966#if defined(LIBXML_XPTR_ENABLED) 967static void 968xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 969 int i; 970 char shift[100]; 971 972 for (i = 0;((i < depth) && (i < 25));i++) 973 shift[2 * i] = shift[2 * i + 1] = ' '; 974 shift[2 * i] = shift[2 * i + 1] = 0; 975 976 if (cur == NULL) { 977 fprintf(output, "%s", shift); 978 fprintf(output, "LocationSet is NULL !\n"); 979 return; 980 981 } 982 983 for (i = 0;i < cur->locNr;i++) { 984 fprintf(output, "%s", shift); 985 fprintf(output, "%d : ", i + 1); 986 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 987 } 988} 989#endif /* LIBXML_XPTR_ENABLED */ 990 991/** 992 * xmlXPathDebugDumpObject: 993 * @output: the FILE * to dump the output 994 * @cur: the object to inspect 995 * @depth: indentation level 996 * 997 * Dump the content of the object for debugging purposes 998 */ 999void 1000xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1001 int i; 1002 char shift[100]; 1003 1004 if (output == NULL) return; 1005 1006 for (i = 0;((i < depth) && (i < 25));i++) 1007 shift[2 * i] = shift[2 * i + 1] = ' '; 1008 shift[2 * i] = shift[2 * i + 1] = 0; 1009 1010 1011 fprintf(output, "%s", shift); 1012 1013 if (cur == NULL) { 1014 fprintf(output, "Object is empty (NULL)\n"); 1015 return; 1016 } 1017 switch(cur->type) { 1018 case XPATH_UNDEFINED: 1019 fprintf(output, "Object is uninitialized\n"); 1020 break; 1021 case XPATH_NODESET: 1022 fprintf(output, "Object is a Node Set :\n"); 1023 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1024 break; 1025 case XPATH_XSLT_TREE: 1026 fprintf(output, "Object is an XSLT value tree :\n"); 1027 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1028 break; 1029 case XPATH_BOOLEAN: 1030 fprintf(output, "Object is a Boolean : "); 1031 if (cur->boolval) fprintf(output, "true\n"); 1032 else fprintf(output, "false\n"); 1033 break; 1034 case XPATH_NUMBER: 1035 switch (xmlXPathIsInf(cur->floatval)) { 1036 case 1: 1037 fprintf(output, "Object is a number : Infinity\n"); 1038 break; 1039 case -1: 1040 fprintf(output, "Object is a number : -Infinity\n"); 1041 break; 1042 default: 1043 if (xmlXPathIsNaN(cur->floatval)) { 1044 fprintf(output, "Object is a number : NaN\n"); 1045 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 1046 fprintf(output, "Object is a number : 0\n"); 1047 } else { 1048 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1049 } 1050 } 1051 break; 1052 case XPATH_STRING: 1053 fprintf(output, "Object is a string : "); 1054 xmlDebugDumpString(output, cur->stringval); 1055 fprintf(output, "\n"); 1056 break; 1057 case XPATH_POINT: 1058 fprintf(output, "Object is a point : index %d in node", cur->index); 1059 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1060 fprintf(output, "\n"); 1061 break; 1062 case XPATH_RANGE: 1063 if ((cur->user2 == NULL) || 1064 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1065 fprintf(output, "Object is a collapsed range :\n"); 1066 fprintf(output, "%s", shift); 1067 if (cur->index >= 0) 1068 fprintf(output, "index %d in ", cur->index); 1069 fprintf(output, "node\n"); 1070 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1071 depth + 1); 1072 } else { 1073 fprintf(output, "Object is a range :\n"); 1074 fprintf(output, "%s", shift); 1075 fprintf(output, "From "); 1076 if (cur->index >= 0) 1077 fprintf(output, "index %d in ", cur->index); 1078 fprintf(output, "node\n"); 1079 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1080 depth + 1); 1081 fprintf(output, "%s", shift); 1082 fprintf(output, "To "); 1083 if (cur->index2 >= 0) 1084 fprintf(output, "index %d in ", cur->index2); 1085 fprintf(output, "node\n"); 1086 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1087 depth + 1); 1088 fprintf(output, "\n"); 1089 } 1090 break; 1091 case XPATH_LOCATIONSET: 1092#if defined(LIBXML_XPTR_ENABLED) 1093 fprintf(output, "Object is a Location Set:\n"); 1094 xmlXPathDebugDumpLocationSet(output, 1095 (xmlLocationSetPtr) cur->user, depth); 1096#endif 1097 break; 1098 case XPATH_USERS: 1099 fprintf(output, "Object is user defined\n"); 1100 break; 1101 } 1102} 1103 1104static void 1105xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1106 xmlXPathStepOpPtr op, int depth) { 1107 int i; 1108 char shift[100]; 1109 1110 for (i = 0;((i < depth) && (i < 25));i++) 1111 shift[2 * i] = shift[2 * i + 1] = ' '; 1112 shift[2 * i] = shift[2 * i + 1] = 0; 1113 1114 fprintf(output, "%s", shift); 1115 if (op == NULL) { 1116 fprintf(output, "Step is NULL\n"); 1117 return; 1118 } 1119 switch (op->op) { 1120 case XPATH_OP_END: 1121 fprintf(output, "END"); break; 1122 case XPATH_OP_AND: 1123 fprintf(output, "AND"); break; 1124 case XPATH_OP_OR: 1125 fprintf(output, "OR"); break; 1126 case XPATH_OP_EQUAL: 1127 if (op->value) 1128 fprintf(output, "EQUAL ="); 1129 else 1130 fprintf(output, "EQUAL !="); 1131 break; 1132 case XPATH_OP_CMP: 1133 if (op->value) 1134 fprintf(output, "CMP <"); 1135 else 1136 fprintf(output, "CMP >"); 1137 if (!op->value2) 1138 fprintf(output, "="); 1139 break; 1140 case XPATH_OP_PLUS: 1141 if (op->value == 0) 1142 fprintf(output, "PLUS -"); 1143 else if (op->value == 1) 1144 fprintf(output, "PLUS +"); 1145 else if (op->value == 2) 1146 fprintf(output, "PLUS unary -"); 1147 else if (op->value == 3) 1148 fprintf(output, "PLUS unary - -"); 1149 break; 1150 case XPATH_OP_MULT: 1151 if (op->value == 0) 1152 fprintf(output, "MULT *"); 1153 else if (op->value == 1) 1154 fprintf(output, "MULT div"); 1155 else 1156 fprintf(output, "MULT mod"); 1157 break; 1158 case XPATH_OP_UNION: 1159 fprintf(output, "UNION"); break; 1160 case XPATH_OP_ROOT: 1161 fprintf(output, "ROOT"); break; 1162 case XPATH_OP_NODE: 1163 fprintf(output, "NODE"); break; 1164 case XPATH_OP_RESET: 1165 fprintf(output, "RESET"); break; 1166 case XPATH_OP_SORT: 1167 fprintf(output, "SORT"); break; 1168 case XPATH_OP_COLLECT: { 1169 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1170 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1171 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1172 const xmlChar *prefix = op->value4; 1173 const xmlChar *name = op->value5; 1174 1175 fprintf(output, "COLLECT "); 1176 switch (axis) { 1177 case AXIS_ANCESTOR: 1178 fprintf(output, " 'ancestors' "); break; 1179 case AXIS_ANCESTOR_OR_SELF: 1180 fprintf(output, " 'ancestors-or-self' "); break; 1181 case AXIS_ATTRIBUTE: 1182 fprintf(output, " 'attributes' "); break; 1183 case AXIS_CHILD: 1184 fprintf(output, " 'child' "); break; 1185 case AXIS_DESCENDANT: 1186 fprintf(output, " 'descendant' "); break; 1187 case AXIS_DESCENDANT_OR_SELF: 1188 fprintf(output, " 'descendant-or-self' "); break; 1189 case AXIS_FOLLOWING: 1190 fprintf(output, " 'following' "); break; 1191 case AXIS_FOLLOWING_SIBLING: 1192 fprintf(output, " 'following-siblings' "); break; 1193 case AXIS_NAMESPACE: 1194 fprintf(output, " 'namespace' "); break; 1195 case AXIS_PARENT: 1196 fprintf(output, " 'parent' "); break; 1197 case AXIS_PRECEDING: 1198 fprintf(output, " 'preceding' "); break; 1199 case AXIS_PRECEDING_SIBLING: 1200 fprintf(output, " 'preceding-sibling' "); break; 1201 case AXIS_SELF: 1202 fprintf(output, " 'self' "); break; 1203 } 1204 switch (test) { 1205 case NODE_TEST_NONE: 1206 fprintf(output, "'none' "); break; 1207 case NODE_TEST_TYPE: 1208 fprintf(output, "'type' "); break; 1209 case NODE_TEST_PI: 1210 fprintf(output, "'PI' "); break; 1211 case NODE_TEST_ALL: 1212 fprintf(output, "'all' "); break; 1213 case NODE_TEST_NS: 1214 fprintf(output, "'namespace' "); break; 1215 case NODE_TEST_NAME: 1216 fprintf(output, "'name' "); break; 1217 } 1218 switch (type) { 1219 case NODE_TYPE_NODE: 1220 fprintf(output, "'node' "); break; 1221 case NODE_TYPE_COMMENT: 1222 fprintf(output, "'comment' "); break; 1223 case NODE_TYPE_TEXT: 1224 fprintf(output, "'text' "); break; 1225 case NODE_TYPE_PI: 1226 fprintf(output, "'PI' "); break; 1227 } 1228 if (prefix != NULL) 1229 fprintf(output, "%s:", prefix); 1230 if (name != NULL) 1231 fprintf(output, "%s", (const char *) name); 1232 break; 1233 1234 } 1235 case XPATH_OP_VALUE: { 1236 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1237 1238 fprintf(output, "ELEM "); 1239 xmlXPathDebugDumpObject(output, object, 0); 1240 goto finish; 1241 } 1242 case XPATH_OP_VARIABLE: { 1243 const xmlChar *prefix = op->value5; 1244 const xmlChar *name = op->value4; 1245 1246 if (prefix != NULL) 1247 fprintf(output, "VARIABLE %s:%s", prefix, name); 1248 else 1249 fprintf(output, "VARIABLE %s", name); 1250 break; 1251 } 1252 case XPATH_OP_FUNCTION: { 1253 int nbargs = op->value; 1254 const xmlChar *prefix = op->value5; 1255 const xmlChar *name = op->value4; 1256 1257 if (prefix != NULL) 1258 fprintf(output, "FUNCTION %s:%s(%d args)", 1259 prefix, name, nbargs); 1260 else 1261 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1262 break; 1263 } 1264 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1265 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1266 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1267#ifdef LIBXML_XPTR_ENABLED 1268 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1269#endif 1270 default: 1271 fprintf(output, "UNKNOWN %d\n", op->op); return; 1272 } 1273 fprintf(output, "\n"); 1274finish: 1275 if (op->ch1 >= 0) 1276 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1277 if (op->ch2 >= 0) 1278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1279} 1280 1281/** 1282 * xmlXPathDebugDumpCompExpr: 1283 * @output: the FILE * for the output 1284 * @comp: the precompiled XPath expression 1285 * @depth: the indentation level. 1286 * 1287 * Dumps the tree of the compiled XPath expression. 1288 */ 1289void 1290xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1291 int depth) { 1292 int i; 1293 char shift[100]; 1294 1295 if ((output == NULL) || (comp == NULL)) return; 1296 1297 for (i = 0;((i < depth) && (i < 25));i++) 1298 shift[2 * i] = shift[2 * i + 1] = ' '; 1299 shift[2 * i] = shift[2 * i + 1] = 0; 1300 1301 fprintf(output, "%s", shift); 1302 1303 fprintf(output, "Compiled Expression : %d elements\n", 1304 comp->nbStep); 1305 i = comp->last; 1306 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1307} 1308 1309#ifdef XP_DEBUG_OBJ_USAGE 1310 1311/* 1312* XPath object usage related debugging variables. 1313*/ 1314static int xmlXPathDebugObjCounterUndefined = 0; 1315static int xmlXPathDebugObjCounterNodeset = 0; 1316static int xmlXPathDebugObjCounterBool = 0; 1317static int xmlXPathDebugObjCounterNumber = 0; 1318static int xmlXPathDebugObjCounterString = 0; 1319static int xmlXPathDebugObjCounterPoint = 0; 1320static int xmlXPathDebugObjCounterRange = 0; 1321static int xmlXPathDebugObjCounterLocset = 0; 1322static int xmlXPathDebugObjCounterUsers = 0; 1323static int xmlXPathDebugObjCounterXSLTTree = 0; 1324static int xmlXPathDebugObjCounterAll = 0; 1325 1326static int xmlXPathDebugObjTotalUndefined = 0; 1327static int xmlXPathDebugObjTotalNodeset = 0; 1328static int xmlXPathDebugObjTotalBool = 0; 1329static int xmlXPathDebugObjTotalNumber = 0; 1330static int xmlXPathDebugObjTotalString = 0; 1331static int xmlXPathDebugObjTotalPoint = 0; 1332static int xmlXPathDebugObjTotalRange = 0; 1333static int xmlXPathDebugObjTotalLocset = 0; 1334static int xmlXPathDebugObjTotalUsers = 0; 1335static int xmlXPathDebugObjTotalXSLTTree = 0; 1336static int xmlXPathDebugObjTotalAll = 0; 1337 1338static int xmlXPathDebugObjMaxUndefined = 0; 1339static int xmlXPathDebugObjMaxNodeset = 0; 1340static int xmlXPathDebugObjMaxBool = 0; 1341static int xmlXPathDebugObjMaxNumber = 0; 1342static int xmlXPathDebugObjMaxString = 0; 1343static int xmlXPathDebugObjMaxPoint = 0; 1344static int xmlXPathDebugObjMaxRange = 0; 1345static int xmlXPathDebugObjMaxLocset = 0; 1346static int xmlXPathDebugObjMaxUsers = 0; 1347static int xmlXPathDebugObjMaxXSLTTree = 0; 1348static int xmlXPathDebugObjMaxAll = 0; 1349 1350/* REVISIT TODO: Make this static when committing */ 1351static void 1352xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1353{ 1354 if (ctxt != NULL) { 1355 if (ctxt->cache != NULL) { 1356 xmlXPathContextCachePtr cache = 1357 (xmlXPathContextCachePtr) ctxt->cache; 1358 1359 cache->dbgCachedAll = 0; 1360 cache->dbgCachedNodeset = 0; 1361 cache->dbgCachedString = 0; 1362 cache->dbgCachedBool = 0; 1363 cache->dbgCachedNumber = 0; 1364 cache->dbgCachedPoint = 0; 1365 cache->dbgCachedRange = 0; 1366 cache->dbgCachedLocset = 0; 1367 cache->dbgCachedUsers = 0; 1368 cache->dbgCachedXSLTTree = 0; 1369 cache->dbgCachedUndefined = 0; 1370 1371 cache->dbgReusedAll = 0; 1372 cache->dbgReusedNodeset = 0; 1373 cache->dbgReusedString = 0; 1374 cache->dbgReusedBool = 0; 1375 cache->dbgReusedNumber = 0; 1376 cache->dbgReusedPoint = 0; 1377 cache->dbgReusedRange = 0; 1378 cache->dbgReusedLocset = 0; 1379 cache->dbgReusedUsers = 0; 1380 cache->dbgReusedXSLTTree = 0; 1381 cache->dbgReusedUndefined = 0; 1382 } 1383 } 1384 1385 xmlXPathDebugObjCounterUndefined = 0; 1386 xmlXPathDebugObjCounterNodeset = 0; 1387 xmlXPathDebugObjCounterBool = 0; 1388 xmlXPathDebugObjCounterNumber = 0; 1389 xmlXPathDebugObjCounterString = 0; 1390 xmlXPathDebugObjCounterPoint = 0; 1391 xmlXPathDebugObjCounterRange = 0; 1392 xmlXPathDebugObjCounterLocset = 0; 1393 xmlXPathDebugObjCounterUsers = 0; 1394 xmlXPathDebugObjCounterXSLTTree = 0; 1395 xmlXPathDebugObjCounterAll = 0; 1396 1397 xmlXPathDebugObjTotalUndefined = 0; 1398 xmlXPathDebugObjTotalNodeset = 0; 1399 xmlXPathDebugObjTotalBool = 0; 1400 xmlXPathDebugObjTotalNumber = 0; 1401 xmlXPathDebugObjTotalString = 0; 1402 xmlXPathDebugObjTotalPoint = 0; 1403 xmlXPathDebugObjTotalRange = 0; 1404 xmlXPathDebugObjTotalLocset = 0; 1405 xmlXPathDebugObjTotalUsers = 0; 1406 xmlXPathDebugObjTotalXSLTTree = 0; 1407 xmlXPathDebugObjTotalAll = 0; 1408 1409 xmlXPathDebugObjMaxUndefined = 0; 1410 xmlXPathDebugObjMaxNodeset = 0; 1411 xmlXPathDebugObjMaxBool = 0; 1412 xmlXPathDebugObjMaxNumber = 0; 1413 xmlXPathDebugObjMaxString = 0; 1414 xmlXPathDebugObjMaxPoint = 0; 1415 xmlXPathDebugObjMaxRange = 0; 1416 xmlXPathDebugObjMaxLocset = 0; 1417 xmlXPathDebugObjMaxUsers = 0; 1418 xmlXPathDebugObjMaxXSLTTree = 0; 1419 xmlXPathDebugObjMaxAll = 0; 1420 1421} 1422 1423static void 1424xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1425 xmlXPathObjectType objType) 1426{ 1427 int isCached = 0; 1428 1429 if (ctxt != NULL) { 1430 if (ctxt->cache != NULL) { 1431 xmlXPathContextCachePtr cache = 1432 (xmlXPathContextCachePtr) ctxt->cache; 1433 1434 isCached = 1; 1435 1436 cache->dbgReusedAll++; 1437 switch (objType) { 1438 case XPATH_UNDEFINED: 1439 cache->dbgReusedUndefined++; 1440 break; 1441 case XPATH_NODESET: 1442 cache->dbgReusedNodeset++; 1443 break; 1444 case XPATH_BOOLEAN: 1445 cache->dbgReusedBool++; 1446 break; 1447 case XPATH_NUMBER: 1448 cache->dbgReusedNumber++; 1449 break; 1450 case XPATH_STRING: 1451 cache->dbgReusedString++; 1452 break; 1453 case XPATH_POINT: 1454 cache->dbgReusedPoint++; 1455 break; 1456 case XPATH_RANGE: 1457 cache->dbgReusedRange++; 1458 break; 1459 case XPATH_LOCATIONSET: 1460 cache->dbgReusedLocset++; 1461 break; 1462 case XPATH_USERS: 1463 cache->dbgReusedUsers++; 1464 break; 1465 case XPATH_XSLT_TREE: 1466 cache->dbgReusedXSLTTree++; 1467 break; 1468 default: 1469 break; 1470 } 1471 } 1472 } 1473 1474 switch (objType) { 1475 case XPATH_UNDEFINED: 1476 if (! isCached) 1477 xmlXPathDebugObjTotalUndefined++; 1478 xmlXPathDebugObjCounterUndefined++; 1479 if (xmlXPathDebugObjCounterUndefined > 1480 xmlXPathDebugObjMaxUndefined) 1481 xmlXPathDebugObjMaxUndefined = 1482 xmlXPathDebugObjCounterUndefined; 1483 break; 1484 case XPATH_NODESET: 1485 if (! isCached) 1486 xmlXPathDebugObjTotalNodeset++; 1487 xmlXPathDebugObjCounterNodeset++; 1488 if (xmlXPathDebugObjCounterNodeset > 1489 xmlXPathDebugObjMaxNodeset) 1490 xmlXPathDebugObjMaxNodeset = 1491 xmlXPathDebugObjCounterNodeset; 1492 break; 1493 case XPATH_BOOLEAN: 1494 if (! isCached) 1495 xmlXPathDebugObjTotalBool++; 1496 xmlXPathDebugObjCounterBool++; 1497 if (xmlXPathDebugObjCounterBool > 1498 xmlXPathDebugObjMaxBool) 1499 xmlXPathDebugObjMaxBool = 1500 xmlXPathDebugObjCounterBool; 1501 break; 1502 case XPATH_NUMBER: 1503 if (! isCached) 1504 xmlXPathDebugObjTotalNumber++; 1505 xmlXPathDebugObjCounterNumber++; 1506 if (xmlXPathDebugObjCounterNumber > 1507 xmlXPathDebugObjMaxNumber) 1508 xmlXPathDebugObjMaxNumber = 1509 xmlXPathDebugObjCounterNumber; 1510 break; 1511 case XPATH_STRING: 1512 if (! isCached) 1513 xmlXPathDebugObjTotalString++; 1514 xmlXPathDebugObjCounterString++; 1515 if (xmlXPathDebugObjCounterString > 1516 xmlXPathDebugObjMaxString) 1517 xmlXPathDebugObjMaxString = 1518 xmlXPathDebugObjCounterString; 1519 break; 1520 case XPATH_POINT: 1521 if (! isCached) 1522 xmlXPathDebugObjTotalPoint++; 1523 xmlXPathDebugObjCounterPoint++; 1524 if (xmlXPathDebugObjCounterPoint > 1525 xmlXPathDebugObjMaxPoint) 1526 xmlXPathDebugObjMaxPoint = 1527 xmlXPathDebugObjCounterPoint; 1528 break; 1529 case XPATH_RANGE: 1530 if (! isCached) 1531 xmlXPathDebugObjTotalRange++; 1532 xmlXPathDebugObjCounterRange++; 1533 if (xmlXPathDebugObjCounterRange > 1534 xmlXPathDebugObjMaxRange) 1535 xmlXPathDebugObjMaxRange = 1536 xmlXPathDebugObjCounterRange; 1537 break; 1538 case XPATH_LOCATIONSET: 1539 if (! isCached) 1540 xmlXPathDebugObjTotalLocset++; 1541 xmlXPathDebugObjCounterLocset++; 1542 if (xmlXPathDebugObjCounterLocset > 1543 xmlXPathDebugObjMaxLocset) 1544 xmlXPathDebugObjMaxLocset = 1545 xmlXPathDebugObjCounterLocset; 1546 break; 1547 case XPATH_USERS: 1548 if (! isCached) 1549 xmlXPathDebugObjTotalUsers++; 1550 xmlXPathDebugObjCounterUsers++; 1551 if (xmlXPathDebugObjCounterUsers > 1552 xmlXPathDebugObjMaxUsers) 1553 xmlXPathDebugObjMaxUsers = 1554 xmlXPathDebugObjCounterUsers; 1555 break; 1556 case XPATH_XSLT_TREE: 1557 if (! isCached) 1558 xmlXPathDebugObjTotalXSLTTree++; 1559 xmlXPathDebugObjCounterXSLTTree++; 1560 if (xmlXPathDebugObjCounterXSLTTree > 1561 xmlXPathDebugObjMaxXSLTTree) 1562 xmlXPathDebugObjMaxXSLTTree = 1563 xmlXPathDebugObjCounterXSLTTree; 1564 break; 1565 default: 1566 break; 1567 } 1568 if (! isCached) 1569 xmlXPathDebugObjTotalAll++; 1570 xmlXPathDebugObjCounterAll++; 1571 if (xmlXPathDebugObjCounterAll > 1572 xmlXPathDebugObjMaxAll) 1573 xmlXPathDebugObjMaxAll = 1574 xmlXPathDebugObjCounterAll; 1575} 1576 1577static void 1578xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1579 xmlXPathObjectType objType) 1580{ 1581 int isCached = 0; 1582 1583 if (ctxt != NULL) { 1584 if (ctxt->cache != NULL) { 1585 xmlXPathContextCachePtr cache = 1586 (xmlXPathContextCachePtr) ctxt->cache; 1587 1588 isCached = 1; 1589 1590 cache->dbgCachedAll++; 1591 switch (objType) { 1592 case XPATH_UNDEFINED: 1593 cache->dbgCachedUndefined++; 1594 break; 1595 case XPATH_NODESET: 1596 cache->dbgCachedNodeset++; 1597 break; 1598 case XPATH_BOOLEAN: 1599 cache->dbgCachedBool++; 1600 break; 1601 case XPATH_NUMBER: 1602 cache->dbgCachedNumber++; 1603 break; 1604 case XPATH_STRING: 1605 cache->dbgCachedString++; 1606 break; 1607 case XPATH_POINT: 1608 cache->dbgCachedPoint++; 1609 break; 1610 case XPATH_RANGE: 1611 cache->dbgCachedRange++; 1612 break; 1613 case XPATH_LOCATIONSET: 1614 cache->dbgCachedLocset++; 1615 break; 1616 case XPATH_USERS: 1617 cache->dbgCachedUsers++; 1618 break; 1619 case XPATH_XSLT_TREE: 1620 cache->dbgCachedXSLTTree++; 1621 break; 1622 default: 1623 break; 1624 } 1625 1626 } 1627 } 1628 switch (objType) { 1629 case XPATH_UNDEFINED: 1630 xmlXPathDebugObjCounterUndefined--; 1631 break; 1632 case XPATH_NODESET: 1633 xmlXPathDebugObjCounterNodeset--; 1634 break; 1635 case XPATH_BOOLEAN: 1636 xmlXPathDebugObjCounterBool--; 1637 break; 1638 case XPATH_NUMBER: 1639 xmlXPathDebugObjCounterNumber--; 1640 break; 1641 case XPATH_STRING: 1642 xmlXPathDebugObjCounterString--; 1643 break; 1644 case XPATH_POINT: 1645 xmlXPathDebugObjCounterPoint--; 1646 break; 1647 case XPATH_RANGE: 1648 xmlXPathDebugObjCounterRange--; 1649 break; 1650 case XPATH_LOCATIONSET: 1651 xmlXPathDebugObjCounterLocset--; 1652 break; 1653 case XPATH_USERS: 1654 xmlXPathDebugObjCounterUsers--; 1655 break; 1656 case XPATH_XSLT_TREE: 1657 xmlXPathDebugObjCounterXSLTTree--; 1658 break; 1659 default: 1660 break; 1661 } 1662 xmlXPathDebugObjCounterAll--; 1663} 1664 1665/* REVISIT TODO: Make this static when committing */ 1666static void 1667xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 1668{ 1669 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 1670 reqXSLTTree, reqUndefined; 1671 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 1672 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 1673 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 1674 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 1675 int leftObjs = xmlXPathDebugObjCounterAll; 1676 1677 reqAll = xmlXPathDebugObjTotalAll; 1678 reqNodeset = xmlXPathDebugObjTotalNodeset; 1679 reqString = xmlXPathDebugObjTotalString; 1680 reqBool = xmlXPathDebugObjTotalBool; 1681 reqNumber = xmlXPathDebugObjTotalNumber; 1682 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 1683 reqUndefined = xmlXPathDebugObjTotalUndefined; 1684 1685 printf("# XPath object usage:\n"); 1686 1687 if (ctxt != NULL) { 1688 if (ctxt->cache != NULL) { 1689 xmlXPathContextCachePtr cache = 1690 (xmlXPathContextCachePtr) ctxt->cache; 1691 1692 reAll = cache->dbgReusedAll; 1693 reqAll += reAll; 1694 reNodeset = cache->dbgReusedNodeset; 1695 reqNodeset += reNodeset; 1696 reString = cache->dbgReusedString; 1697 reqString += reString; 1698 reBool = cache->dbgReusedBool; 1699 reqBool += reBool; 1700 reNumber = cache->dbgReusedNumber; 1701 reqNumber += reNumber; 1702 reXSLTTree = cache->dbgReusedXSLTTree; 1703 reqXSLTTree += reXSLTTree; 1704 reUndefined = cache->dbgReusedUndefined; 1705 reqUndefined += reUndefined; 1706 1707 caAll = cache->dbgCachedAll; 1708 caBool = cache->dbgCachedBool; 1709 caNodeset = cache->dbgCachedNodeset; 1710 caString = cache->dbgCachedString; 1711 caNumber = cache->dbgCachedNumber; 1712 caXSLTTree = cache->dbgCachedXSLTTree; 1713 caUndefined = cache->dbgCachedUndefined; 1714 1715 if (cache->nodesetObjs) 1716 leftObjs -= cache->nodesetObjs->number; 1717 if (cache->stringObjs) 1718 leftObjs -= cache->stringObjs->number; 1719 if (cache->booleanObjs) 1720 leftObjs -= cache->booleanObjs->number; 1721 if (cache->numberObjs) 1722 leftObjs -= cache->numberObjs->number; 1723 if (cache->miscObjs) 1724 leftObjs -= cache->miscObjs->number; 1725 } 1726 } 1727 1728 printf("# all\n"); 1729 printf("# total : %d\n", reqAll); 1730 printf("# left : %d\n", leftObjs); 1731 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 1732 printf("# reused : %d\n", reAll); 1733 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 1734 1735 printf("# node-sets\n"); 1736 printf("# total : %d\n", reqNodeset); 1737 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 1738 printf("# reused : %d\n", reNodeset); 1739 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 1740 1741 printf("# strings\n"); 1742 printf("# total : %d\n", reqString); 1743 printf("# created: %d\n", xmlXPathDebugObjTotalString); 1744 printf("# reused : %d\n", reString); 1745 printf("# max : %d\n", xmlXPathDebugObjMaxString); 1746 1747 printf("# booleans\n"); 1748 printf("# total : %d\n", reqBool); 1749 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 1750 printf("# reused : %d\n", reBool); 1751 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 1752 1753 printf("# numbers\n"); 1754 printf("# total : %d\n", reqNumber); 1755 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 1756 printf("# reused : %d\n", reNumber); 1757 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 1758 1759 printf("# XSLT result tree fragments\n"); 1760 printf("# total : %d\n", reqXSLTTree); 1761 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 1762 printf("# reused : %d\n", reXSLTTree); 1763 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 1764 1765 printf("# undefined\n"); 1766 printf("# total : %d\n", reqUndefined); 1767 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 1768 printf("# reused : %d\n", reUndefined); 1769 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 1770 1771} 1772 1773#endif /* XP_DEBUG_OBJ_USAGE */ 1774 1775#endif /* LIBXML_DEBUG_ENABLED */ 1776 1777/************************************************************************ 1778 * * 1779 * XPath object caching * 1780 * * 1781 ************************************************************************/ 1782 1783/** 1784 * xmlXPathNewCache: 1785 * 1786 * Create a new object cache 1787 * 1788 * Returns the xmlXPathCache just allocated. 1789 */ 1790static xmlXPathContextCachePtr 1791xmlXPathNewCache(void) 1792{ 1793 xmlXPathContextCachePtr ret; 1794 1795 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 1796 if (ret == NULL) { 1797 xmlXPathErrMemory(NULL, "creating object cache\n"); 1798 return(NULL); 1799 } 1800 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 1801 ret->maxNodeset = 100; 1802 ret->maxString = 100; 1803 ret->maxBoolean = 100; 1804 ret->maxNumber = 100; 1805 ret->maxMisc = 100; 1806 return(ret); 1807} 1808 1809static void 1810xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 1811{ 1812 int i; 1813 xmlXPathObjectPtr obj; 1814 1815 if (list == NULL) 1816 return; 1817 1818 for (i = 0; i < list->number; i++) { 1819 obj = list->items[i]; 1820 /* 1821 * Note that it is already assured that we don't need to 1822 * look out for namespace nodes in the node-set. 1823 */ 1824 if (obj->nodesetval != NULL) { 1825 if (obj->nodesetval->nodeTab != NULL) 1826 xmlFree(obj->nodesetval->nodeTab); 1827 xmlFree(obj->nodesetval); 1828 } 1829 xmlFree(obj); 1830#ifdef XP_DEBUG_OBJ_USAGE 1831 xmlXPathDebugObjCounterAll--; 1832#endif 1833 } 1834 xmlPointerListFree(list); 1835} 1836 1837static void 1838xmlXPathFreeCache(xmlXPathContextCachePtr cache) 1839{ 1840 if (cache == NULL) 1841 return; 1842 if (cache->nodesetObjs) 1843 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 1844 if (cache->stringObjs) 1845 xmlXPathCacheFreeObjectList(cache->stringObjs); 1846 if (cache->booleanObjs) 1847 xmlXPathCacheFreeObjectList(cache->booleanObjs); 1848 if (cache->numberObjs) 1849 xmlXPathCacheFreeObjectList(cache->numberObjs); 1850 if (cache->miscObjs) 1851 xmlXPathCacheFreeObjectList(cache->miscObjs); 1852 xmlFree(cache); 1853} 1854 1855/** 1856 * xmlXPathContextSetCache: 1857 * 1858 * @ctxt: the XPath context 1859 * @active: enables/disables (creates/frees) the cache 1860 * @value: a value with semantics dependant on @options 1861 * @options: options (currently only the value 0 is used) 1862 * 1863 * Creates/frees an object cache on the XPath context. 1864 * If activates XPath objects (xmlXPathObject) will be cached internally 1865 * to be reused. 1866 * @options: 1867 * 0: This will set the XPath object caching: 1868 * @value: 1869 * This will set the maximum number of XPath objects 1870 * to be cached per slot 1871 * There are 5 slots for: node-set, string, number, boolean, and 1872 * misc objects. Use <0 for the default number (100). 1873 * Other values for @options have currently no effect. 1874 * 1875 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 1876 */ 1877int 1878xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 1879 int active, 1880 int value, 1881 int options) 1882{ 1883 if (ctxt == NULL) 1884 return(-1); 1885 if (active) { 1886 xmlXPathContextCachePtr cache; 1887 1888 if (ctxt->cache == NULL) { 1889 ctxt->cache = xmlXPathNewCache(); 1890 if (ctxt->cache == NULL) 1891 return(-1); 1892 } 1893 cache = (xmlXPathContextCachePtr) ctxt->cache; 1894 if (options == 0) { 1895 if (value < 0) 1896 value = 100; 1897 cache->maxNodeset = value; 1898 cache->maxString = value; 1899 cache->maxNumber = value; 1900 cache->maxBoolean = value; 1901 cache->maxMisc = value; 1902 } 1903 } else if (ctxt->cache != NULL) { 1904 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 1905 ctxt->cache = NULL; 1906 } 1907 return(0); 1908} 1909 1910/** 1911 * xmlXPathCacheWrapNodeSet: 1912 * @ctxt: the XPath context 1913 * @val: the NodePtr value 1914 * 1915 * This is the cached version of xmlXPathWrapNodeSet(). 1916 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 1917 * 1918 * Returns the created or reused object. 1919 */ 1920static xmlXPathObjectPtr 1921xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 1922{ 1923 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1924 xmlXPathContextCachePtr cache = 1925 (xmlXPathContextCachePtr) ctxt->cache; 1926 1927 if ((cache->miscObjs != NULL) && 1928 (cache->miscObjs->number != 0)) 1929 { 1930 xmlXPathObjectPtr ret; 1931 1932 ret = (xmlXPathObjectPtr) 1933 cache->miscObjs->items[--cache->miscObjs->number]; 1934 ret->type = XPATH_NODESET; 1935 ret->nodesetval = val; 1936#ifdef XP_DEBUG_OBJ_USAGE 1937 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 1938#endif 1939 return(ret); 1940 } 1941 } 1942 1943 return(xmlXPathWrapNodeSet(val)); 1944 1945} 1946 1947/** 1948 * xmlXPathCacheWrapString: 1949 * @ctxt: the XPath context 1950 * @val: the xmlChar * value 1951 * 1952 * This is the cached version of xmlXPathWrapString(). 1953 * Wraps the @val string into an XPath object. 1954 * 1955 * Returns the created or reused object. 1956 */ 1957static xmlXPathObjectPtr 1958xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 1959{ 1960 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1961 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 1962 1963 if ((cache->stringObjs != NULL) && 1964 (cache->stringObjs->number != 0)) 1965 { 1966 1967 xmlXPathObjectPtr ret; 1968 1969 ret = (xmlXPathObjectPtr) 1970 cache->stringObjs->items[--cache->stringObjs->number]; 1971 ret->type = XPATH_STRING; 1972 ret->stringval = val; 1973#ifdef XP_DEBUG_OBJ_USAGE 1974 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1975#endif 1976 return(ret); 1977 } else if ((cache->miscObjs != NULL) && 1978 (cache->miscObjs->number != 0)) 1979 { 1980 xmlXPathObjectPtr ret; 1981 /* 1982 * Fallback to misc-cache. 1983 */ 1984 ret = (xmlXPathObjectPtr) 1985 cache->miscObjs->items[--cache->miscObjs->number]; 1986 1987 ret->type = XPATH_STRING; 1988 ret->stringval = val; 1989#ifdef XP_DEBUG_OBJ_USAGE 1990 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1991#endif 1992 return(ret); 1993 } 1994 } 1995 return(xmlXPathWrapString(val)); 1996} 1997 1998/** 1999 * xmlXPathCacheNewNodeSet: 2000 * @ctxt: the XPath context 2001 * @val: the NodePtr value 2002 * 2003 * This is the cached version of xmlXPathNewNodeSet(). 2004 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2005 * it with the single Node @val 2006 * 2007 * Returns the created or reused object. 2008 */ 2009static xmlXPathObjectPtr 2010xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2011{ 2012 if ((ctxt != NULL) && (ctxt->cache)) { 2013 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2014 2015 if ((cache->nodesetObjs != NULL) && 2016 (cache->nodesetObjs->number != 0)) 2017 { 2018 xmlXPathObjectPtr ret; 2019 /* 2020 * Use the nodset-cache. 2021 */ 2022 ret = (xmlXPathObjectPtr) 2023 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2024 ret->type = XPATH_NODESET; 2025 ret->boolval = 0; 2026 if (val) { 2027 if ((ret->nodesetval->nodeMax == 0) || 2028 (val->type == XML_NAMESPACE_DECL)) 2029 { 2030 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2031 } else { 2032 ret->nodesetval->nodeTab[0] = val; 2033 ret->nodesetval->nodeNr = 1; 2034 } 2035 } 2036#ifdef XP_DEBUG_OBJ_USAGE 2037 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2038#endif 2039 return(ret); 2040 } else if ((cache->miscObjs != NULL) && 2041 (cache->miscObjs->number != 0)) 2042 { 2043 xmlXPathObjectPtr ret; 2044 /* 2045 * Fallback to misc-cache. 2046 */ 2047 2048 ret = (xmlXPathObjectPtr) 2049 cache->miscObjs->items[--cache->miscObjs->number]; 2050 2051 ret->type = XPATH_NODESET; 2052 ret->boolval = 0; 2053 ret->nodesetval = xmlXPathNodeSetCreate(val); 2054#ifdef XP_DEBUG_OBJ_USAGE 2055 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2056#endif 2057 return(ret); 2058 } 2059 } 2060 return(xmlXPathNewNodeSet(val)); 2061} 2062 2063/** 2064 * xmlXPathCacheNewCString: 2065 * @ctxt: the XPath context 2066 * @val: the char * value 2067 * 2068 * This is the cached version of xmlXPathNewCString(). 2069 * Acquire an xmlXPathObjectPtr of type string and of value @val 2070 * 2071 * Returns the created or reused object. 2072 */ 2073static xmlXPathObjectPtr 2074xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2075{ 2076 if ((ctxt != NULL) && (ctxt->cache)) { 2077 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2078 2079 if ((cache->stringObjs != NULL) && 2080 (cache->stringObjs->number != 0)) 2081 { 2082 xmlXPathObjectPtr ret; 2083 2084 ret = (xmlXPathObjectPtr) 2085 cache->stringObjs->items[--cache->stringObjs->number]; 2086 2087 ret->type = XPATH_STRING; 2088 ret->stringval = xmlStrdup(BAD_CAST val); 2089#ifdef XP_DEBUG_OBJ_USAGE 2090 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2091#endif 2092 return(ret); 2093 } else if ((cache->miscObjs != NULL) && 2094 (cache->miscObjs->number != 0)) 2095 { 2096 xmlXPathObjectPtr ret; 2097 2098 ret = (xmlXPathObjectPtr) 2099 cache->miscObjs->items[--cache->miscObjs->number]; 2100 2101 ret->type = XPATH_STRING; 2102 ret->stringval = xmlStrdup(BAD_CAST val); 2103#ifdef XP_DEBUG_OBJ_USAGE 2104 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2105#endif 2106 return(ret); 2107 } 2108 } 2109 return(xmlXPathNewCString(val)); 2110} 2111 2112/** 2113 * xmlXPathCacheNewString: 2114 * @ctxt: the XPath context 2115 * @val: the xmlChar * value 2116 * 2117 * This is the cached version of xmlXPathNewString(). 2118 * Acquire an xmlXPathObjectPtr of type string and of value @val 2119 * 2120 * Returns the created or reused object. 2121 */ 2122static xmlXPathObjectPtr 2123xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2124{ 2125 if ((ctxt != NULL) && (ctxt->cache)) { 2126 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2127 2128 if ((cache->stringObjs != NULL) && 2129 (cache->stringObjs->number != 0)) 2130 { 2131 xmlXPathObjectPtr ret; 2132 2133 ret = (xmlXPathObjectPtr) 2134 cache->stringObjs->items[--cache->stringObjs->number]; 2135 ret->type = XPATH_STRING; 2136 if (val != NULL) 2137 ret->stringval = xmlStrdup(val); 2138 else 2139 ret->stringval = xmlStrdup((const xmlChar *)""); 2140#ifdef XP_DEBUG_OBJ_USAGE 2141 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2142#endif 2143 return(ret); 2144 } else if ((cache->miscObjs != NULL) && 2145 (cache->miscObjs->number != 0)) 2146 { 2147 xmlXPathObjectPtr ret; 2148 2149 ret = (xmlXPathObjectPtr) 2150 cache->miscObjs->items[--cache->miscObjs->number]; 2151 2152 ret->type = XPATH_STRING; 2153 if (val != NULL) 2154 ret->stringval = xmlStrdup(val); 2155 else 2156 ret->stringval = xmlStrdup((const xmlChar *)""); 2157#ifdef XP_DEBUG_OBJ_USAGE 2158 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2159#endif 2160 return(ret); 2161 } 2162 } 2163 return(xmlXPathNewString(val)); 2164} 2165 2166/** 2167 * xmlXPathCacheNewBoolean: 2168 * @ctxt: the XPath context 2169 * @val: the boolean value 2170 * 2171 * This is the cached version of xmlXPathNewBoolean(). 2172 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2173 * 2174 * Returns the created or reused object. 2175 */ 2176static xmlXPathObjectPtr 2177xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2178{ 2179 if ((ctxt != NULL) && (ctxt->cache)) { 2180 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2181 2182 if ((cache->booleanObjs != NULL) && 2183 (cache->booleanObjs->number != 0)) 2184 { 2185 xmlXPathObjectPtr ret; 2186 2187 ret = (xmlXPathObjectPtr) 2188 cache->booleanObjs->items[--cache->booleanObjs->number]; 2189 ret->type = XPATH_BOOLEAN; 2190 ret->boolval = (val != 0); 2191#ifdef XP_DEBUG_OBJ_USAGE 2192 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2193#endif 2194 return(ret); 2195 } else if ((cache->miscObjs != NULL) && 2196 (cache->miscObjs->number != 0)) 2197 { 2198 xmlXPathObjectPtr ret; 2199 2200 ret = (xmlXPathObjectPtr) 2201 cache->miscObjs->items[--cache->miscObjs->number]; 2202 2203 ret->type = XPATH_BOOLEAN; 2204 ret->boolval = (val != 0); 2205#ifdef XP_DEBUG_OBJ_USAGE 2206 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2207#endif 2208 return(ret); 2209 } 2210 } 2211 return(xmlXPathNewBoolean(val)); 2212} 2213 2214/** 2215 * xmlXPathCacheNewFloat: 2216 * @ctxt: the XPath context 2217 * @val: the double value 2218 * 2219 * This is the cached version of xmlXPathNewFloat(). 2220 * Acquires an xmlXPathObjectPtr of type double and of value @val 2221 * 2222 * Returns the created or reused object. 2223 */ 2224static xmlXPathObjectPtr 2225xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2226{ 2227 if ((ctxt != NULL) && (ctxt->cache)) { 2228 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2229 2230 if ((cache->numberObjs != NULL) && 2231 (cache->numberObjs->number != 0)) 2232 { 2233 xmlXPathObjectPtr ret; 2234 2235 ret = (xmlXPathObjectPtr) 2236 cache->numberObjs->items[--cache->numberObjs->number]; 2237 ret->type = XPATH_NUMBER; 2238 ret->floatval = val; 2239#ifdef XP_DEBUG_OBJ_USAGE 2240 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2241#endif 2242 return(ret); 2243 } else if ((cache->miscObjs != NULL) && 2244 (cache->miscObjs->number != 0)) 2245 { 2246 xmlXPathObjectPtr ret; 2247 2248 ret = (xmlXPathObjectPtr) 2249 cache->miscObjs->items[--cache->miscObjs->number]; 2250 2251 ret->type = XPATH_NUMBER; 2252 ret->floatval = val; 2253#ifdef XP_DEBUG_OBJ_USAGE 2254 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2255#endif 2256 return(ret); 2257 } 2258 } 2259 return(xmlXPathNewFloat(val)); 2260} 2261 2262/** 2263 * xmlXPathCacheConvertString: 2264 * @ctxt: the XPath context 2265 * @val: an XPath object 2266 * 2267 * This is the cached version of xmlXPathConvertString(). 2268 * Converts an existing object to its string() equivalent 2269 * 2270 * Returns a created or reused object, the old one is freed (cached) 2271 * (or the operation is done directly on @val) 2272 */ 2273 2274static xmlXPathObjectPtr 2275xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2276 xmlChar *res = NULL; 2277 2278 if (val == NULL) 2279 return(xmlXPathCacheNewCString(ctxt, "")); 2280 2281 switch (val->type) { 2282 case XPATH_UNDEFINED: 2283#ifdef DEBUG_EXPR 2284 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2285#endif 2286 break; 2287 case XPATH_NODESET: 2288 case XPATH_XSLT_TREE: 2289 res = xmlXPathCastNodeSetToString(val->nodesetval); 2290 break; 2291 case XPATH_STRING: 2292 return(val); 2293 case XPATH_BOOLEAN: 2294 res = xmlXPathCastBooleanToString(val->boolval); 2295 break; 2296 case XPATH_NUMBER: 2297 res = xmlXPathCastNumberToString(val->floatval); 2298 break; 2299 case XPATH_USERS: 2300 case XPATH_POINT: 2301 case XPATH_RANGE: 2302 case XPATH_LOCATIONSET: 2303 TODO; 2304 break; 2305 } 2306 xmlXPathReleaseObject(ctxt, val); 2307 if (res == NULL) 2308 return(xmlXPathCacheNewCString(ctxt, "")); 2309 return(xmlXPathCacheWrapString(ctxt, res)); 2310} 2311 2312/** 2313 * xmlXPathCacheObjectCopy: 2314 * @ctxt: the XPath context 2315 * @val: the original object 2316 * 2317 * This is the cached version of xmlXPathObjectCopy(). 2318 * Acquire a copy of a given object 2319 * 2320 * Returns a created or reused created object. 2321 */ 2322static xmlXPathObjectPtr 2323xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2324{ 2325 if (val == NULL) 2326 return(NULL); 2327 2328 if (XP_HAS_CACHE(ctxt)) { 2329 switch (val->type) { 2330 case XPATH_NODESET: 2331 return(xmlXPathCacheWrapNodeSet(ctxt, 2332 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2333 case XPATH_STRING: 2334 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2335 case XPATH_BOOLEAN: 2336 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2337 case XPATH_NUMBER: 2338 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2339 default: 2340 break; 2341 } 2342 } 2343 return(xmlXPathObjectCopy(val)); 2344} 2345 2346/** 2347 * xmlXPathCacheConvertBoolean: 2348 * @ctxt: the XPath context 2349 * @val: an XPath object 2350 * 2351 * This is the cached version of xmlXPathConvertBoolean(). 2352 * Converts an existing object to its boolean() equivalent 2353 * 2354 * Returns a created or reused object, the old one is freed (or the operation 2355 * is done directly on @val) 2356 */ 2357static xmlXPathObjectPtr 2358xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2359 xmlXPathObjectPtr ret; 2360 2361 if (val == NULL) 2362 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2363 if (val->type == XPATH_BOOLEAN) 2364 return(val); 2365 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2366 xmlXPathReleaseObject(ctxt, val); 2367 return(ret); 2368} 2369 2370/** 2371 * xmlXPathCacheConvertNumber: 2372 * @ctxt: the XPath context 2373 * @val: an XPath object 2374 * 2375 * This is the cached version of xmlXPathConvertNumber(). 2376 * Converts an existing object to its number() equivalent 2377 * 2378 * Returns a created or reused object, the old one is freed (or the operation 2379 * is done directly on @val) 2380 */ 2381static xmlXPathObjectPtr 2382xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2383 xmlXPathObjectPtr ret; 2384 2385 if (val == NULL) 2386 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2387 if (val->type == XPATH_NUMBER) 2388 return(val); 2389 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2390 xmlXPathReleaseObject(ctxt, val); 2391 return(ret); 2392} 2393 2394/************************************************************************ 2395 * * 2396 * Parser stacks related functions and macros * 2397 * * 2398 ************************************************************************/ 2399 2400/** 2401 * valuePop: 2402 * @ctxt: an XPath evaluation context 2403 * 2404 * Pops the top XPath object from the value stack 2405 * 2406 * Returns the XPath object just removed 2407 */ 2408xmlXPathObjectPtr 2409valuePop(xmlXPathParserContextPtr ctxt) 2410{ 2411 xmlXPathObjectPtr ret; 2412 2413 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2414 return (NULL); 2415 ctxt->valueNr--; 2416 if (ctxt->valueNr > 0) 2417 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2418 else 2419 ctxt->value = NULL; 2420 ret = ctxt->valueTab[ctxt->valueNr]; 2421 ctxt->valueTab[ctxt->valueNr] = NULL; 2422 return (ret); 2423} 2424/** 2425 * valuePush: 2426 * @ctxt: an XPath evaluation context 2427 * @value: the XPath object 2428 * 2429 * Pushes a new XPath object on top of the value stack 2430 * 2431 * returns the number of items on the value stack 2432 */ 2433int 2434valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2435{ 2436 if ((ctxt == NULL) || (value == NULL)) return(-1); 2437 if (ctxt->valueNr >= ctxt->valueMax) { 2438 xmlXPathObjectPtr *tmp; 2439 2440 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2441 2 * ctxt->valueMax * 2442 sizeof(ctxt->valueTab[0])); 2443 if (tmp == NULL) { 2444 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 2445 return (0); 2446 } 2447 ctxt->valueMax *= 2; 2448 ctxt->valueTab = tmp; 2449 } 2450 ctxt->valueTab[ctxt->valueNr] = value; 2451 ctxt->value = value; 2452 return (ctxt->valueNr++); 2453} 2454 2455/** 2456 * xmlXPathPopBoolean: 2457 * @ctxt: an XPath parser context 2458 * 2459 * Pops a boolean from the stack, handling conversion if needed. 2460 * Check error with #xmlXPathCheckError. 2461 * 2462 * Returns the boolean 2463 */ 2464int 2465xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2466 xmlXPathObjectPtr obj; 2467 int ret; 2468 2469 obj = valuePop(ctxt); 2470 if (obj == NULL) { 2471 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2472 return(0); 2473 } 2474 if (obj->type != XPATH_BOOLEAN) 2475 ret = xmlXPathCastToBoolean(obj); 2476 else 2477 ret = obj->boolval; 2478 xmlXPathReleaseObject(ctxt->context, obj); 2479 return(ret); 2480} 2481 2482/** 2483 * xmlXPathPopNumber: 2484 * @ctxt: an XPath parser context 2485 * 2486 * Pops a number from the stack, handling conversion if needed. 2487 * Check error with #xmlXPathCheckError. 2488 * 2489 * Returns the number 2490 */ 2491double 2492xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2493 xmlXPathObjectPtr obj; 2494 double ret; 2495 2496 obj = valuePop(ctxt); 2497 if (obj == NULL) { 2498 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2499 return(0); 2500 } 2501 if (obj->type != XPATH_NUMBER) 2502 ret = xmlXPathCastToNumber(obj); 2503 else 2504 ret = obj->floatval; 2505 xmlXPathReleaseObject(ctxt->context, obj); 2506 return(ret); 2507} 2508 2509/** 2510 * xmlXPathPopString: 2511 * @ctxt: an XPath parser context 2512 * 2513 * Pops a string from the stack, handling conversion if needed. 2514 * Check error with #xmlXPathCheckError. 2515 * 2516 * Returns the string 2517 */ 2518xmlChar * 2519xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2520 xmlXPathObjectPtr obj; 2521 xmlChar * ret; 2522 2523 obj = valuePop(ctxt); 2524 if (obj == NULL) { 2525 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2526 return(NULL); 2527 } 2528 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2529 /* TODO: needs refactoring somewhere else */ 2530 if (obj->stringval == ret) 2531 obj->stringval = NULL; 2532 xmlXPathReleaseObject(ctxt->context, obj); 2533 return(ret); 2534} 2535 2536/** 2537 * xmlXPathPopNodeSet: 2538 * @ctxt: an XPath parser context 2539 * 2540 * Pops a node-set from the stack, handling conversion if needed. 2541 * Check error with #xmlXPathCheckError. 2542 * 2543 * Returns the node-set 2544 */ 2545xmlNodeSetPtr 2546xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 2547 xmlXPathObjectPtr obj; 2548 xmlNodeSetPtr ret; 2549 2550 if (ctxt == NULL) return(NULL); 2551 if (ctxt->value == NULL) { 2552 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2553 return(NULL); 2554 } 2555 if (!xmlXPathStackIsNodeSet(ctxt)) { 2556 xmlXPathSetTypeError(ctxt); 2557 return(NULL); 2558 } 2559 obj = valuePop(ctxt); 2560 ret = obj->nodesetval; 2561#if 0 2562 /* to fix memory leak of not clearing obj->user */ 2563 if (obj->boolval && obj->user != NULL) 2564 xmlFreeNodeList((xmlNodePtr) obj->user); 2565#endif 2566 obj->nodesetval = NULL; 2567 xmlXPathReleaseObject(ctxt->context, obj); 2568 return(ret); 2569} 2570 2571/** 2572 * xmlXPathPopExternal: 2573 * @ctxt: an XPath parser context 2574 * 2575 * Pops an external object from the stack, handling conversion if needed. 2576 * Check error with #xmlXPathCheckError. 2577 * 2578 * Returns the object 2579 */ 2580void * 2581xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 2582 xmlXPathObjectPtr obj; 2583 void * ret; 2584 2585 if ((ctxt == NULL) || (ctxt->value == NULL)) { 2586 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2587 return(NULL); 2588 } 2589 if (ctxt->value->type != XPATH_USERS) { 2590 xmlXPathSetTypeError(ctxt); 2591 return(NULL); 2592 } 2593 obj = valuePop(ctxt); 2594 ret = obj->user; 2595 obj->user = NULL; 2596 xmlXPathReleaseObject(ctxt->context, obj); 2597 return(ret); 2598} 2599 2600/* 2601 * Macros for accessing the content. Those should be used only by the parser, 2602 * and not exported. 2603 * 2604 * Dirty macros, i.e. one need to make assumption on the context to use them 2605 * 2606 * CUR_PTR return the current pointer to the xmlChar to be parsed. 2607 * CUR returns the current xmlChar value, i.e. a 8 bit value 2608 * in ISO-Latin or UTF-8. 2609 * This should be used internally by the parser 2610 * only to compare to ASCII values otherwise it would break when 2611 * running with UTF-8 encoding. 2612 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 2613 * to compare on ASCII based substring. 2614 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 2615 * strings within the parser. 2616 * CURRENT Returns the current char value, with the full decoding of 2617 * UTF-8 if we are using this mode. It returns an int. 2618 * NEXT Skip to the next character, this does the proper decoding 2619 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 2620 * It returns the pointer to the current xmlChar. 2621 */ 2622 2623#define CUR (*ctxt->cur) 2624#define SKIP(val) ctxt->cur += (val) 2625#define NXT(val) ctxt->cur[(val)] 2626#define CUR_PTR ctxt->cur 2627#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 2628 2629#define COPY_BUF(l,b,i,v) \ 2630 if (l == 1) b[i++] = (xmlChar) v; \ 2631 else i += xmlCopyChar(l,&b[i],v) 2632 2633#define NEXTL(l) ctxt->cur += l 2634 2635#define SKIP_BLANKS \ 2636 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 2637 2638#define CURRENT (*ctxt->cur) 2639#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 2640 2641 2642#ifndef DBL_DIG 2643#define DBL_DIG 16 2644#endif 2645#ifndef DBL_EPSILON 2646#define DBL_EPSILON 1E-9 2647#endif 2648 2649#define UPPER_DOUBLE 1E9 2650#define LOWER_DOUBLE 1E-5 2651#define LOWER_DOUBLE_EXP 5 2652 2653#define INTEGER_DIGITS DBL_DIG 2654#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 2655#define EXPONENT_DIGITS (3 + 2) 2656 2657/** 2658 * xmlXPathFormatNumber: 2659 * @number: number to format 2660 * @buffer: output buffer 2661 * @buffersize: size of output buffer 2662 * 2663 * Convert the number into a string representation. 2664 */ 2665static void 2666xmlXPathFormatNumber(double number, char buffer[], int buffersize) 2667{ 2668 switch (xmlXPathIsInf(number)) { 2669 case 1: 2670 if (buffersize > (int)sizeof("Infinity")) 2671 snprintf(buffer, buffersize, "Infinity"); 2672 break; 2673 case -1: 2674 if (buffersize > (int)sizeof("-Infinity")) 2675 snprintf(buffer, buffersize, "-Infinity"); 2676 break; 2677 default: 2678 if (xmlXPathIsNaN(number)) { 2679 if (buffersize > (int)sizeof("NaN")) 2680 snprintf(buffer, buffersize, "NaN"); 2681 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 2682 snprintf(buffer, buffersize, "0"); 2683 } else if (number == ((int) number)) { 2684 char work[30]; 2685 char *ptr, *cur; 2686 int value = (int) number; 2687 2688 ptr = &buffer[0]; 2689 if (value == 0) { 2690 *ptr++ = '0'; 2691 } else { 2692 snprintf(work, 29, "%d", value); 2693 cur = &work[0]; 2694 while ((*cur) && (ptr - buffer < buffersize)) { 2695 *ptr++ = *cur++; 2696 } 2697 } 2698 if (ptr - buffer < buffersize) { 2699 *ptr = 0; 2700 } else if (buffersize > 0) { 2701 ptr--; 2702 *ptr = 0; 2703 } 2704 } else { 2705 /* 2706 For the dimension of work, 2707 DBL_DIG is number of significant digits 2708 EXPONENT is only needed for "scientific notation" 2709 3 is sign, decimal point, and terminating zero 2710 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 2711 Note that this dimension is slightly (a few characters) 2712 larger than actually necessary. 2713 */ 2714 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 2715 int integer_place, fraction_place; 2716 char *ptr; 2717 char *after_fraction; 2718 double absolute_value; 2719 int size; 2720 2721 absolute_value = fabs(number); 2722 2723 /* 2724 * First choose format - scientific or regular floating point. 2725 * In either case, result is in work, and after_fraction points 2726 * just past the fractional part. 2727 */ 2728 if ( ((absolute_value > UPPER_DOUBLE) || 2729 (absolute_value < LOWER_DOUBLE)) && 2730 (absolute_value != 0.0) ) { 2731 /* Use scientific notation */ 2732 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 2733 fraction_place = DBL_DIG - 1; 2734 size = snprintf(work, sizeof(work),"%*.*e", 2735 integer_place, fraction_place, number); 2736 while ((size > 0) && (work[size] != 'e')) size--; 2737 2738 } 2739 else { 2740 /* Use regular notation */ 2741 if (absolute_value > 0.0) { 2742 integer_place = (int)log10(absolute_value); 2743 if (integer_place > 0) 2744 fraction_place = DBL_DIG - integer_place - 1; 2745 else 2746 fraction_place = DBL_DIG - integer_place; 2747 } else { 2748 fraction_place = 1; 2749 } 2750 size = snprintf(work, sizeof(work), "%0.*f", 2751 fraction_place, number); 2752 } 2753 2754 /* Remove fractional trailing zeroes */ 2755 after_fraction = work + size; 2756 ptr = after_fraction; 2757 while (*(--ptr) == '0') 2758 ; 2759 if (*ptr != '.') 2760 ptr++; 2761 while ((*ptr++ = *after_fraction++) != 0); 2762 2763 /* Finally copy result back to caller */ 2764 size = strlen(work) + 1; 2765 if (size > buffersize) { 2766 work[buffersize - 1] = 0; 2767 size = buffersize; 2768 } 2769 memmove(buffer, work, size); 2770 } 2771 break; 2772 } 2773} 2774 2775 2776/************************************************************************ 2777 * * 2778 * Routines to handle NodeSets * 2779 * * 2780 ************************************************************************/ 2781 2782/** 2783 * xmlXPathOrderDocElems: 2784 * @doc: an input document 2785 * 2786 * Call this routine to speed up XPath computation on static documents. 2787 * This stamps all the element nodes with the document order 2788 * Like for line information, the order is kept in the element->content 2789 * field, the value stored is actually - the node number (starting at -1) 2790 * to be able to differentiate from line numbers. 2791 * 2792 * Returns the number of elements found in the document or -1 in case 2793 * of error. 2794 */ 2795long 2796xmlXPathOrderDocElems(xmlDocPtr doc) { 2797 long count = 0; 2798 xmlNodePtr cur; 2799 2800 if (doc == NULL) 2801 return(-1); 2802 cur = doc->children; 2803 while (cur != NULL) { 2804 if (cur->type == XML_ELEMENT_NODE) { 2805 cur->content = (void *) (-(++count)); 2806 if (cur->children != NULL) { 2807 cur = cur->children; 2808 continue; 2809 } 2810 } 2811 if (cur->next != NULL) { 2812 cur = cur->next; 2813 continue; 2814 } 2815 do { 2816 cur = cur->parent; 2817 if (cur == NULL) 2818 break; 2819 if (cur == (xmlNodePtr) doc) { 2820 cur = NULL; 2821 break; 2822 } 2823 if (cur->next != NULL) { 2824 cur = cur->next; 2825 break; 2826 } 2827 } while (cur != NULL); 2828 } 2829 return(count); 2830} 2831 2832/** 2833 * xmlXPathCmpNodes: 2834 * @node1: the first node 2835 * @node2: the second node 2836 * 2837 * Compare two nodes w.r.t document order 2838 * 2839 * Returns -2 in case of error 1 if first point < second point, 0 if 2840 * it's the same node, -1 otherwise 2841 */ 2842int 2843xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 2844 int depth1, depth2; 2845 int attr1 = 0, attr2 = 0; 2846 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 2847 xmlNodePtr cur, root; 2848 2849 if ((node1 == NULL) || (node2 == NULL)) 2850 return(-2); 2851 /* 2852 * a couple of optimizations which will avoid computations in most cases 2853 */ 2854 if (node1 == node2) /* trivial case */ 2855 return(0); 2856 if (node1->type == XML_ATTRIBUTE_NODE) { 2857 attr1 = 1; 2858 attrNode1 = node1; 2859 node1 = node1->parent; 2860 } 2861 if (node2->type == XML_ATTRIBUTE_NODE) { 2862 attr2 = 1; 2863 attrNode2 = node2; 2864 node2 = node2->parent; 2865 } 2866 if (node1 == node2) { 2867 if (attr1 == attr2) { 2868 /* not required, but we keep attributes in order */ 2869 if (attr1 != 0) { 2870 cur = attrNode2->prev; 2871 while (cur != NULL) { 2872 if (cur == attrNode1) 2873 return (1); 2874 cur = cur->prev; 2875 } 2876 return (-1); 2877 } 2878 return(0); 2879 } 2880 if (attr2 == 1) 2881 return(1); 2882 return(-1); 2883 } 2884 if ((node1->type == XML_NAMESPACE_DECL) || 2885 (node2->type == XML_NAMESPACE_DECL)) 2886 return(1); 2887 if (node1 == node2->prev) 2888 return(1); 2889 if (node1 == node2->next) 2890 return(-1); 2891 2892 /* 2893 * Speedup using document order if availble. 2894 */ 2895 if ((node1->type == XML_ELEMENT_NODE) && 2896 (node2->type == XML_ELEMENT_NODE) && 2897 (0 > (long) node1->content) && 2898 (0 > (long) node2->content) && 2899 (node1->doc == node2->doc)) { 2900 long l1, l2; 2901 2902 l1 = -((long) node1->content); 2903 l2 = -((long) node2->content); 2904 if (l1 < l2) 2905 return(1); 2906 if (l1 > l2) 2907 return(-1); 2908 } 2909 2910 /* 2911 * compute depth to root 2912 */ 2913 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 2914 if (cur == node1) 2915 return(1); 2916 depth2++; 2917 } 2918 root = cur; 2919 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 2920 if (cur == node2) 2921 return(-1); 2922 depth1++; 2923 } 2924 /* 2925 * Distinct document (or distinct entities :-( ) case. 2926 */ 2927 if (root != cur) { 2928 return(-2); 2929 } 2930 /* 2931 * get the nearest common ancestor. 2932 */ 2933 while (depth1 > depth2) { 2934 depth1--; 2935 node1 = node1->parent; 2936 } 2937 while (depth2 > depth1) { 2938 depth2--; 2939 node2 = node2->parent; 2940 } 2941 while (node1->parent != node2->parent) { 2942 node1 = node1->parent; 2943 node2 = node2->parent; 2944 /* should not happen but just in case ... */ 2945 if ((node1 == NULL) || (node2 == NULL)) 2946 return(-2); 2947 } 2948 /* 2949 * Find who's first. 2950 */ 2951 if (node1 == node2->prev) 2952 return(1); 2953 if (node1 == node2->next) 2954 return(-1); 2955 /* 2956 * Speedup using document order if availble. 2957 */ 2958 if ((node1->type == XML_ELEMENT_NODE) && 2959 (node2->type == XML_ELEMENT_NODE) && 2960 (0 > (long) node1->content) && 2961 (0 > (long) node2->content) && 2962 (node1->doc == node2->doc)) { 2963 long l1, l2; 2964 2965 l1 = -((long) node1->content); 2966 l2 = -((long) node2->content); 2967 if (l1 < l2) 2968 return(1); 2969 if (l1 > l2) 2970 return(-1); 2971 } 2972 2973 for (cur = node1->next;cur != NULL;cur = cur->next) 2974 if (cur == node2) 2975 return(1); 2976 return(-1); /* assume there is no sibling list corruption */ 2977} 2978 2979#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 2980/** 2981 * xmlXPathCmpNodesExt: 2982 * @node1: the first node 2983 * @node2: the second node 2984 * 2985 * Compare two nodes w.r.t document order. 2986 * This one is optimized for handling of non-element nodes. 2987 * 2988 * Returns -2 in case of error 1 if first point < second point, 0 if 2989 * it's the same node, -1 otherwise 2990 */ 2991static int 2992xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 2993 int depth1, depth2; 2994 int misc = 0, precedence1 = 0, precedence2 = 0; 2995 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 2996 xmlNodePtr cur, root; 2997 long l1, l2; 2998 2999 if ((node1 == NULL) || (node2 == NULL)) 3000 return(-2); 3001 3002 if (node1 == node2) 3003 return(0); 3004 3005 /* 3006 * a couple of optimizations which will avoid computations in most cases 3007 */ 3008 switch (node1->type) { 3009 case XML_ELEMENT_NODE: 3010 if (node2->type == XML_ELEMENT_NODE) { 3011 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */ 3012 (0 > (long) node2->content) && 3013 (node1->doc == node2->doc)) 3014 { 3015 l1 = -((long) node1->content); 3016 l2 = -((long) node2->content); 3017 if (l1 < l2) 3018 return(1); 3019 if (l1 > l2) 3020 return(-1); 3021 } else 3022 goto turtle_comparison; 3023 } 3024 break; 3025 case XML_ATTRIBUTE_NODE: 3026 precedence1 = 1; /* element is owner */ 3027 miscNode1 = node1; 3028 node1 = node1->parent; 3029 misc = 1; 3030 break; 3031 case XML_TEXT_NODE: 3032 case XML_CDATA_SECTION_NODE: 3033 case XML_COMMENT_NODE: 3034 case XML_PI_NODE: { 3035 miscNode1 = node1; 3036 /* 3037 * Find nearest element node. 3038 */ 3039 if (node1->prev != NULL) { 3040 do { 3041 node1 = node1->prev; 3042 if (node1->type == XML_ELEMENT_NODE) { 3043 precedence1 = 3; /* element in prev-sibl axis */ 3044 break; 3045 } 3046 if (node1->prev == NULL) { 3047 precedence1 = 2; /* element is parent */ 3048 /* 3049 * URGENT TODO: Are there any cases, where the 3050 * parent of such a node is not an element node? 3051 */ 3052 node1 = node1->parent; 3053 break; 3054 } 3055 } while (1); 3056 } else { 3057 precedence1 = 2; /* element is parent */ 3058 node1 = node1->parent; 3059 } 3060 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 3061 (0 <= (long) node1->content)) { 3062 /* 3063 * Fallback for whatever case. 3064 */ 3065 node1 = miscNode1; 3066 precedence1 = 0; 3067 } else 3068 misc = 1; 3069 } 3070 break; 3071 case XML_NAMESPACE_DECL: 3072 /* 3073 * TODO: why do we return 1 for namespace nodes? 3074 */ 3075 return(1); 3076 default: 3077 break; 3078 } 3079 switch (node2->type) { 3080 case XML_ELEMENT_NODE: 3081 break; 3082 case XML_ATTRIBUTE_NODE: 3083 precedence2 = 1; /* element is owner */ 3084 miscNode2 = node2; 3085 node2 = node2->parent; 3086 misc = 1; 3087 break; 3088 case XML_TEXT_NODE: 3089 case XML_CDATA_SECTION_NODE: 3090 case XML_COMMENT_NODE: 3091 case XML_PI_NODE: { 3092 miscNode2 = node2; 3093 if (node2->prev != NULL) { 3094 do { 3095 node2 = node2->prev; 3096 if (node2->type == XML_ELEMENT_NODE) { 3097 precedence2 = 3; /* element in prev-sibl axis */ 3098 break; 3099 } 3100 if (node2->prev == NULL) { 3101 precedence2 = 2; /* element is parent */ 3102 node2 = node2->parent; 3103 break; 3104 } 3105 } while (1); 3106 } else { 3107 precedence2 = 2; /* element is parent */ 3108 node2 = node2->parent; 3109 } 3110 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 3111 (0 <= (long) node1->content)) 3112 { 3113 node2 = miscNode2; 3114 precedence2 = 0; 3115 } else 3116 misc = 1; 3117 } 3118 break; 3119 case XML_NAMESPACE_DECL: 3120 return(1); 3121 default: 3122 break; 3123 } 3124 if (misc) { 3125 if (node1 == node2) { 3126 if (precedence1 == precedence2) { 3127 /* 3128 * The ugly case; but normally there aren't many 3129 * adjacent non-element nodes around. 3130 */ 3131 cur = miscNode2->prev; 3132 while (cur != NULL) { 3133 if (cur == miscNode1) 3134 return(1); 3135 if (cur->type == XML_ELEMENT_NODE) 3136 return(-1); 3137 cur = cur->prev; 3138 } 3139 return (-1); 3140 } else { 3141 /* 3142 * Evaluate based on higher precedence wrt to the element. 3143 * TODO: This assumes attributes are sorted before content. 3144 * Is this 100% correct? 3145 */ 3146 if (precedence1 < precedence2) 3147 return(1); 3148 else 3149 return(-1); 3150 } 3151 } 3152 /* 3153 * Special case: One of the helper-elements is contained by the other. 3154 * <foo> 3155 * <node2> 3156 * <node1>Text-1(precedence1 == 2)</node1> 3157 * </node2> 3158 * Text-6(precedence2 == 3) 3159 * </foo> 3160 */ 3161 if ((precedence2 == 3) && (precedence1 > 1)) { 3162 cur = node1->parent; 3163 while (cur) { 3164 if (cur == node2) 3165 return(1); 3166 cur = cur->parent; 3167 } 3168 } 3169 if ((precedence1 == 3) && (precedence2 > 1)) { 3170 cur = node2->parent; 3171 while (cur) { 3172 if (cur == node1) 3173 return(-1); 3174 cur = cur->parent; 3175 } 3176 } 3177 } 3178 3179 /* 3180 * Speedup using document order if availble. 3181 */ 3182 if ((node1->type == XML_ELEMENT_NODE) && 3183 (node2->type == XML_ELEMENT_NODE) && 3184 (0 > (long) node1->content) && 3185 (0 > (long) node2->content) && 3186 (node1->doc == node2->doc)) { 3187 3188 l1 = -((long) node1->content); 3189 l2 = -((long) node2->content); 3190 if (l1 < l2) 3191 return(1); 3192 if (l1 > l2) 3193 return(-1); 3194 } 3195 3196turtle_comparison: 3197 3198 if (node1 == node2->prev) 3199 return(1); 3200 if (node1 == node2->next) 3201 return(-1); 3202 /* 3203 * compute depth to root 3204 */ 3205 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3206 if (cur == node1) 3207 return(1); 3208 depth2++; 3209 } 3210 root = cur; 3211 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3212 if (cur == node2) 3213 return(-1); 3214 depth1++; 3215 } 3216 /* 3217 * Distinct document (or distinct entities :-( ) case. 3218 */ 3219 if (root != cur) { 3220 return(-2); 3221 } 3222 /* 3223 * get the nearest common ancestor. 3224 */ 3225 while (depth1 > depth2) { 3226 depth1--; 3227 node1 = node1->parent; 3228 } 3229 while (depth2 > depth1) { 3230 depth2--; 3231 node2 = node2->parent; 3232 } 3233 while (node1->parent != node2->parent) { 3234 node1 = node1->parent; 3235 node2 = node2->parent; 3236 /* should not happen but just in case ... */ 3237 if ((node1 == NULL) || (node2 == NULL)) 3238 return(-2); 3239 } 3240 /* 3241 * Find who's first. 3242 */ 3243 if (node1 == node2->prev) 3244 return(1); 3245 if (node1 == node2->next) 3246 return(-1); 3247 /* 3248 * Speedup using document order if availble. 3249 */ 3250 if ((node1->type == XML_ELEMENT_NODE) && 3251 (node2->type == XML_ELEMENT_NODE) && 3252 (0 > (long) node1->content) && 3253 (0 > (long) node2->content) && 3254 (node1->doc == node2->doc)) { 3255 3256 l1 = -((long) node1->content); 3257 l2 = -((long) node2->content); 3258 if (l1 < l2) 3259 return(1); 3260 if (l1 > l2) 3261 return(-1); 3262 } 3263 3264 for (cur = node1->next;cur != NULL;cur = cur->next) 3265 if (cur == node2) 3266 return(1); 3267 return(-1); /* assume there is no sibling list corruption */ 3268} 3269#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 3270 3271/** 3272 * xmlXPathNodeSetSort: 3273 * @set: the node set 3274 * 3275 * Sort the node set in document order 3276 */ 3277void 3278xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3279 int i, j, incr, len; 3280 xmlNodePtr tmp; 3281 3282 if (set == NULL) 3283 return; 3284 3285 /* Use Shell's sort to sort the node-set */ 3286 len = set->nodeNr; 3287 for (incr = len / 2; incr > 0; incr /= 2) { 3288 for (i = incr; i < len; i++) { 3289 j = i - incr; 3290 while (j >= 0) { 3291#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3292 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3293 set->nodeTab[j + incr]) == -1) 3294#else 3295 if (xmlXPathCmpNodes(set->nodeTab[j], 3296 set->nodeTab[j + incr]) == -1) 3297#endif 3298 { 3299 tmp = set->nodeTab[j]; 3300 set->nodeTab[j] = set->nodeTab[j + incr]; 3301 set->nodeTab[j + incr] = tmp; 3302 j -= incr; 3303 } else 3304 break; 3305 } 3306 } 3307 } 3308} 3309 3310#define XML_NODESET_DEFAULT 10 3311/** 3312 * xmlXPathNodeSetDupNs: 3313 * @node: the parent node of the namespace XPath node 3314 * @ns: the libxml namespace declaration node. 3315 * 3316 * Namespace node in libxml don't match the XPath semantic. In a node set 3317 * the namespace nodes are duplicated and the next pointer is set to the 3318 * parent node in the XPath semantic. 3319 * 3320 * Returns the newly created object. 3321 */ 3322static xmlNodePtr 3323xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3324 xmlNsPtr cur; 3325 3326 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3327 return(NULL); 3328 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3329 return((xmlNodePtr) ns); 3330 3331 /* 3332 * Allocate a new Namespace and fill the fields. 3333 */ 3334 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3335 if (cur == NULL) { 3336 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3337 return(NULL); 3338 } 3339 memset(cur, 0, sizeof(xmlNs)); 3340 cur->type = XML_NAMESPACE_DECL; 3341 if (ns->href != NULL) 3342 cur->href = xmlStrdup(ns->href); 3343 if (ns->prefix != NULL) 3344 cur->prefix = xmlStrdup(ns->prefix); 3345 cur->next = (xmlNsPtr) node; 3346 return((xmlNodePtr) cur); 3347} 3348 3349/** 3350 * xmlXPathNodeSetFreeNs: 3351 * @ns: the XPath namespace node found in a nodeset. 3352 * 3353 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3354 * the namespace nodes are duplicated and the next pointer is set to the 3355 * parent node in the XPath semantic. Check if such a node needs to be freed 3356 */ 3357void 3358xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3359 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3360 return; 3361 3362 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3363 if (ns->href != NULL) 3364 xmlFree((xmlChar *)ns->href); 3365 if (ns->prefix != NULL) 3366 xmlFree((xmlChar *)ns->prefix); 3367 xmlFree(ns); 3368 } 3369} 3370 3371/** 3372 * xmlXPathNodeSetCreate: 3373 * @val: an initial xmlNodePtr, or NULL 3374 * 3375 * Create a new xmlNodeSetPtr of type double and of value @val 3376 * 3377 * Returns the newly created object. 3378 */ 3379xmlNodeSetPtr 3380xmlXPathNodeSetCreate(xmlNodePtr val) { 3381 xmlNodeSetPtr ret; 3382 3383 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3384 if (ret == NULL) { 3385 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3386 return(NULL); 3387 } 3388 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3389 if (val != NULL) { 3390 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3391 sizeof(xmlNodePtr)); 3392 if (ret->nodeTab == NULL) { 3393 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3394 xmlFree(ret); 3395 return(NULL); 3396 } 3397 memset(ret->nodeTab, 0 , 3398 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3399 ret->nodeMax = XML_NODESET_DEFAULT; 3400 if (val->type == XML_NAMESPACE_DECL) { 3401 xmlNsPtr ns = (xmlNsPtr) val; 3402 3403 ret->nodeTab[ret->nodeNr++] = 3404 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3405 } else 3406 ret->nodeTab[ret->nodeNr++] = val; 3407 } 3408 return(ret); 3409} 3410 3411/** 3412 * xmlXPathNodeSetCreateSize: 3413 * @size: the initial size of the set 3414 * 3415 * Create a new xmlNodeSetPtr of type double and of value @val 3416 * 3417 * Returns the newly created object. 3418 */ 3419static xmlNodeSetPtr 3420xmlXPathNodeSetCreateSize(int size) { 3421 xmlNodeSetPtr ret; 3422 3423 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3424 if (ret == NULL) { 3425 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3426 return(NULL); 3427 } 3428 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3429 if (size < XML_NODESET_DEFAULT) 3430 size = XML_NODESET_DEFAULT; 3431 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr)); 3432 if (ret->nodeTab == NULL) { 3433 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3434 xmlFree(ret); 3435 return(NULL); 3436 } 3437 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr)); 3438 ret->nodeMax = size; 3439 return(ret); 3440} 3441 3442/** 3443 * xmlXPathNodeSetContains: 3444 * @cur: the node-set 3445 * @val: the node 3446 * 3447 * checks whether @cur contains @val 3448 * 3449 * Returns true (1) if @cur contains @val, false (0) otherwise 3450 */ 3451int 3452xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3453 int i; 3454 3455 if ((cur == NULL) || (val == NULL)) return(0); 3456 if (val->type == XML_NAMESPACE_DECL) { 3457 for (i = 0; i < cur->nodeNr; i++) { 3458 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3459 xmlNsPtr ns1, ns2; 3460 3461 ns1 = (xmlNsPtr) val; 3462 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3463 if (ns1 == ns2) 3464 return(1); 3465 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3466 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3467 return(1); 3468 } 3469 } 3470 } else { 3471 for (i = 0; i < cur->nodeNr; i++) { 3472 if (cur->nodeTab[i] == val) 3473 return(1); 3474 } 3475 } 3476 return(0); 3477} 3478 3479/** 3480 * xmlXPathNodeSetAddNs: 3481 * @cur: the initial node set 3482 * @node: the hosting node 3483 * @ns: a the namespace node 3484 * 3485 * add a new namespace node to an existing NodeSet 3486 */ 3487void 3488xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3489 int i; 3490 3491 3492 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3493 (ns->type != XML_NAMESPACE_DECL) || 3494 (node->type != XML_ELEMENT_NODE)) 3495 return; 3496 3497 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3498 /* 3499 * prevent duplicates 3500 */ 3501 for (i = 0;i < cur->nodeNr;i++) { 3502 if ((cur->nodeTab[i] != NULL) && 3503 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3504 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3505 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3506 return; 3507 } 3508 3509 /* 3510 * grow the nodeTab if needed 3511 */ 3512 if (cur->nodeMax == 0) { 3513 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3514 sizeof(xmlNodePtr)); 3515 if (cur->nodeTab == NULL) { 3516 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3517 return; 3518 } 3519 memset(cur->nodeTab, 0 , 3520 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3521 cur->nodeMax = XML_NODESET_DEFAULT; 3522 } else if (cur->nodeNr == cur->nodeMax) { 3523 xmlNodePtr *temp; 3524 3525 cur->nodeMax *= 2; 3526 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3527 sizeof(xmlNodePtr)); 3528 if (temp == NULL) { 3529 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3530 return; 3531 } 3532 cur->nodeTab = temp; 3533 } 3534 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3535} 3536 3537/** 3538 * xmlXPathNodeSetAdd: 3539 * @cur: the initial node set 3540 * @val: a new xmlNodePtr 3541 * 3542 * add a new xmlNodePtr to an existing NodeSet 3543 */ 3544void 3545xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3546 int i; 3547 3548 if ((cur == NULL) || (val == NULL)) return; 3549 3550#if 0 3551 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3552 return; /* an XSLT fake node */ 3553#endif 3554 3555 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3556 /* 3557 * prevent duplcates 3558 */ 3559 for (i = 0;i < cur->nodeNr;i++) 3560 if (cur->nodeTab[i] == val) return; 3561 3562 /* 3563 * grow the nodeTab if needed 3564 */ 3565 if (cur->nodeMax == 0) { 3566 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3567 sizeof(xmlNodePtr)); 3568 if (cur->nodeTab == NULL) { 3569 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3570 return; 3571 } 3572 memset(cur->nodeTab, 0 , 3573 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3574 cur->nodeMax = XML_NODESET_DEFAULT; 3575 } else if (cur->nodeNr == cur->nodeMax) { 3576 xmlNodePtr *temp; 3577 3578 cur->nodeMax *= 2; 3579 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3580 sizeof(xmlNodePtr)); 3581 if (temp == NULL) { 3582 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3583 return; 3584 } 3585 cur->nodeTab = temp; 3586 } 3587 if (val->type == XML_NAMESPACE_DECL) { 3588 xmlNsPtr ns = (xmlNsPtr) val; 3589 3590 cur->nodeTab[cur->nodeNr++] = 3591 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3592 } else 3593 cur->nodeTab[cur->nodeNr++] = val; 3594} 3595 3596/** 3597 * xmlXPathNodeSetAddUnique: 3598 * @cur: the initial node set 3599 * @val: a new xmlNodePtr 3600 * 3601 * add a new xmlNodePtr to an existing NodeSet, optimized version 3602 * when we are sure the node is not already in the set. 3603 */ 3604void 3605xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3606 if ((cur == NULL) || (val == NULL)) return; 3607 3608#if 0 3609 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3610 return; /* an XSLT fake node */ 3611#endif 3612 3613 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3614 /* 3615 * grow the nodeTab if needed 3616 */ 3617 if (cur->nodeMax == 0) { 3618 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3619 sizeof(xmlNodePtr)); 3620 if (cur->nodeTab == NULL) { 3621 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3622 return; 3623 } 3624 memset(cur->nodeTab, 0 , 3625 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3626 cur->nodeMax = XML_NODESET_DEFAULT; 3627 } else if (cur->nodeNr == cur->nodeMax) { 3628 xmlNodePtr *temp; 3629 3630 cur->nodeMax *= 2; 3631 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3632 sizeof(xmlNodePtr)); 3633 if (temp == NULL) { 3634 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3635 return; 3636 } 3637 cur->nodeTab = temp; 3638 } 3639 if (val->type == XML_NAMESPACE_DECL) { 3640 xmlNsPtr ns = (xmlNsPtr) val; 3641 3642 cur->nodeTab[cur->nodeNr++] = 3643 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3644 } else 3645 cur->nodeTab[cur->nodeNr++] = val; 3646} 3647 3648/** 3649 * xmlXPathNodeSetMerge: 3650 * @val1: the first NodeSet or NULL 3651 * @val2: the second NodeSet 3652 * 3653 * Merges two nodesets, all nodes from @val2 are added to @val1 3654 * if @val1 is NULL, a new set is created and copied from @val2 3655 * 3656 * Returns @val1 once extended or NULL in case of error. 3657 */ 3658xmlNodeSetPtr 3659xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3660 int i, j, initNr, skip; 3661 xmlNodePtr n1, n2; 3662 3663 if (val2 == NULL) return(val1); 3664 if (val1 == NULL) { 3665 val1 = xmlXPathNodeSetCreate(NULL); 3666 if (val1 == NULL) 3667 return (NULL); 3668#if 0 3669 /* 3670 * TODO: The optimization won't work in every case, since 3671 * those nasty namespace nodes need to be added with 3672 * xmlXPathNodeSetDupNs() to the set; thus a pure 3673 * memcpy is not possible. 3674 * If there was a flag on the nodesetval, indicating that 3675 * some temporary nodes are in, that would be helpfull. 3676 */ 3677 /* 3678 * Optimization: Create an equally sized node-set 3679 * and memcpy the content. 3680 */ 3681 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3682 if (val1 == NULL) 3683 return(NULL); 3684 if (val2->nodeNr != 0) { 3685 if (val2->nodeNr == 1) 3686 *(val1->nodeTab) = *(val2->nodeTab); 3687 else { 3688 memcpy(val1->nodeTab, val2->nodeTab, 3689 val2->nodeNr * sizeof(xmlNodePtr)); 3690 } 3691 val1->nodeNr = val2->nodeNr; 3692 } 3693 return(val1); 3694#endif 3695 } 3696 3697 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3698 initNr = val1->nodeNr; 3699 3700 for (i = 0;i < val2->nodeNr;i++) { 3701 n2 = val2->nodeTab[i]; 3702 /* 3703 * check against duplicates 3704 */ 3705 skip = 0; 3706 for (j = 0; j < initNr; j++) { 3707 n1 = val1->nodeTab[j]; 3708 if (n1 == n2) { 3709 skip = 1; 3710 break; 3711 } else if ((n1->type == XML_NAMESPACE_DECL) && 3712 (n2->type == XML_NAMESPACE_DECL)) { 3713 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3714 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3715 ((xmlNsPtr) n2)->prefix))) 3716 { 3717 skip = 1; 3718 break; 3719 } 3720 } 3721 } 3722 if (skip) 3723 continue; 3724 3725 /* 3726 * grow the nodeTab if needed 3727 */ 3728 if (val1->nodeMax == 0) { 3729 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3730 sizeof(xmlNodePtr)); 3731 if (val1->nodeTab == NULL) { 3732 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3733 return(NULL); 3734 } 3735 memset(val1->nodeTab, 0 , 3736 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3737 val1->nodeMax = XML_NODESET_DEFAULT; 3738 } else if (val1->nodeNr == val1->nodeMax) { 3739 xmlNodePtr *temp; 3740 3741 val1->nodeMax *= 2; 3742 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 3743 sizeof(xmlNodePtr)); 3744 if (temp == NULL) { 3745 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3746 return(NULL); 3747 } 3748 val1->nodeTab = temp; 3749 } 3750 if (n2->type == XML_NAMESPACE_DECL) { 3751 xmlNsPtr ns = (xmlNsPtr) n2; 3752 3753 val1->nodeTab[val1->nodeNr++] = 3754 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3755 } else 3756 val1->nodeTab[val1->nodeNr++] = n2; 3757 } 3758 3759 return(val1); 3760} 3761 3762#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 3763/** 3764 * xmlXPathNodeSetMergeUnique: 3765 * @val1: the first NodeSet or NULL 3766 * @val2: the second NodeSet 3767 * 3768 * Merges two nodesets, all nodes from @val2 are added to @val1 3769 * if @val1 is NULL, a new set is created and copied from @val2 3770 * 3771 * Returns @val1 once extended or NULL in case of error. 3772 */ 3773static xmlNodeSetPtr 3774xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3775 int i; 3776 3777 if (val2 == NULL) return(val1); 3778 if (val1 == NULL) { 3779 val1 = xmlXPathNodeSetCreate(NULL); 3780 } 3781 if (val1 == NULL) 3782 return (NULL); 3783 3784 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3785 3786 for (i = 0;i < val2->nodeNr;i++) { 3787 /* 3788 * grow the nodeTab if needed 3789 */ 3790 if (val1->nodeMax == 0) { 3791 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3792 sizeof(xmlNodePtr)); 3793 if (val1->nodeTab == NULL) { 3794 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3795 return(NULL); 3796 } 3797 memset(val1->nodeTab, 0 , 3798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3799 val1->nodeMax = XML_NODESET_DEFAULT; 3800 } else if (val1->nodeNr == val1->nodeMax) { 3801 xmlNodePtr *temp; 3802 3803 val1->nodeMax *= 2; 3804 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 3805 sizeof(xmlNodePtr)); 3806 if (temp == NULL) { 3807 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3808 return(NULL); 3809 } 3810 val1->nodeTab = temp; 3811 } 3812 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3813 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; 3814 3815 val1->nodeTab[val1->nodeNr++] = 3816 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3817 } else 3818 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; 3819 } 3820 3821 return(val1); 3822} 3823#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 3824 3825/** 3826 * xmlXPathNodeSetMergeAndClear: 3827 * @set1: the first NodeSet or NULL 3828 * @set2: the second NodeSet 3829 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3830 * 3831 * Merges two nodesets, all nodes from @set2 are added to @set1 3832 * if @set1 is NULL, a new set is created and copied from @set2. 3833 * Checks for duplicate nodes. Clears set2. 3834 * 3835 * Returns @set1 once extended or NULL in case of error. 3836 */ 3837static xmlNodeSetPtr 3838xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3839 int hasNullEntries) 3840{ 3841 if ((set1 == NULL) && (hasNullEntries == 0)) { 3842 /* 3843 * Note that doing a memcpy of the list, namespace nodes are 3844 * just assigned to set1, since set2 is cleared anyway. 3845 */ 3846 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3847 if (set1 == NULL) 3848 return(NULL); 3849 if (set2->nodeNr != 0) { 3850 memcpy(set1->nodeTab, set2->nodeTab, 3851 set2->nodeNr * sizeof(xmlNodePtr)); 3852 set1->nodeNr = set2->nodeNr; 3853 } 3854 } else { 3855 int i, j, initNbSet1; 3856 xmlNodePtr n1, n2; 3857 3858 if (set1 == NULL) 3859 set1 = xmlXPathNodeSetCreate(NULL); 3860 if (set1 == NULL) 3861 return (NULL); 3862 3863 initNbSet1 = set1->nodeNr; 3864 for (i = 0;i < set2->nodeNr;i++) { 3865 n2 = set2->nodeTab[i]; 3866 /* 3867 * Skip NULLed entries. 3868 */ 3869 if (n2 == NULL) 3870 continue; 3871 /* 3872 * Skip duplicates. 3873 */ 3874 for (j = 0; j < initNbSet1; j++) { 3875 n1 = set1->nodeTab[j]; 3876 if (n1 == n2) { 3877 goto skip_node; 3878 } else if ((n1->type == XML_NAMESPACE_DECL) && 3879 (n2->type == XML_NAMESPACE_DECL)) 3880 { 3881 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3882 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3883 ((xmlNsPtr) n2)->prefix))) 3884 { 3885 /* 3886 * Free the namespace node. 3887 */ 3888 set2->nodeTab[i] = NULL; 3889 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3890 goto skip_node; 3891 } 3892 } 3893 } 3894 /* 3895 * grow the nodeTab if needed 3896 */ 3897 if (set1->nodeMax == 0) { 3898 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3899 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3900 if (set1->nodeTab == NULL) { 3901 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3902 return(NULL); 3903 } 3904 memset(set1->nodeTab, 0, 3905 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3906 set1->nodeMax = XML_NODESET_DEFAULT; 3907 } else if (set1->nodeNr >= set1->nodeMax) { 3908 xmlNodePtr *temp; 3909 3910 set1->nodeMax *= 2; 3911 temp = (xmlNodePtr *) xmlRealloc( 3912 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr)); 3913 if (temp == NULL) { 3914 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3915 return(NULL); 3916 } 3917 set1->nodeTab = temp; 3918 } 3919 if (n2->type == XML_NAMESPACE_DECL) { 3920 xmlNsPtr ns = (xmlNsPtr) n2; 3921 3922 set1->nodeTab[set1->nodeNr++] = 3923 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3924 } else 3925 set1->nodeTab[set1->nodeNr++] = n2; 3926skip_node: 3927 {} 3928 } 3929 } 3930 set2->nodeNr = 0; 3931 return(set1); 3932} 3933 3934/** 3935 * xmlXPathNodeSetMergeAndClearNoDupls: 3936 * @set1: the first NodeSet or NULL 3937 * @set2: the second NodeSet 3938 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3939 * 3940 * Merges two nodesets, all nodes from @set2 are added to @set1 3941 * if @set1 is NULL, a new set is created and copied from @set2. 3942 * Doesn't chack for duplicate nodes. Clears set2. 3943 * 3944 * Returns @set1 once extended or NULL in case of error. 3945 */ 3946static xmlNodeSetPtr 3947xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3948 int hasNullEntries) 3949{ 3950 if (set2 == NULL) 3951 return(set1); 3952 if ((set1 == NULL) && (hasNullEntries == 0)) { 3953 /* 3954 * Note that doing a memcpy of the list, namespace nodes are 3955 * just assigned to set1, since set2 is cleared anyway. 3956 */ 3957 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3958 if (set1 == NULL) 3959 return(NULL); 3960 if (set2->nodeNr != 0) { 3961 memcpy(set1->nodeTab, set2->nodeTab, 3962 set2->nodeNr * sizeof(xmlNodePtr)); 3963 set1->nodeNr = set2->nodeNr; 3964 } 3965 } else { 3966 int i; 3967 xmlNodePtr n2; 3968 3969 if (set1 == NULL) 3970 set1 = xmlXPathNodeSetCreate(NULL); 3971 if (set1 == NULL) 3972 return (NULL); 3973 3974 for (i = 0;i < set2->nodeNr;i++) { 3975 n2 = set2->nodeTab[i]; 3976 /* 3977 * Skip NULLed entries. 3978 */ 3979 if (n2 == NULL) 3980 continue; 3981 if (set1->nodeMax == 0) { 3982 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3983 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3984 if (set1->nodeTab == NULL) { 3985 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3986 return(NULL); 3987 } 3988 memset(set1->nodeTab, 0, 3989 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3990 set1->nodeMax = XML_NODESET_DEFAULT; 3991 } else if (set1->nodeNr >= set1->nodeMax) { 3992 xmlNodePtr *temp; 3993 3994 set1->nodeMax *= 2; 3995 temp = (xmlNodePtr *) xmlRealloc( 3996 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr)); 3997 if (temp == NULL) { 3998 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3999 return(NULL); 4000 } 4001 set1->nodeTab = temp; 4002 } 4003 set1->nodeTab[set1->nodeNr++] = n2; 4004 } 4005 } 4006 set2->nodeNr = 0; 4007 return(set1); 4008} 4009 4010/** 4011 * xmlXPathNodeSetDel: 4012 * @cur: the initial node set 4013 * @val: an xmlNodePtr 4014 * 4015 * Removes an xmlNodePtr from an existing NodeSet 4016 */ 4017void 4018xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4019 int i; 4020 4021 if (cur == NULL) return; 4022 if (val == NULL) return; 4023 4024 /* 4025 * find node in nodeTab 4026 */ 4027 for (i = 0;i < cur->nodeNr;i++) 4028 if (cur->nodeTab[i] == val) break; 4029 4030 if (i >= cur->nodeNr) { /* not found */ 4031#ifdef DEBUG 4032 xmlGenericError(xmlGenericErrorContext, 4033 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4034 val->name); 4035#endif 4036 return; 4037 } 4038 if ((cur->nodeTab[i] != NULL) && 4039 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4040 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4041 cur->nodeNr--; 4042 for (;i < cur->nodeNr;i++) 4043 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4044 cur->nodeTab[cur->nodeNr] = NULL; 4045} 4046 4047/** 4048 * xmlXPathNodeSetRemove: 4049 * @cur: the initial node set 4050 * @val: the index to remove 4051 * 4052 * Removes an entry from an existing NodeSet list. 4053 */ 4054void 4055xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4056 if (cur == NULL) return; 4057 if (val >= cur->nodeNr) return; 4058 if ((cur->nodeTab[val] != NULL) && 4059 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4060 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4061 cur->nodeNr--; 4062 for (;val < cur->nodeNr;val++) 4063 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4064 cur->nodeTab[cur->nodeNr] = NULL; 4065} 4066 4067/** 4068 * xmlXPathFreeNodeSet: 4069 * @obj: the xmlNodeSetPtr to free 4070 * 4071 * Free the NodeSet compound (not the actual nodes !). 4072 */ 4073void 4074xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4075 if (obj == NULL) return; 4076 if (obj->nodeTab != NULL) { 4077 int i; 4078 4079 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4080 for (i = 0;i < obj->nodeNr;i++) 4081 if ((obj->nodeTab[i] != NULL) && 4082 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4083 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4084 xmlFree(obj->nodeTab); 4085 } 4086 xmlFree(obj); 4087} 4088 4089/** 4090 * xmlXPathNodeSetClear: 4091 * @set: the node set to clear 4092 * 4093 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4094 * are feed), but does *not* free the list itself. Sets the length of the 4095 * list to 0. 4096 */ 4097static void 4098xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4099{ 4100 if ((set == NULL) || (set->nodeNr <= 0)) 4101 return; 4102 else if (hasNsNodes) { 4103 int i; 4104 xmlNodePtr node; 4105 4106 for (i = 0; i < set->nodeNr; i++) { 4107 node = set->nodeTab[i]; 4108 if ((node != NULL) && 4109 (node->type == XML_NAMESPACE_DECL)) 4110 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4111 } 4112 } 4113 set->nodeNr = 0; 4114} 4115 4116/** 4117 * xmlXPathNodeSetClearFromPos: 4118 * @set: the node set to be cleared 4119 * @pos: the start position to clear from 4120 * 4121 * Clears the list from temporary XPath objects (e.g. namespace nodes 4122 * are feed) starting with the entry at @pos, but does *not* free the list 4123 * itself. Sets the length of the list to @pos. 4124 */ 4125static void 4126xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4127{ 4128 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr)) 4129 return; 4130 else if ((hasNsNodes)) { 4131 int i; 4132 xmlNodePtr node; 4133 4134 for (i = pos; i < set->nodeNr; i++) { 4135 node = set->nodeTab[i]; 4136 if ((node != NULL) && 4137 (node->type == XML_NAMESPACE_DECL)) 4138 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4139 } 4140 } 4141 set->nodeNr = pos; 4142} 4143 4144/** 4145 * xmlXPathFreeValueTree: 4146 * @obj: the xmlNodeSetPtr to free 4147 * 4148 * Free the NodeSet compound and the actual tree, this is different 4149 * from xmlXPathFreeNodeSet() 4150 */ 4151static void 4152xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4153 int i; 4154 4155 if (obj == NULL) return; 4156 4157 if (obj->nodeTab != NULL) { 4158 for (i = 0;i < obj->nodeNr;i++) { 4159 if (obj->nodeTab[i] != NULL) { 4160 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4161 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4162 } else { 4163 xmlFreeNodeList(obj->nodeTab[i]); 4164 } 4165 } 4166 } 4167 xmlFree(obj->nodeTab); 4168 } 4169 xmlFree(obj); 4170} 4171 4172#if defined(DEBUG) || defined(DEBUG_STEP) 4173/** 4174 * xmlGenericErrorContextNodeSet: 4175 * @output: a FILE * for the output 4176 * @obj: the xmlNodeSetPtr to display 4177 * 4178 * Quick display of a NodeSet 4179 */ 4180void 4181xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4182 int i; 4183 4184 if (output == NULL) output = xmlGenericErrorContext; 4185 if (obj == NULL) { 4186 fprintf(output, "NodeSet == NULL !\n"); 4187 return; 4188 } 4189 if (obj->nodeNr == 0) { 4190 fprintf(output, "NodeSet is empty\n"); 4191 return; 4192 } 4193 if (obj->nodeTab == NULL) { 4194 fprintf(output, " nodeTab == NULL !\n"); 4195 return; 4196 } 4197 for (i = 0; i < obj->nodeNr; i++) { 4198 if (obj->nodeTab[i] == NULL) { 4199 fprintf(output, " NULL !\n"); 4200 return; 4201 } 4202 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4203 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4204 fprintf(output, " /"); 4205 else if (obj->nodeTab[i]->name == NULL) 4206 fprintf(output, " noname!"); 4207 else fprintf(output, " %s", obj->nodeTab[i]->name); 4208 } 4209 fprintf(output, "\n"); 4210} 4211#endif 4212 4213/** 4214 * xmlXPathNewNodeSet: 4215 * @val: the NodePtr value 4216 * 4217 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4218 * it with the single Node @val 4219 * 4220 * Returns the newly created object. 4221 */ 4222xmlXPathObjectPtr 4223xmlXPathNewNodeSet(xmlNodePtr val) { 4224 xmlXPathObjectPtr ret; 4225 4226 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4227 if (ret == NULL) { 4228 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4229 return(NULL); 4230 } 4231 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4232 ret->type = XPATH_NODESET; 4233 ret->boolval = 0; 4234 ret->nodesetval = xmlXPathNodeSetCreate(val); 4235 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4236#ifdef XP_DEBUG_OBJ_USAGE 4237 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4238#endif 4239 return(ret); 4240} 4241 4242/** 4243 * xmlXPathNewValueTree: 4244 * @val: the NodePtr value 4245 * 4246 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4247 * it with the tree root @val 4248 * 4249 * Returns the newly created object. 4250 */ 4251xmlXPathObjectPtr 4252xmlXPathNewValueTree(xmlNodePtr val) { 4253 xmlXPathObjectPtr ret; 4254 4255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4256 if (ret == NULL) { 4257 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4258 return(NULL); 4259 } 4260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4261 ret->type = XPATH_XSLT_TREE; 4262 ret->boolval = 1; 4263 ret->user = (void *) val; 4264 ret->nodesetval = xmlXPathNodeSetCreate(val); 4265#ifdef XP_DEBUG_OBJ_USAGE 4266 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4267#endif 4268 return(ret); 4269} 4270 4271/** 4272 * xmlXPathNewNodeSetList: 4273 * @val: an existing NodeSet 4274 * 4275 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4276 * it with the Nodeset @val 4277 * 4278 * Returns the newly created object. 4279 */ 4280xmlXPathObjectPtr 4281xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4282{ 4283 xmlXPathObjectPtr ret; 4284 int i; 4285 4286 if (val == NULL) 4287 ret = NULL; 4288 else if (val->nodeTab == NULL) 4289 ret = xmlXPathNewNodeSet(NULL); 4290 else { 4291 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4292 if (ret) 4293 for (i = 1; i < val->nodeNr; ++i) 4294 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]); 4295 } 4296 4297 return (ret); 4298} 4299 4300/** 4301 * xmlXPathWrapNodeSet: 4302 * @val: the NodePtr value 4303 * 4304 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4305 * 4306 * Returns the newly created object. 4307 */ 4308xmlXPathObjectPtr 4309xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4310 xmlXPathObjectPtr ret; 4311 4312 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4313 if (ret == NULL) { 4314 xmlXPathErrMemory(NULL, "creating node set object\n"); 4315 return(NULL); 4316 } 4317 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4318 ret->type = XPATH_NODESET; 4319 ret->nodesetval = val; 4320#ifdef XP_DEBUG_OBJ_USAGE 4321 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4322#endif 4323 return(ret); 4324} 4325 4326/** 4327 * xmlXPathFreeNodeSetList: 4328 * @obj: an existing NodeSetList object 4329 * 4330 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4331 * the list contrary to xmlXPathFreeObject(). 4332 */ 4333void 4334xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4335 if (obj == NULL) return; 4336#ifdef XP_DEBUG_OBJ_USAGE 4337 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4338#endif 4339 xmlFree(obj); 4340} 4341 4342/** 4343 * xmlXPathDifference: 4344 * @nodes1: a node-set 4345 * @nodes2: a node-set 4346 * 4347 * Implements the EXSLT - Sets difference() function: 4348 * node-set set:difference (node-set, node-set) 4349 * 4350 * Returns the difference between the two node sets, or nodes1 if 4351 * nodes2 is empty 4352 */ 4353xmlNodeSetPtr 4354xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4355 xmlNodeSetPtr ret; 4356 int i, l1; 4357 xmlNodePtr cur; 4358 4359 if (xmlXPathNodeSetIsEmpty(nodes2)) 4360 return(nodes1); 4361 4362 ret = xmlXPathNodeSetCreate(NULL); 4363 if (xmlXPathNodeSetIsEmpty(nodes1)) 4364 return(ret); 4365 4366 l1 = xmlXPathNodeSetGetLength(nodes1); 4367 4368 for (i = 0; i < l1; i++) { 4369 cur = xmlXPathNodeSetItem(nodes1, i); 4370 if (!xmlXPathNodeSetContains(nodes2, cur)) 4371 xmlXPathNodeSetAddUnique(ret, cur); 4372 } 4373 return(ret); 4374} 4375 4376/** 4377 * xmlXPathIntersection: 4378 * @nodes1: a node-set 4379 * @nodes2: a node-set 4380 * 4381 * Implements the EXSLT - Sets intersection() function: 4382 * node-set set:intersection (node-set, node-set) 4383 * 4384 * Returns a node set comprising the nodes that are within both the 4385 * node sets passed as arguments 4386 */ 4387xmlNodeSetPtr 4388xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4389 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4390 int i, l1; 4391 xmlNodePtr cur; 4392 4393 if (ret == NULL) 4394 return(ret); 4395 if (xmlXPathNodeSetIsEmpty(nodes1)) 4396 return(ret); 4397 if (xmlXPathNodeSetIsEmpty(nodes2)) 4398 return(ret); 4399 4400 l1 = xmlXPathNodeSetGetLength(nodes1); 4401 4402 for (i = 0; i < l1; i++) { 4403 cur = xmlXPathNodeSetItem(nodes1, i); 4404 if (xmlXPathNodeSetContains(nodes2, cur)) 4405 xmlXPathNodeSetAddUnique(ret, cur); 4406 } 4407 return(ret); 4408} 4409 4410/** 4411 * xmlXPathDistinctSorted: 4412 * @nodes: a node-set, sorted by document order 4413 * 4414 * Implements the EXSLT - Sets distinct() function: 4415 * node-set set:distinct (node-set) 4416 * 4417 * Returns a subset of the nodes contained in @nodes, or @nodes if 4418 * it is empty 4419 */ 4420xmlNodeSetPtr 4421xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4422 xmlNodeSetPtr ret; 4423 xmlHashTablePtr hash; 4424 int i, l; 4425 xmlChar * strval; 4426 xmlNodePtr cur; 4427 4428 if (xmlXPathNodeSetIsEmpty(nodes)) 4429 return(nodes); 4430 4431 ret = xmlXPathNodeSetCreate(NULL); 4432 if (ret == NULL) 4433 return(ret); 4434 l = xmlXPathNodeSetGetLength(nodes); 4435 hash = xmlHashCreate (l); 4436 for (i = 0; i < l; i++) { 4437 cur = xmlXPathNodeSetItem(nodes, i); 4438 strval = xmlXPathCastNodeToString(cur); 4439 if (xmlHashLookup(hash, strval) == NULL) { 4440 xmlHashAddEntry(hash, strval, strval); 4441 xmlXPathNodeSetAddUnique(ret, cur); 4442 } else { 4443 xmlFree(strval); 4444 } 4445 } 4446 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 4447 return(ret); 4448} 4449 4450/** 4451 * xmlXPathDistinct: 4452 * @nodes: a node-set 4453 * 4454 * Implements the EXSLT - Sets distinct() function: 4455 * node-set set:distinct (node-set) 4456 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4457 * is called with the sorted node-set 4458 * 4459 * Returns a subset of the nodes contained in @nodes, or @nodes if 4460 * it is empty 4461 */ 4462xmlNodeSetPtr 4463xmlXPathDistinct (xmlNodeSetPtr nodes) { 4464 if (xmlXPathNodeSetIsEmpty(nodes)) 4465 return(nodes); 4466 4467 xmlXPathNodeSetSort(nodes); 4468 return(xmlXPathDistinctSorted(nodes)); 4469} 4470 4471/** 4472 * xmlXPathHasSameNodes: 4473 * @nodes1: a node-set 4474 * @nodes2: a node-set 4475 * 4476 * Implements the EXSLT - Sets has-same-nodes function: 4477 * boolean set:has-same-node(node-set, node-set) 4478 * 4479 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4480 * otherwise 4481 */ 4482int 4483xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4484 int i, l; 4485 xmlNodePtr cur; 4486 4487 if (xmlXPathNodeSetIsEmpty(nodes1) || 4488 xmlXPathNodeSetIsEmpty(nodes2)) 4489 return(0); 4490 4491 l = xmlXPathNodeSetGetLength(nodes1); 4492 for (i = 0; i < l; i++) { 4493 cur = xmlXPathNodeSetItem(nodes1, i); 4494 if (xmlXPathNodeSetContains(nodes2, cur)) 4495 return(1); 4496 } 4497 return(0); 4498} 4499 4500/** 4501 * xmlXPathNodeLeadingSorted: 4502 * @nodes: a node-set, sorted by document order 4503 * @node: a node 4504 * 4505 * Implements the EXSLT - Sets leading() function: 4506 * node-set set:leading (node-set, node-set) 4507 * 4508 * Returns the nodes in @nodes that precede @node in document order, 4509 * @nodes if @node is NULL or an empty node-set if @nodes 4510 * doesn't contain @node 4511 */ 4512xmlNodeSetPtr 4513xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4514 int i, l; 4515 xmlNodePtr cur; 4516 xmlNodeSetPtr ret; 4517 4518 if (node == NULL) 4519 return(nodes); 4520 4521 ret = xmlXPathNodeSetCreate(NULL); 4522 if (ret == NULL) 4523 return(ret); 4524 if (xmlXPathNodeSetIsEmpty(nodes) || 4525 (!xmlXPathNodeSetContains(nodes, node))) 4526 return(ret); 4527 4528 l = xmlXPathNodeSetGetLength(nodes); 4529 for (i = 0; i < l; i++) { 4530 cur = xmlXPathNodeSetItem(nodes, i); 4531 if (cur == node) 4532 break; 4533 xmlXPathNodeSetAddUnique(ret, cur); 4534 } 4535 return(ret); 4536} 4537 4538/** 4539 * xmlXPathNodeLeading: 4540 * @nodes: a node-set 4541 * @node: a node 4542 * 4543 * Implements the EXSLT - Sets leading() function: 4544 * node-set set:leading (node-set, node-set) 4545 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4546 * is called. 4547 * 4548 * Returns the nodes in @nodes that precede @node in document order, 4549 * @nodes if @node is NULL or an empty node-set if @nodes 4550 * doesn't contain @node 4551 */ 4552xmlNodeSetPtr 4553xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4554 xmlXPathNodeSetSort(nodes); 4555 return(xmlXPathNodeLeadingSorted(nodes, node)); 4556} 4557 4558/** 4559 * xmlXPathLeadingSorted: 4560 * @nodes1: a node-set, sorted by document order 4561 * @nodes2: a node-set, sorted by document order 4562 * 4563 * Implements the EXSLT - Sets leading() function: 4564 * node-set set:leading (node-set, node-set) 4565 * 4566 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4567 * in document order, @nodes1 if @nodes2 is NULL or empty or 4568 * an empty node-set if @nodes1 doesn't contain @nodes2 4569 */ 4570xmlNodeSetPtr 4571xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4572 if (xmlXPathNodeSetIsEmpty(nodes2)) 4573 return(nodes1); 4574 return(xmlXPathNodeLeadingSorted(nodes1, 4575 xmlXPathNodeSetItem(nodes2, 1))); 4576} 4577 4578/** 4579 * xmlXPathLeading: 4580 * @nodes1: a node-set 4581 * @nodes2: a node-set 4582 * 4583 * Implements the EXSLT - Sets leading() function: 4584 * node-set set:leading (node-set, node-set) 4585 * @nodes1 and @nodes2 are sorted by document order, then 4586 * #exslSetsLeadingSorted is called. 4587 * 4588 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4589 * in document order, @nodes1 if @nodes2 is NULL or empty or 4590 * an empty node-set if @nodes1 doesn't contain @nodes2 4591 */ 4592xmlNodeSetPtr 4593xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4594 if (xmlXPathNodeSetIsEmpty(nodes2)) 4595 return(nodes1); 4596 if (xmlXPathNodeSetIsEmpty(nodes1)) 4597 return(xmlXPathNodeSetCreate(NULL)); 4598 xmlXPathNodeSetSort(nodes1); 4599 xmlXPathNodeSetSort(nodes2); 4600 return(xmlXPathNodeLeadingSorted(nodes1, 4601 xmlXPathNodeSetItem(nodes2, 1))); 4602} 4603 4604/** 4605 * xmlXPathNodeTrailingSorted: 4606 * @nodes: a node-set, sorted by document order 4607 * @node: a node 4608 * 4609 * Implements the EXSLT - Sets trailing() function: 4610 * node-set set:trailing (node-set, node-set) 4611 * 4612 * Returns the nodes in @nodes that follow @node in document order, 4613 * @nodes if @node is NULL or an empty node-set if @nodes 4614 * doesn't contain @node 4615 */ 4616xmlNodeSetPtr 4617xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4618 int i, l; 4619 xmlNodePtr cur; 4620 xmlNodeSetPtr ret; 4621 4622 if (node == NULL) 4623 return(nodes); 4624 4625 ret = xmlXPathNodeSetCreate(NULL); 4626 if (ret == NULL) 4627 return(ret); 4628 if (xmlXPathNodeSetIsEmpty(nodes) || 4629 (!xmlXPathNodeSetContains(nodes, node))) 4630 return(ret); 4631 4632 l = xmlXPathNodeSetGetLength(nodes); 4633 for (i = l - 1; i >= 0; i--) { 4634 cur = xmlXPathNodeSetItem(nodes, i); 4635 if (cur == node) 4636 break; 4637 xmlXPathNodeSetAddUnique(ret, cur); 4638 } 4639 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4640 return(ret); 4641} 4642 4643/** 4644 * xmlXPathNodeTrailing: 4645 * @nodes: a node-set 4646 * @node: a node 4647 * 4648 * Implements the EXSLT - Sets trailing() function: 4649 * node-set set:trailing (node-set, node-set) 4650 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4651 * is called. 4652 * 4653 * Returns the nodes in @nodes that follow @node in document order, 4654 * @nodes if @node is NULL or an empty node-set if @nodes 4655 * doesn't contain @node 4656 */ 4657xmlNodeSetPtr 4658xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4659 xmlXPathNodeSetSort(nodes); 4660 return(xmlXPathNodeTrailingSorted(nodes, node)); 4661} 4662 4663/** 4664 * xmlXPathTrailingSorted: 4665 * @nodes1: a node-set, sorted by document order 4666 * @nodes2: a node-set, sorted by document order 4667 * 4668 * Implements the EXSLT - Sets trailing() function: 4669 * node-set set:trailing (node-set, node-set) 4670 * 4671 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4672 * in document order, @nodes1 if @nodes2 is NULL or empty or 4673 * an empty node-set if @nodes1 doesn't contain @nodes2 4674 */ 4675xmlNodeSetPtr 4676xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4677 if (xmlXPathNodeSetIsEmpty(nodes2)) 4678 return(nodes1); 4679 return(xmlXPathNodeTrailingSorted(nodes1, 4680 xmlXPathNodeSetItem(nodes2, 0))); 4681} 4682 4683/** 4684 * xmlXPathTrailing: 4685 * @nodes1: a node-set 4686 * @nodes2: a node-set 4687 * 4688 * Implements the EXSLT - Sets trailing() function: 4689 * node-set set:trailing (node-set, node-set) 4690 * @nodes1 and @nodes2 are sorted by document order, then 4691 * #xmlXPathTrailingSorted is called. 4692 * 4693 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4694 * in document order, @nodes1 if @nodes2 is NULL or empty or 4695 * an empty node-set if @nodes1 doesn't contain @nodes2 4696 */ 4697xmlNodeSetPtr 4698xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4699 if (xmlXPathNodeSetIsEmpty(nodes2)) 4700 return(nodes1); 4701 if (xmlXPathNodeSetIsEmpty(nodes1)) 4702 return(xmlXPathNodeSetCreate(NULL)); 4703 xmlXPathNodeSetSort(nodes1); 4704 xmlXPathNodeSetSort(nodes2); 4705 return(xmlXPathNodeTrailingSorted(nodes1, 4706 xmlXPathNodeSetItem(nodes2, 0))); 4707} 4708 4709/************************************************************************ 4710 * * 4711 * Routines to handle extra functions * 4712 * * 4713 ************************************************************************/ 4714 4715/** 4716 * xmlXPathRegisterFunc: 4717 * @ctxt: the XPath context 4718 * @name: the function name 4719 * @f: the function implementation or NULL 4720 * 4721 * Register a new function. If @f is NULL it unregisters the function 4722 * 4723 * Returns 0 in case of success, -1 in case of error 4724 */ 4725int 4726xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4727 xmlXPathFunction f) { 4728 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4729} 4730 4731/** 4732 * xmlXPathRegisterFuncNS: 4733 * @ctxt: the XPath context 4734 * @name: the function name 4735 * @ns_uri: the function namespace URI 4736 * @f: the function implementation or NULL 4737 * 4738 * Register a new function. If @f is NULL it unregisters the function 4739 * 4740 * Returns 0 in case of success, -1 in case of error 4741 */ 4742int 4743xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4744 const xmlChar *ns_uri, xmlXPathFunction f) { 4745 if (ctxt == NULL) 4746 return(-1); 4747 if (name == NULL) 4748 return(-1); 4749 4750 if (ctxt->funcHash == NULL) 4751 ctxt->funcHash = xmlHashCreate(0); 4752 if (ctxt->funcHash == NULL) 4753 return(-1); 4754 if (f == NULL) 4755 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4756 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f))); 4757} 4758 4759/** 4760 * xmlXPathRegisterFuncLookup: 4761 * @ctxt: the XPath context 4762 * @f: the lookup function 4763 * @funcCtxt: the lookup data 4764 * 4765 * Registers an external mechanism to do function lookup. 4766 */ 4767void 4768xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4769 xmlXPathFuncLookupFunc f, 4770 void *funcCtxt) { 4771 if (ctxt == NULL) 4772 return; 4773 ctxt->funcLookupFunc = f; 4774 ctxt->funcLookupData = funcCtxt; 4775} 4776 4777/** 4778 * xmlXPathFunctionLookup: 4779 * @ctxt: the XPath context 4780 * @name: the function name 4781 * 4782 * Search in the Function array of the context for the given 4783 * function. 4784 * 4785 * Returns the xmlXPathFunction or NULL if not found 4786 */ 4787xmlXPathFunction 4788xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4789 if (ctxt == NULL) 4790 return (NULL); 4791 4792 if (ctxt->funcLookupFunc != NULL) { 4793 xmlXPathFunction ret; 4794 xmlXPathFuncLookupFunc f; 4795 4796 f = ctxt->funcLookupFunc; 4797 ret = f(ctxt->funcLookupData, name, NULL); 4798 if (ret != NULL) 4799 return(ret); 4800 } 4801 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4802} 4803 4804/** 4805 * xmlXPathFunctionLookupNS: 4806 * @ctxt: the XPath context 4807 * @name: the function name 4808 * @ns_uri: the function namespace URI 4809 * 4810 * Search in the Function array of the context for the given 4811 * function. 4812 * 4813 * Returns the xmlXPathFunction or NULL if not found 4814 */ 4815xmlXPathFunction 4816xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4817 const xmlChar *ns_uri) { 4818 xmlXPathFunction ret; 4819 4820 if (ctxt == NULL) 4821 return(NULL); 4822 if (name == NULL) 4823 return(NULL); 4824 4825 if (ctxt->funcLookupFunc != NULL) { 4826 xmlXPathFuncLookupFunc f; 4827 4828 f = ctxt->funcLookupFunc; 4829 ret = f(ctxt->funcLookupData, name, ns_uri); 4830 if (ret != NULL) 4831 return(ret); 4832 } 4833 4834 if (ctxt->funcHash == NULL) 4835 return(NULL); 4836 4837 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4838 return(ret); 4839} 4840 4841/** 4842 * xmlXPathRegisteredFuncsCleanup: 4843 * @ctxt: the XPath context 4844 * 4845 * Cleanup the XPath context data associated to registered functions 4846 */ 4847void 4848xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4849 if (ctxt == NULL) 4850 return; 4851 4852 xmlHashFree(ctxt->funcHash, NULL); 4853 ctxt->funcHash = NULL; 4854} 4855 4856/************************************************************************ 4857 * * 4858 * Routines to handle Variables * 4859 * * 4860 ************************************************************************/ 4861 4862/** 4863 * xmlXPathRegisterVariable: 4864 * @ctxt: the XPath context 4865 * @name: the variable name 4866 * @value: the variable value or NULL 4867 * 4868 * Register a new variable value. If @value is NULL it unregisters 4869 * the variable 4870 * 4871 * Returns 0 in case of success, -1 in case of error 4872 */ 4873int 4874xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 4875 xmlXPathObjectPtr value) { 4876 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 4877} 4878 4879/** 4880 * xmlXPathRegisterVariableNS: 4881 * @ctxt: the XPath context 4882 * @name: the variable name 4883 * @ns_uri: the variable namespace URI 4884 * @value: the variable value or NULL 4885 * 4886 * Register a new variable value. If @value is NULL it unregisters 4887 * the variable 4888 * 4889 * Returns 0 in case of success, -1 in case of error 4890 */ 4891int 4892xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4893 const xmlChar *ns_uri, 4894 xmlXPathObjectPtr value) { 4895 if (ctxt == NULL) 4896 return(-1); 4897 if (name == NULL) 4898 return(-1); 4899 4900 if (ctxt->varHash == NULL) 4901 ctxt->varHash = xmlHashCreate(0); 4902 if (ctxt->varHash == NULL) 4903 return(-1); 4904 if (value == NULL) 4905 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 4906 (xmlHashDeallocator)xmlXPathFreeObject)); 4907 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 4908 (void *) value, 4909 (xmlHashDeallocator)xmlXPathFreeObject)); 4910} 4911 4912/** 4913 * xmlXPathRegisterVariableLookup: 4914 * @ctxt: the XPath context 4915 * @f: the lookup function 4916 * @data: the lookup data 4917 * 4918 * register an external mechanism to do variable lookup 4919 */ 4920void 4921xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 4922 xmlXPathVariableLookupFunc f, void *data) { 4923 if (ctxt == NULL) 4924 return; 4925 ctxt->varLookupFunc = f; 4926 ctxt->varLookupData = data; 4927} 4928 4929/** 4930 * xmlXPathVariableLookup: 4931 * @ctxt: the XPath context 4932 * @name: the variable name 4933 * 4934 * Search in the Variable array of the context for the given 4935 * variable value. 4936 * 4937 * Returns a copy of the value or NULL if not found 4938 */ 4939xmlXPathObjectPtr 4940xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4941 if (ctxt == NULL) 4942 return(NULL); 4943 4944 if (ctxt->varLookupFunc != NULL) { 4945 xmlXPathObjectPtr ret; 4946 4947 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 4948 (ctxt->varLookupData, name, NULL); 4949 return(ret); 4950 } 4951 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 4952} 4953 4954/** 4955 * xmlXPathVariableLookupNS: 4956 * @ctxt: the XPath context 4957 * @name: the variable name 4958 * @ns_uri: the variable namespace URI 4959 * 4960 * Search in the Variable array of the context for the given 4961 * variable value. 4962 * 4963 * Returns the a copy of the value or NULL if not found 4964 */ 4965xmlXPathObjectPtr 4966xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4967 const xmlChar *ns_uri) { 4968 if (ctxt == NULL) 4969 return(NULL); 4970 4971 if (ctxt->varLookupFunc != NULL) { 4972 xmlXPathObjectPtr ret; 4973 4974 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 4975 (ctxt->varLookupData, name, ns_uri); 4976 if (ret != NULL) return(ret); 4977 } 4978 4979 if (ctxt->varHash == NULL) 4980 return(NULL); 4981 if (name == NULL) 4982 return(NULL); 4983 4984 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 4985 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 4986} 4987 4988/** 4989 * xmlXPathRegisteredVariablesCleanup: 4990 * @ctxt: the XPath context 4991 * 4992 * Cleanup the XPath context data associated to registered variables 4993 */ 4994void 4995xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 4996 if (ctxt == NULL) 4997 return; 4998 4999 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 5000 ctxt->varHash = NULL; 5001} 5002 5003/** 5004 * xmlXPathRegisterNs: 5005 * @ctxt: the XPath context 5006 * @prefix: the namespace prefix cannot be NULL or empty string 5007 * @ns_uri: the namespace name 5008 * 5009 * Register a new namespace. If @ns_uri is NULL it unregisters 5010 * the namespace 5011 * 5012 * Returns 0 in case of success, -1 in case of error 5013 */ 5014int 5015xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5016 const xmlChar *ns_uri) { 5017 if (ctxt == NULL) 5018 return(-1); 5019 if (prefix == NULL) 5020 return(-1); 5021 if (prefix[0] == 0) 5022 return(-1); 5023 5024 if (ctxt->nsHash == NULL) 5025 ctxt->nsHash = xmlHashCreate(10); 5026 if (ctxt->nsHash == NULL) 5027 return(-1); 5028 if (ns_uri == NULL) 5029 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5030 (xmlHashDeallocator)xmlFree)); 5031 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 5032 (xmlHashDeallocator)xmlFree)); 5033} 5034 5035/** 5036 * xmlXPathNsLookup: 5037 * @ctxt: the XPath context 5038 * @prefix: the namespace prefix value 5039 * 5040 * Search in the namespace declaration array of the context for the given 5041 * namespace name associated to the given prefix 5042 * 5043 * Returns the value or NULL if not found 5044 */ 5045const xmlChar * 5046xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 5047 if (ctxt == NULL) 5048 return(NULL); 5049 if (prefix == NULL) 5050 return(NULL); 5051 5052#ifdef XML_XML_NAMESPACE 5053 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 5054 return(XML_XML_NAMESPACE); 5055#endif 5056 5057 if (ctxt->namespaces != NULL) { 5058 int i; 5059 5060 for (i = 0;i < ctxt->nsNr;i++) { 5061 if ((ctxt->namespaces[i] != NULL) && 5062 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 5063 return(ctxt->namespaces[i]->href); 5064 } 5065 } 5066 5067 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 5068} 5069 5070/** 5071 * xmlXPathRegisteredNsCleanup: 5072 * @ctxt: the XPath context 5073 * 5074 * Cleanup the XPath context data associated to registered variables 5075 */ 5076void 5077xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 5078 if (ctxt == NULL) 5079 return; 5080 5081 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); 5082 ctxt->nsHash = NULL; 5083} 5084 5085/************************************************************************ 5086 * * 5087 * Routines to handle Values * 5088 * * 5089 ************************************************************************/ 5090 5091/* Allocations are terrible, one needs to optimize all this !!! */ 5092 5093/** 5094 * xmlXPathNewFloat: 5095 * @val: the double value 5096 * 5097 * Create a new xmlXPathObjectPtr of type double and of value @val 5098 * 5099 * Returns the newly created object. 5100 */ 5101xmlXPathObjectPtr 5102xmlXPathNewFloat(double val) { 5103 xmlXPathObjectPtr ret; 5104 5105 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5106 if (ret == NULL) { 5107 xmlXPathErrMemory(NULL, "creating float object\n"); 5108 return(NULL); 5109 } 5110 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5111 ret->type = XPATH_NUMBER; 5112 ret->floatval = val; 5113#ifdef XP_DEBUG_OBJ_USAGE 5114 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 5115#endif 5116 return(ret); 5117} 5118 5119/** 5120 * xmlXPathNewBoolean: 5121 * @val: the boolean value 5122 * 5123 * Create a new xmlXPathObjectPtr of type boolean and of value @val 5124 * 5125 * Returns the newly created object. 5126 */ 5127xmlXPathObjectPtr 5128xmlXPathNewBoolean(int val) { 5129 xmlXPathObjectPtr ret; 5130 5131 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5132 if (ret == NULL) { 5133 xmlXPathErrMemory(NULL, "creating boolean object\n"); 5134 return(NULL); 5135 } 5136 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5137 ret->type = XPATH_BOOLEAN; 5138 ret->boolval = (val != 0); 5139#ifdef XP_DEBUG_OBJ_USAGE 5140 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 5141#endif 5142 return(ret); 5143} 5144 5145/** 5146 * xmlXPathNewString: 5147 * @val: the xmlChar * value 5148 * 5149 * Create a new xmlXPathObjectPtr of type string and of value @val 5150 * 5151 * Returns the newly created object. 5152 */ 5153xmlXPathObjectPtr 5154xmlXPathNewString(const xmlChar *val) { 5155 xmlXPathObjectPtr ret; 5156 5157 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5158 if (ret == NULL) { 5159 xmlXPathErrMemory(NULL, "creating string object\n"); 5160 return(NULL); 5161 } 5162 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5163 ret->type = XPATH_STRING; 5164 if (val != NULL) 5165 ret->stringval = xmlStrdup(val); 5166 else 5167 ret->stringval = xmlStrdup((const xmlChar *)""); 5168#ifdef XP_DEBUG_OBJ_USAGE 5169 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5170#endif 5171 return(ret); 5172} 5173 5174/** 5175 * xmlXPathWrapString: 5176 * @val: the xmlChar * value 5177 * 5178 * Wraps the @val string into an XPath object. 5179 * 5180 * Returns the newly created object. 5181 */ 5182xmlXPathObjectPtr 5183xmlXPathWrapString (xmlChar *val) { 5184 xmlXPathObjectPtr ret; 5185 5186 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5187 if (ret == NULL) { 5188 xmlXPathErrMemory(NULL, "creating string object\n"); 5189 return(NULL); 5190 } 5191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5192 ret->type = XPATH_STRING; 5193 ret->stringval = val; 5194#ifdef XP_DEBUG_OBJ_USAGE 5195 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5196#endif 5197 return(ret); 5198} 5199 5200/** 5201 * xmlXPathNewCString: 5202 * @val: the char * value 5203 * 5204 * Create a new xmlXPathObjectPtr of type string and of value @val 5205 * 5206 * Returns the newly created object. 5207 */ 5208xmlXPathObjectPtr 5209xmlXPathNewCString(const char *val) { 5210 xmlXPathObjectPtr ret; 5211 5212 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5213 if (ret == NULL) { 5214 xmlXPathErrMemory(NULL, "creating string object\n"); 5215 return(NULL); 5216 } 5217 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5218 ret->type = XPATH_STRING; 5219 ret->stringval = xmlStrdup(BAD_CAST val); 5220#ifdef XP_DEBUG_OBJ_USAGE 5221 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 5222#endif 5223 return(ret); 5224} 5225 5226/** 5227 * xmlXPathWrapCString: 5228 * @val: the char * value 5229 * 5230 * Wraps a string into an XPath object. 5231 * 5232 * Returns the newly created object. 5233 */ 5234xmlXPathObjectPtr 5235xmlXPathWrapCString (char * val) { 5236 return(xmlXPathWrapString((xmlChar *)(val))); 5237} 5238 5239/** 5240 * xmlXPathWrapExternal: 5241 * @val: the user data 5242 * 5243 * Wraps the @val data into an XPath object. 5244 * 5245 * Returns the newly created object. 5246 */ 5247xmlXPathObjectPtr 5248xmlXPathWrapExternal (void *val) { 5249 xmlXPathObjectPtr ret; 5250 5251 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5252 if (ret == NULL) { 5253 xmlXPathErrMemory(NULL, "creating user object\n"); 5254 return(NULL); 5255 } 5256 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 5257 ret->type = XPATH_USERS; 5258 ret->user = val; 5259#ifdef XP_DEBUG_OBJ_USAGE 5260 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 5261#endif 5262 return(ret); 5263} 5264 5265/** 5266 * xmlXPathObjectCopy: 5267 * @val: the original object 5268 * 5269 * allocate a new copy of a given object 5270 * 5271 * Returns the newly created object. 5272 */ 5273xmlXPathObjectPtr 5274xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5275 xmlXPathObjectPtr ret; 5276 5277 if (val == NULL) 5278 return(NULL); 5279 5280 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5281 if (ret == NULL) { 5282 xmlXPathErrMemory(NULL, "copying object\n"); 5283 return(NULL); 5284 } 5285 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5286#ifdef XP_DEBUG_OBJ_USAGE 5287 xmlXPathDebugObjUsageRequested(NULL, val->type); 5288#endif 5289 switch (val->type) { 5290 case XPATH_BOOLEAN: 5291 case XPATH_NUMBER: 5292 case XPATH_POINT: 5293 case XPATH_RANGE: 5294 break; 5295 case XPATH_STRING: 5296 ret->stringval = xmlStrdup(val->stringval); 5297 break; 5298 case XPATH_XSLT_TREE: 5299#if 0 5300/* 5301 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5302 this previous handling is no longer correct, and can cause some serious 5303 problems (ref. bug 145547) 5304*/ 5305 if ((val->nodesetval != NULL) && 5306 (val->nodesetval->nodeTab != NULL)) { 5307 xmlNodePtr cur, tmp; 5308 xmlDocPtr top; 5309 5310 ret->boolval = 1; 5311 top = xmlNewDoc(NULL); 5312 top->name = (char *) 5313 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5314 ret->user = top; 5315 if (top != NULL) { 5316 top->doc = top; 5317 cur = val->nodesetval->nodeTab[0]->children; 5318 while (cur != NULL) { 5319 tmp = xmlDocCopyNode(cur, top, 1); 5320 xmlAddChild((xmlNodePtr) top, tmp); 5321 cur = cur->next; 5322 } 5323 } 5324 5325 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5326 } else 5327 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5328 /* Deallocate the copied tree value */ 5329 break; 5330#endif 5331 case XPATH_NODESET: 5332 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5333 /* Do not deallocate the copied tree value */ 5334 ret->boolval = 0; 5335 break; 5336 case XPATH_LOCATIONSET: 5337#ifdef LIBXML_XPTR_ENABLED 5338 { 5339 xmlLocationSetPtr loc = val->user; 5340 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5341 break; 5342 } 5343#endif 5344 case XPATH_USERS: 5345 ret->user = val->user; 5346 break; 5347 case XPATH_UNDEFINED: 5348 xmlGenericError(xmlGenericErrorContext, 5349 "xmlXPathObjectCopy: unsupported type %d\n", 5350 val->type); 5351 break; 5352 } 5353 return(ret); 5354} 5355 5356/** 5357 * xmlXPathFreeObject: 5358 * @obj: the object to free 5359 * 5360 * Free up an xmlXPathObjectPtr object. 5361 */ 5362void 5363xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5364 if (obj == NULL) return; 5365 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5366 if (obj->boolval) { 5367#if 0 5368 if (obj->user != NULL) { 5369 xmlXPathFreeNodeSet(obj->nodesetval); 5370 xmlFreeNodeList((xmlNodePtr) obj->user); 5371 } else 5372#endif 5373 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5374 if (obj->nodesetval != NULL) 5375 xmlXPathFreeValueTree(obj->nodesetval); 5376 } else { 5377 if (obj->nodesetval != NULL) 5378 xmlXPathFreeNodeSet(obj->nodesetval); 5379 } 5380#ifdef LIBXML_XPTR_ENABLED 5381 } else if (obj->type == XPATH_LOCATIONSET) { 5382 if (obj->user != NULL) 5383 xmlXPtrFreeLocationSet(obj->user); 5384#endif 5385 } else if (obj->type == XPATH_STRING) { 5386 if (obj->stringval != NULL) 5387 xmlFree(obj->stringval); 5388 } 5389#ifdef XP_DEBUG_OBJ_USAGE 5390 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5391#endif 5392 xmlFree(obj); 5393} 5394 5395/** 5396 * xmlXPathReleaseObject: 5397 * @obj: the xmlXPathObjectPtr to free or to cache 5398 * 5399 * Depending on the state of the cache this frees the given 5400 * XPath object or stores it in the cache. 5401 */ 5402static void 5403xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5404{ 5405#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5406 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5407 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5408 5409#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5410 5411 if (obj == NULL) 5412 return; 5413 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5414 xmlXPathFreeObject(obj); 5415 } else { 5416 xmlXPathContextCachePtr cache = 5417 (xmlXPathContextCachePtr) ctxt->cache; 5418 5419 switch (obj->type) { 5420 case XPATH_NODESET: 5421 case XPATH_XSLT_TREE: 5422 if (obj->nodesetval != NULL) { 5423 if (obj->boolval) { 5424 /* 5425 * It looks like the @boolval is used for 5426 * evaluation if this an XSLT Result Tree Fragment. 5427 * TODO: Check if this assumption is correct. 5428 */ 5429 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5430 xmlXPathFreeValueTree(obj->nodesetval); 5431 obj->nodesetval = NULL; 5432 } else if ((obj->nodesetval->nodeMax <= 40) && 5433 (XP_CACHE_WANTS(cache->nodesetObjs, 5434 cache->maxNodeset))) 5435 { 5436 XP_CACHE_ADD(cache->nodesetObjs, obj); 5437 goto obj_cached; 5438 } else { 5439 xmlXPathFreeNodeSet(obj->nodesetval); 5440 obj->nodesetval = NULL; 5441 } 5442 } 5443 break; 5444 case XPATH_STRING: 5445 if (obj->stringval != NULL) 5446 xmlFree(obj->stringval); 5447 5448 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5449 XP_CACHE_ADD(cache->stringObjs, obj); 5450 goto obj_cached; 5451 } 5452 break; 5453 case XPATH_BOOLEAN: 5454 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5455 XP_CACHE_ADD(cache->booleanObjs, obj); 5456 goto obj_cached; 5457 } 5458 break; 5459 case XPATH_NUMBER: 5460 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5461 XP_CACHE_ADD(cache->numberObjs, obj); 5462 goto obj_cached; 5463 } 5464 break; 5465#ifdef LIBXML_XPTR_ENABLED 5466 case XPATH_LOCATIONSET: 5467 if (obj->user != NULL) { 5468 xmlXPtrFreeLocationSet(obj->user); 5469 } 5470 goto free_obj; 5471#endif 5472 default: 5473 goto free_obj; 5474 } 5475 5476 /* 5477 * Fallback to adding to the misc-objects slot. 5478 */ 5479 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5480 XP_CACHE_ADD(cache->miscObjs, obj); 5481 } else 5482 goto free_obj; 5483 5484obj_cached: 5485 5486#ifdef XP_DEBUG_OBJ_USAGE 5487 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5488#endif 5489 5490 if (obj->nodesetval != NULL) { 5491 xmlNodeSetPtr tmpset = obj->nodesetval; 5492 5493 /* 5494 * TODO: Due to those nasty ns-nodes, we need to traverse 5495 * the list and free the ns-nodes. 5496 * URGENT TODO: Check if it's actually slowing things down. 5497 * Maybe we shouldn't try to preserve the list. 5498 */ 5499 if (tmpset->nodeNr > 1) { 5500 int i; 5501 xmlNodePtr node; 5502 5503 for (i = 0; i < tmpset->nodeNr; i++) { 5504 node = tmpset->nodeTab[i]; 5505 if ((node != NULL) && 5506 (node->type == XML_NAMESPACE_DECL)) 5507 { 5508 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5509 } 5510 } 5511 } else if (tmpset->nodeNr == 1) { 5512 if ((tmpset->nodeTab[0] != NULL) && 5513 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5514 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5515 } 5516 tmpset->nodeNr = 0; 5517 memset(obj, 0, sizeof(xmlXPathObject)); 5518 obj->nodesetval = tmpset; 5519 } else 5520 memset(obj, 0, sizeof(xmlXPathObject)); 5521 5522 return; 5523 5524free_obj: 5525 /* 5526 * Cache is full; free the object. 5527 */ 5528 if (obj->nodesetval != NULL) 5529 xmlXPathFreeNodeSet(obj->nodesetval); 5530#ifdef XP_DEBUG_OBJ_USAGE 5531 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5532#endif 5533 xmlFree(obj); 5534 } 5535 return; 5536} 5537 5538 5539/************************************************************************ 5540 * * 5541 * Type Casting Routines * 5542 * * 5543 ************************************************************************/ 5544 5545/** 5546 * xmlXPathCastBooleanToString: 5547 * @val: a boolean 5548 * 5549 * Converts a boolean to its string value. 5550 * 5551 * Returns a newly allocated string. 5552 */ 5553xmlChar * 5554xmlXPathCastBooleanToString (int val) { 5555 xmlChar *ret; 5556 if (val) 5557 ret = xmlStrdup((const xmlChar *) "true"); 5558 else 5559 ret = xmlStrdup((const xmlChar *) "false"); 5560 return(ret); 5561} 5562 5563/** 5564 * xmlXPathCastNumberToString: 5565 * @val: a number 5566 * 5567 * Converts a number to its string value. 5568 * 5569 * Returns a newly allocated string. 5570 */ 5571xmlChar * 5572xmlXPathCastNumberToString (double val) { 5573 xmlChar *ret; 5574 switch (xmlXPathIsInf(val)) { 5575 case 1: 5576 ret = xmlStrdup((const xmlChar *) "Infinity"); 5577 break; 5578 case -1: 5579 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5580 break; 5581 default: 5582 if (xmlXPathIsNaN(val)) { 5583 ret = xmlStrdup((const xmlChar *) "NaN"); 5584 } else if (val == 0 && xmlXPathGetSign(val) != 0) { 5585 ret = xmlStrdup((const xmlChar *) "0"); 5586 } else { 5587 /* could be improved */ 5588 char buf[100]; 5589 xmlXPathFormatNumber(val, buf, 99); 5590 buf[99] = 0; 5591 ret = xmlStrdup((const xmlChar *) buf); 5592 } 5593 } 5594 return(ret); 5595} 5596 5597/** 5598 * xmlXPathCastNodeToString: 5599 * @node: a node 5600 * 5601 * Converts a node to its string value. 5602 * 5603 * Returns a newly allocated string. 5604 */ 5605xmlChar * 5606xmlXPathCastNodeToString (xmlNodePtr node) { 5607xmlChar *ret; 5608 if ((ret = xmlNodeGetContent(node)) == NULL) 5609 ret = xmlStrdup((const xmlChar *) ""); 5610 return(ret); 5611} 5612 5613/** 5614 * xmlXPathCastNodeSetToString: 5615 * @ns: a node-set 5616 * 5617 * Converts a node-set to its string value. 5618 * 5619 * Returns a newly allocated string. 5620 */ 5621xmlChar * 5622xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5623 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5624 return(xmlStrdup((const xmlChar *) "")); 5625 5626 if (ns->nodeNr > 1) 5627 xmlXPathNodeSetSort(ns); 5628 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5629} 5630 5631/** 5632 * xmlXPathCastToString: 5633 * @val: an XPath object 5634 * 5635 * Converts an existing object to its string() equivalent 5636 * 5637 * Returns the allocated string value of the object, NULL in case of error. 5638 * It's up to the caller to free the string memory with xmlFree(). 5639 */ 5640xmlChar * 5641xmlXPathCastToString(xmlXPathObjectPtr val) { 5642 xmlChar *ret = NULL; 5643 5644 if (val == NULL) 5645 return(xmlStrdup((const xmlChar *) "")); 5646 switch (val->type) { 5647 case XPATH_UNDEFINED: 5648#ifdef DEBUG_EXPR 5649 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5650#endif 5651 ret = xmlStrdup((const xmlChar *) ""); 5652 break; 5653 case XPATH_NODESET: 5654 case XPATH_XSLT_TREE: 5655 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5656 break; 5657 case XPATH_STRING: 5658 return(xmlStrdup(val->stringval)); 5659 case XPATH_BOOLEAN: 5660 ret = xmlXPathCastBooleanToString(val->boolval); 5661 break; 5662 case XPATH_NUMBER: { 5663 ret = xmlXPathCastNumberToString(val->floatval); 5664 break; 5665 } 5666 case XPATH_USERS: 5667 case XPATH_POINT: 5668 case XPATH_RANGE: 5669 case XPATH_LOCATIONSET: 5670 TODO 5671 ret = xmlStrdup((const xmlChar *) ""); 5672 break; 5673 } 5674 return(ret); 5675} 5676 5677/** 5678 * xmlXPathConvertString: 5679 * @val: an XPath object 5680 * 5681 * Converts an existing object to its string() equivalent 5682 * 5683 * Returns the new object, the old one is freed (or the operation 5684 * is done directly on @val) 5685 */ 5686xmlXPathObjectPtr 5687xmlXPathConvertString(xmlXPathObjectPtr val) { 5688 xmlChar *res = NULL; 5689 5690 if (val == NULL) 5691 return(xmlXPathNewCString("")); 5692 5693 switch (val->type) { 5694 case XPATH_UNDEFINED: 5695#ifdef DEBUG_EXPR 5696 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5697#endif 5698 break; 5699 case XPATH_NODESET: 5700 case XPATH_XSLT_TREE: 5701 res = xmlXPathCastNodeSetToString(val->nodesetval); 5702 break; 5703 case XPATH_STRING: 5704 return(val); 5705 case XPATH_BOOLEAN: 5706 res = xmlXPathCastBooleanToString(val->boolval); 5707 break; 5708 case XPATH_NUMBER: 5709 res = xmlXPathCastNumberToString(val->floatval); 5710 break; 5711 case XPATH_USERS: 5712 case XPATH_POINT: 5713 case XPATH_RANGE: 5714 case XPATH_LOCATIONSET: 5715 TODO; 5716 break; 5717 } 5718 xmlXPathFreeObject(val); 5719 if (res == NULL) 5720 return(xmlXPathNewCString("")); 5721 return(xmlXPathWrapString(res)); 5722} 5723 5724/** 5725 * xmlXPathCastBooleanToNumber: 5726 * @val: a boolean 5727 * 5728 * Converts a boolean to its number value 5729 * 5730 * Returns the number value 5731 */ 5732double 5733xmlXPathCastBooleanToNumber(int val) { 5734 if (val) 5735 return(1.0); 5736 return(0.0); 5737} 5738 5739/** 5740 * xmlXPathCastStringToNumber: 5741 * @val: a string 5742 * 5743 * Converts a string to its number value 5744 * 5745 * Returns the number value 5746 */ 5747double 5748xmlXPathCastStringToNumber(const xmlChar * val) { 5749 return(xmlXPathStringEvalNumber(val)); 5750} 5751 5752/** 5753 * xmlXPathCastNodeToNumber: 5754 * @node: a node 5755 * 5756 * Converts a node to its number value 5757 * 5758 * Returns the number value 5759 */ 5760double 5761xmlXPathCastNodeToNumber (xmlNodePtr node) { 5762 xmlChar *strval; 5763 double ret; 5764 5765 if (node == NULL) 5766 return(xmlXPathNAN); 5767 strval = xmlXPathCastNodeToString(node); 5768 if (strval == NULL) 5769 return(xmlXPathNAN); 5770 ret = xmlXPathCastStringToNumber(strval); 5771 xmlFree(strval); 5772 5773 return(ret); 5774} 5775 5776/** 5777 * xmlXPathCastNodeSetToNumber: 5778 * @ns: a node-set 5779 * 5780 * Converts a node-set to its number value 5781 * 5782 * Returns the number value 5783 */ 5784double 5785xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5786 xmlChar *str; 5787 double ret; 5788 5789 if (ns == NULL) 5790 return(xmlXPathNAN); 5791 str = xmlXPathCastNodeSetToString(ns); 5792 ret = xmlXPathCastStringToNumber(str); 5793 xmlFree(str); 5794 return(ret); 5795} 5796 5797/** 5798 * xmlXPathCastToNumber: 5799 * @val: an XPath object 5800 * 5801 * Converts an XPath object to its number value 5802 * 5803 * Returns the number value 5804 */ 5805double 5806xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5807 double ret = 0.0; 5808 5809 if (val == NULL) 5810 return(xmlXPathNAN); 5811 switch (val->type) { 5812 case XPATH_UNDEFINED: 5813#ifdef DEGUB_EXPR 5814 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5815#endif 5816 ret = xmlXPathNAN; 5817 break; 5818 case XPATH_NODESET: 5819 case XPATH_XSLT_TREE: 5820 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5821 break; 5822 case XPATH_STRING: 5823 ret = xmlXPathCastStringToNumber(val->stringval); 5824 break; 5825 case XPATH_NUMBER: 5826 ret = val->floatval; 5827 break; 5828 case XPATH_BOOLEAN: 5829 ret = xmlXPathCastBooleanToNumber(val->boolval); 5830 break; 5831 case XPATH_USERS: 5832 case XPATH_POINT: 5833 case XPATH_RANGE: 5834 case XPATH_LOCATIONSET: 5835 TODO; 5836 ret = xmlXPathNAN; 5837 break; 5838 } 5839 return(ret); 5840} 5841 5842/** 5843 * xmlXPathConvertNumber: 5844 * @val: an XPath object 5845 * 5846 * Converts an existing object to its number() equivalent 5847 * 5848 * Returns the new object, the old one is freed (or the operation 5849 * is done directly on @val) 5850 */ 5851xmlXPathObjectPtr 5852xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5853 xmlXPathObjectPtr ret; 5854 5855 if (val == NULL) 5856 return(xmlXPathNewFloat(0.0)); 5857 if (val->type == XPATH_NUMBER) 5858 return(val); 5859 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5860 xmlXPathFreeObject(val); 5861 return(ret); 5862} 5863 5864/** 5865 * xmlXPathCastNumberToBoolean: 5866 * @val: a number 5867 * 5868 * Converts a number to its boolean value 5869 * 5870 * Returns the boolean value 5871 */ 5872int 5873xmlXPathCastNumberToBoolean (double val) { 5874 if (xmlXPathIsNaN(val) || (val == 0.0)) 5875 return(0); 5876 return(1); 5877} 5878 5879/** 5880 * xmlXPathCastStringToBoolean: 5881 * @val: a string 5882 * 5883 * Converts a string to its boolean value 5884 * 5885 * Returns the boolean value 5886 */ 5887int 5888xmlXPathCastStringToBoolean (const xmlChar *val) { 5889 if ((val == NULL) || (xmlStrlen(val) == 0)) 5890 return(0); 5891 return(1); 5892} 5893 5894/** 5895 * xmlXPathCastNodeSetToBoolean: 5896 * @ns: a node-set 5897 * 5898 * Converts a node-set to its boolean value 5899 * 5900 * Returns the boolean value 5901 */ 5902int 5903xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 5904 if ((ns == NULL) || (ns->nodeNr == 0)) 5905 return(0); 5906 return(1); 5907} 5908 5909/** 5910 * xmlXPathCastToBoolean: 5911 * @val: an XPath object 5912 * 5913 * Converts an XPath object to its boolean value 5914 * 5915 * Returns the boolean value 5916 */ 5917int 5918xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 5919 int ret = 0; 5920 5921 if (val == NULL) 5922 return(0); 5923 switch (val->type) { 5924 case XPATH_UNDEFINED: 5925#ifdef DEBUG_EXPR 5926 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 5927#endif 5928 ret = 0; 5929 break; 5930 case XPATH_NODESET: 5931 case XPATH_XSLT_TREE: 5932 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 5933 break; 5934 case XPATH_STRING: 5935 ret = xmlXPathCastStringToBoolean(val->stringval); 5936 break; 5937 case XPATH_NUMBER: 5938 ret = xmlXPathCastNumberToBoolean(val->floatval); 5939 break; 5940 case XPATH_BOOLEAN: 5941 ret = val->boolval; 5942 break; 5943 case XPATH_USERS: 5944 case XPATH_POINT: 5945 case XPATH_RANGE: 5946 case XPATH_LOCATIONSET: 5947 TODO; 5948 ret = 0; 5949 break; 5950 } 5951 return(ret); 5952} 5953 5954 5955/** 5956 * xmlXPathConvertBoolean: 5957 * @val: an XPath object 5958 * 5959 * Converts an existing object to its boolean() equivalent 5960 * 5961 * Returns the new object, the old one is freed (or the operation 5962 * is done directly on @val) 5963 */ 5964xmlXPathObjectPtr 5965xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 5966 xmlXPathObjectPtr ret; 5967 5968 if (val == NULL) 5969 return(xmlXPathNewBoolean(0)); 5970 if (val->type == XPATH_BOOLEAN) 5971 return(val); 5972 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 5973 xmlXPathFreeObject(val); 5974 return(ret); 5975} 5976 5977/************************************************************************ 5978 * * 5979 * Routines to handle XPath contexts * 5980 * * 5981 ************************************************************************/ 5982 5983/** 5984 * xmlXPathNewContext: 5985 * @doc: the XML document 5986 * 5987 * Create a new xmlXPathContext 5988 * 5989 * Returns the xmlXPathContext just allocated. The caller will need to free it. 5990 */ 5991xmlXPathContextPtr 5992xmlXPathNewContext(xmlDocPtr doc) { 5993 xmlXPathContextPtr ret; 5994 5995 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 5996 if (ret == NULL) { 5997 xmlXPathErrMemory(NULL, "creating context\n"); 5998 return(NULL); 5999 } 6000 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 6001 ret->doc = doc; 6002 ret->node = NULL; 6003 6004 ret->varHash = NULL; 6005 6006 ret->nb_types = 0; 6007 ret->max_types = 0; 6008 ret->types = NULL; 6009 6010 ret->funcHash = xmlHashCreate(0); 6011 6012 ret->nb_axis = 0; 6013 ret->max_axis = 0; 6014 ret->axis = NULL; 6015 6016 ret->nsHash = NULL; 6017 ret->user = NULL; 6018 6019 ret->contextSize = -1; 6020 ret->proximityPosition = -1; 6021 6022#ifdef XP_DEFAULT_CACHE_ON 6023 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 6024 xmlXPathFreeContext(ret); 6025 return(NULL); 6026 } 6027#endif 6028 6029 xmlXPathRegisterAllFunctions(ret); 6030 6031 return(ret); 6032} 6033 6034/** 6035 * xmlXPathFreeContext: 6036 * @ctxt: the context to free 6037 * 6038 * Free up an xmlXPathContext 6039 */ 6040void 6041xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 6042 if (ctxt == NULL) return; 6043 6044 if (ctxt->cache != NULL) 6045 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 6046 xmlXPathRegisteredNsCleanup(ctxt); 6047 xmlXPathRegisteredFuncsCleanup(ctxt); 6048 xmlXPathRegisteredVariablesCleanup(ctxt); 6049 xmlResetError(&ctxt->lastError); 6050 xmlFree(ctxt); 6051} 6052 6053/************************************************************************ 6054 * * 6055 * Routines to handle XPath parser contexts * 6056 * * 6057 ************************************************************************/ 6058 6059#define CHECK_CTXT(ctxt) \ 6060 if (ctxt == NULL) { \ 6061 __xmlRaiseError(NULL, NULL, NULL, \ 6062 NULL, NULL, XML_FROM_XPATH, \ 6063 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6064 __FILE__, __LINE__, \ 6065 NULL, NULL, NULL, 0, 0, \ 6066 "NULL context pointer\n"); \ 6067 return(NULL); \ 6068 } \ 6069 6070#define CHECK_CTXT_NEG(ctxt) \ 6071 if (ctxt == NULL) { \ 6072 __xmlRaiseError(NULL, NULL, NULL, \ 6073 NULL, NULL, XML_FROM_XPATH, \ 6074 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 6075 __FILE__, __LINE__, \ 6076 NULL, NULL, NULL, 0, 0, \ 6077 "NULL context pointer\n"); \ 6078 return(-1); \ 6079 } \ 6080 6081 6082#define CHECK_CONTEXT(ctxt) \ 6083 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 6084 (ctxt->doc->children == NULL)) { \ 6085 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 6086 return(NULL); \ 6087 } 6088 6089 6090/** 6091 * xmlXPathNewParserContext: 6092 * @str: the XPath expression 6093 * @ctxt: the XPath context 6094 * 6095 * Create a new xmlXPathParserContext 6096 * 6097 * Returns the xmlXPathParserContext just allocated. 6098 */ 6099xmlXPathParserContextPtr 6100xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 6101 xmlXPathParserContextPtr ret; 6102 6103 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6104 if (ret == NULL) { 6105 xmlXPathErrMemory(ctxt, "creating parser context\n"); 6106 return(NULL); 6107 } 6108 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6109 ret->cur = ret->base = str; 6110 ret->context = ctxt; 6111 6112 ret->comp = xmlXPathNewCompExpr(); 6113 if (ret->comp == NULL) { 6114 xmlFree(ret->valueTab); 6115 xmlFree(ret); 6116 return(NULL); 6117 } 6118 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 6119 ret->comp->dict = ctxt->dict; 6120 xmlDictReference(ret->comp->dict); 6121 } 6122 6123 return(ret); 6124} 6125 6126/** 6127 * xmlXPathCompParserContext: 6128 * @comp: the XPath compiled expression 6129 * @ctxt: the XPath context 6130 * 6131 * Create a new xmlXPathParserContext when processing a compiled expression 6132 * 6133 * Returns the xmlXPathParserContext just allocated. 6134 */ 6135static xmlXPathParserContextPtr 6136xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 6137 xmlXPathParserContextPtr ret; 6138 6139 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 6140 if (ret == NULL) { 6141 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6142 return(NULL); 6143 } 6144 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 6145 6146 /* Allocate the value stack */ 6147 ret->valueTab = (xmlXPathObjectPtr *) 6148 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 6149 if (ret->valueTab == NULL) { 6150 xmlFree(ret); 6151 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 6152 return(NULL); 6153 } 6154 ret->valueNr = 0; 6155 ret->valueMax = 10; 6156 ret->value = NULL; 6157 6158 ret->context = ctxt; 6159 ret->comp = comp; 6160 6161 return(ret); 6162} 6163 6164/** 6165 * xmlXPathFreeParserContext: 6166 * @ctxt: the context to free 6167 * 6168 * Free up an xmlXPathParserContext 6169 */ 6170void 6171xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 6172 if (ctxt->valueTab != NULL) { 6173 xmlFree(ctxt->valueTab); 6174 } 6175 if (ctxt->comp != NULL) { 6176#ifdef XPATH_STREAMING 6177 if (ctxt->comp->stream != NULL) { 6178 xmlFreePatternList(ctxt->comp->stream); 6179 ctxt->comp->stream = NULL; 6180 } 6181#endif 6182 xmlXPathFreeCompExpr(ctxt->comp); 6183 } 6184 xmlFree(ctxt); 6185} 6186 6187/************************************************************************ 6188 * * 6189 * The implicit core function library * 6190 * * 6191 ************************************************************************/ 6192 6193/** 6194 * xmlXPathNodeValHash: 6195 * @node: a node pointer 6196 * 6197 * Function computing the beginning of the string value of the node, 6198 * used to speed up comparisons 6199 * 6200 * Returns an int usable as a hash 6201 */ 6202static unsigned int 6203xmlXPathNodeValHash(xmlNodePtr node) { 6204 int len = 2; 6205 const xmlChar * string = NULL; 6206 xmlNodePtr tmp = NULL; 6207 unsigned int ret = 0; 6208 6209 if (node == NULL) 6210 return(0); 6211 6212 if (node->type == XML_DOCUMENT_NODE) { 6213 tmp = xmlDocGetRootElement((xmlDocPtr) node); 6214 if (tmp == NULL) 6215 node = node->children; 6216 else 6217 node = tmp; 6218 6219 if (node == NULL) 6220 return(0); 6221 } 6222 6223 switch (node->type) { 6224 case XML_COMMENT_NODE: 6225 case XML_PI_NODE: 6226 case XML_CDATA_SECTION_NODE: 6227 case XML_TEXT_NODE: 6228 string = node->content; 6229 if (string == NULL) 6230 return(0); 6231 if (string[0] == 0) 6232 return(0); 6233 return(((unsigned int) string[0]) + 6234 (((unsigned int) string[1]) << 8)); 6235 case XML_NAMESPACE_DECL: 6236 string = ((xmlNsPtr)node)->href; 6237 if (string == NULL) 6238 return(0); 6239 if (string[0] == 0) 6240 return(0); 6241 return(((unsigned int) string[0]) + 6242 (((unsigned int) string[1]) << 8)); 6243 case XML_ATTRIBUTE_NODE: 6244 tmp = ((xmlAttrPtr) node)->children; 6245 break; 6246 case XML_ELEMENT_NODE: 6247 tmp = node->children; 6248 break; 6249 default: 6250 return(0); 6251 } 6252 while (tmp != NULL) { 6253 switch (tmp->type) { 6254 case XML_COMMENT_NODE: 6255 case XML_PI_NODE: 6256 case XML_CDATA_SECTION_NODE: 6257 case XML_TEXT_NODE: 6258 string = tmp->content; 6259 break; 6260 case XML_NAMESPACE_DECL: 6261 string = ((xmlNsPtr)tmp)->href; 6262 break; 6263 default: 6264 break; 6265 } 6266 if ((string != NULL) && (string[0] != 0)) { 6267 if (len == 1) { 6268 return(ret + (((unsigned int) string[0]) << 8)); 6269 } 6270 if (string[1] == 0) { 6271 len = 1; 6272 ret = (unsigned int) string[0]; 6273 } else { 6274 return(((unsigned int) string[0]) + 6275 (((unsigned int) string[1]) << 8)); 6276 } 6277 } 6278 /* 6279 * Skip to next node 6280 */ 6281 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 6282 if (tmp->children->type != XML_ENTITY_DECL) { 6283 tmp = tmp->children; 6284 continue; 6285 } 6286 } 6287 if (tmp == node) 6288 break; 6289 6290 if (tmp->next != NULL) { 6291 tmp = tmp->next; 6292 continue; 6293 } 6294 6295 do { 6296 tmp = tmp->parent; 6297 if (tmp == NULL) 6298 break; 6299 if (tmp == node) { 6300 tmp = NULL; 6301 break; 6302 } 6303 if (tmp->next != NULL) { 6304 tmp = tmp->next; 6305 break; 6306 } 6307 } while (tmp != NULL); 6308 } 6309 return(ret); 6310} 6311 6312/** 6313 * xmlXPathStringHash: 6314 * @string: a string 6315 * 6316 * Function computing the beginning of the string value of the node, 6317 * used to speed up comparisons 6318 * 6319 * Returns an int usable as a hash 6320 */ 6321static unsigned int 6322xmlXPathStringHash(const xmlChar * string) { 6323 if (string == NULL) 6324 return((unsigned int) 0); 6325 if (string[0] == 0) 6326 return(0); 6327 return(((unsigned int) string[0]) + 6328 (((unsigned int) string[1]) << 8)); 6329} 6330 6331/** 6332 * xmlXPathCompareNodeSetFloat: 6333 * @ctxt: the XPath Parser context 6334 * @inf: less than (1) or greater than (0) 6335 * @strict: is the comparison strict 6336 * @arg: the node set 6337 * @f: the value 6338 * 6339 * Implement the compare operation between a nodeset and a number 6340 * @ns < @val (1, 1, ... 6341 * @ns <= @val (1, 0, ... 6342 * @ns > @val (0, 1, ... 6343 * @ns >= @val (0, 0, ... 6344 * 6345 * If one object to be compared is a node-set and the other is a number, 6346 * then the comparison will be true if and only if there is a node in the 6347 * node-set such that the result of performing the comparison on the number 6348 * to be compared and on the result of converting the string-value of that 6349 * node to a number using the number function is true. 6350 * 6351 * Returns 0 or 1 depending on the results of the test. 6352 */ 6353static int 6354xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6355 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6356 int i, ret = 0; 6357 xmlNodeSetPtr ns; 6358 xmlChar *str2; 6359 6360 if ((f == NULL) || (arg == NULL) || 6361 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6362 xmlXPathReleaseObject(ctxt->context, arg); 6363 xmlXPathReleaseObject(ctxt->context, f); 6364 return(0); 6365 } 6366 ns = arg->nodesetval; 6367 if (ns != NULL) { 6368 for (i = 0;i < ns->nodeNr;i++) { 6369 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6370 if (str2 != NULL) { 6371 valuePush(ctxt, 6372 xmlXPathCacheNewString(ctxt->context, str2)); 6373 xmlFree(str2); 6374 xmlXPathNumberFunction(ctxt, 1); 6375 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6376 ret = xmlXPathCompareValues(ctxt, inf, strict); 6377 if (ret) 6378 break; 6379 } 6380 } 6381 } 6382 xmlXPathReleaseObject(ctxt->context, arg); 6383 xmlXPathReleaseObject(ctxt->context, f); 6384 return(ret); 6385} 6386 6387/** 6388 * xmlXPathCompareNodeSetString: 6389 * @ctxt: the XPath Parser context 6390 * @inf: less than (1) or greater than (0) 6391 * @strict: is the comparison strict 6392 * @arg: the node set 6393 * @s: the value 6394 * 6395 * Implement the compare operation between a nodeset and a string 6396 * @ns < @val (1, 1, ... 6397 * @ns <= @val (1, 0, ... 6398 * @ns > @val (0, 1, ... 6399 * @ns >= @val (0, 0, ... 6400 * 6401 * If one object to be compared is a node-set and the other is a string, 6402 * then the comparison will be true if and only if there is a node in 6403 * the node-set such that the result of performing the comparison on the 6404 * string-value of the node and the other string is true. 6405 * 6406 * Returns 0 or 1 depending on the results of the test. 6407 */ 6408static int 6409xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6410 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6411 int i, ret = 0; 6412 xmlNodeSetPtr ns; 6413 xmlChar *str2; 6414 6415 if ((s == NULL) || (arg == NULL) || 6416 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6417 xmlXPathReleaseObject(ctxt->context, arg); 6418 xmlXPathReleaseObject(ctxt->context, s); 6419 return(0); 6420 } 6421 ns = arg->nodesetval; 6422 if (ns != NULL) { 6423 for (i = 0;i < ns->nodeNr;i++) { 6424 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6425 if (str2 != NULL) { 6426 valuePush(ctxt, 6427 xmlXPathCacheNewString(ctxt->context, str2)); 6428 xmlFree(str2); 6429 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6430 ret = xmlXPathCompareValues(ctxt, inf, strict); 6431 if (ret) 6432 break; 6433 } 6434 } 6435 } 6436 xmlXPathReleaseObject(ctxt->context, arg); 6437 xmlXPathReleaseObject(ctxt->context, s); 6438 return(ret); 6439} 6440 6441/** 6442 * xmlXPathCompareNodeSets: 6443 * @inf: less than (1) or greater than (0) 6444 * @strict: is the comparison strict 6445 * @arg1: the first node set object 6446 * @arg2: the second node set object 6447 * 6448 * Implement the compare operation on nodesets: 6449 * 6450 * If both objects to be compared are node-sets, then the comparison 6451 * will be true if and only if there is a node in the first node-set 6452 * and a node in the second node-set such that the result of performing 6453 * the comparison on the string-values of the two nodes is true. 6454 * .... 6455 * When neither object to be compared is a node-set and the operator 6456 * is <=, <, >= or >, then the objects are compared by converting both 6457 * objects to numbers and comparing the numbers according to IEEE 754. 6458 * .... 6459 * The number function converts its argument to a number as follows: 6460 * - a string that consists of optional whitespace followed by an 6461 * optional minus sign followed by a Number followed by whitespace 6462 * is converted to the IEEE 754 number that is nearest (according 6463 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6464 * represented by the string; any other string is converted to NaN 6465 * 6466 * Conclusion all nodes need to be converted first to their string value 6467 * and then the comparison must be done when possible 6468 */ 6469static int 6470xmlXPathCompareNodeSets(int inf, int strict, 6471 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6472 int i, j, init = 0; 6473 double val1; 6474 double *values2; 6475 int ret = 0; 6476 xmlNodeSetPtr ns1; 6477 xmlNodeSetPtr ns2; 6478 6479 if ((arg1 == NULL) || 6480 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6481 xmlXPathFreeObject(arg2); 6482 return(0); 6483 } 6484 if ((arg2 == NULL) || 6485 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6486 xmlXPathFreeObject(arg1); 6487 xmlXPathFreeObject(arg2); 6488 return(0); 6489 } 6490 6491 ns1 = arg1->nodesetval; 6492 ns2 = arg2->nodesetval; 6493 6494 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6495 xmlXPathFreeObject(arg1); 6496 xmlXPathFreeObject(arg2); 6497 return(0); 6498 } 6499 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6500 xmlXPathFreeObject(arg1); 6501 xmlXPathFreeObject(arg2); 6502 return(0); 6503 } 6504 6505 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6506 if (values2 == NULL) { 6507 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6508 xmlXPathFreeObject(arg1); 6509 xmlXPathFreeObject(arg2); 6510 return(0); 6511 } 6512 for (i = 0;i < ns1->nodeNr;i++) { 6513 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6514 if (xmlXPathIsNaN(val1)) 6515 continue; 6516 for (j = 0;j < ns2->nodeNr;j++) { 6517 if (init == 0) { 6518 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6519 } 6520 if (xmlXPathIsNaN(values2[j])) 6521 continue; 6522 if (inf && strict) 6523 ret = (val1 < values2[j]); 6524 else if (inf && !strict) 6525 ret = (val1 <= values2[j]); 6526 else if (!inf && strict) 6527 ret = (val1 > values2[j]); 6528 else if (!inf && !strict) 6529 ret = (val1 >= values2[j]); 6530 if (ret) 6531 break; 6532 } 6533 if (ret) 6534 break; 6535 init = 1; 6536 } 6537 xmlFree(values2); 6538 xmlXPathFreeObject(arg1); 6539 xmlXPathFreeObject(arg2); 6540 return(ret); 6541} 6542 6543/** 6544 * xmlXPathCompareNodeSetValue: 6545 * @ctxt: the XPath Parser context 6546 * @inf: less than (1) or greater than (0) 6547 * @strict: is the comparison strict 6548 * @arg: the node set 6549 * @val: the value 6550 * 6551 * Implement the compare operation between a nodeset and a value 6552 * @ns < @val (1, 1, ... 6553 * @ns <= @val (1, 0, ... 6554 * @ns > @val (0, 1, ... 6555 * @ns >= @val (0, 0, ... 6556 * 6557 * If one object to be compared is a node-set and the other is a boolean, 6558 * then the comparison will be true if and only if the result of performing 6559 * the comparison on the boolean and on the result of converting 6560 * the node-set to a boolean using the boolean function is true. 6561 * 6562 * Returns 0 or 1 depending on the results of the test. 6563 */ 6564static int 6565xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6566 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6567 if ((val == NULL) || (arg == NULL) || 6568 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6569 return(0); 6570 6571 switch(val->type) { 6572 case XPATH_NUMBER: 6573 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6574 case XPATH_NODESET: 6575 case XPATH_XSLT_TREE: 6576 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6577 case XPATH_STRING: 6578 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6579 case XPATH_BOOLEAN: 6580 valuePush(ctxt, arg); 6581 xmlXPathBooleanFunction(ctxt, 1); 6582 valuePush(ctxt, val); 6583 return(xmlXPathCompareValues(ctxt, inf, strict)); 6584 default: 6585 TODO 6586 } 6587 return(0); 6588} 6589 6590/** 6591 * xmlXPathEqualNodeSetString: 6592 * @arg: the nodeset object argument 6593 * @str: the string to compare to. 6594 * @neq: flag to show whether for '=' (0) or '!=' (1) 6595 * 6596 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6597 * If one object to be compared is a node-set and the other is a string, 6598 * then the comparison will be true if and only if there is a node in 6599 * the node-set such that the result of performing the comparison on the 6600 * string-value of the node and the other string is true. 6601 * 6602 * Returns 0 or 1 depending on the results of the test. 6603 */ 6604static int 6605xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6606{ 6607 int i; 6608 xmlNodeSetPtr ns; 6609 xmlChar *str2; 6610 unsigned int hash; 6611 6612 if ((str == NULL) || (arg == NULL) || 6613 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6614 return (0); 6615 ns = arg->nodesetval; 6616 /* 6617 * A NULL nodeset compared with a string is always false 6618 * (since there is no node equal, and no node not equal) 6619 */ 6620 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6621 return (0); 6622 hash = xmlXPathStringHash(str); 6623 for (i = 0; i < ns->nodeNr; i++) { 6624 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6625 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6626 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6627 xmlFree(str2); 6628 if (neq) 6629 continue; 6630 return (1); 6631 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6632 if (neq) 6633 continue; 6634 return (1); 6635 } else if (neq) { 6636 if (str2 != NULL) 6637 xmlFree(str2); 6638 return (1); 6639 } 6640 if (str2 != NULL) 6641 xmlFree(str2); 6642 } else if (neq) 6643 return (1); 6644 } 6645 return (0); 6646} 6647 6648/** 6649 * xmlXPathEqualNodeSetFloat: 6650 * @arg: the nodeset object argument 6651 * @f: the float to compare to 6652 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6653 * 6654 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6655 * If one object to be compared is a node-set and the other is a number, 6656 * then the comparison will be true if and only if there is a node in 6657 * the node-set such that the result of performing the comparison on the 6658 * number to be compared and on the result of converting the string-value 6659 * of that node to a number using the number function is true. 6660 * 6661 * Returns 0 or 1 depending on the results of the test. 6662 */ 6663static int 6664xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6665 xmlXPathObjectPtr arg, double f, int neq) { 6666 int i, ret=0; 6667 xmlNodeSetPtr ns; 6668 xmlChar *str2; 6669 xmlXPathObjectPtr val; 6670 double v; 6671 6672 if ((arg == NULL) || 6673 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6674 return(0); 6675 6676 ns = arg->nodesetval; 6677 if (ns != NULL) { 6678 for (i=0;i<ns->nodeNr;i++) { 6679 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6680 if (str2 != NULL) { 6681 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6682 xmlFree(str2); 6683 xmlXPathNumberFunction(ctxt, 1); 6684 val = valuePop(ctxt); 6685 v = val->floatval; 6686 xmlXPathReleaseObject(ctxt->context, val); 6687 if (!xmlXPathIsNaN(v)) { 6688 if ((!neq) && (v==f)) { 6689 ret = 1; 6690 break; 6691 } else if ((neq) && (v!=f)) { 6692 ret = 1; 6693 break; 6694 } 6695 } else { /* NaN is unequal to any value */ 6696 if (neq) 6697 ret = 1; 6698 } 6699 } 6700 } 6701 } 6702 6703 return(ret); 6704} 6705 6706 6707/** 6708 * xmlXPathEqualNodeSets: 6709 * @arg1: first nodeset object argument 6710 * @arg2: second nodeset object argument 6711 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6712 * 6713 * Implement the equal / not equal operation on XPath nodesets: 6714 * @arg1 == @arg2 or @arg1 != @arg2 6715 * If both objects to be compared are node-sets, then the comparison 6716 * will be true if and only if there is a node in the first node-set and 6717 * a node in the second node-set such that the result of performing the 6718 * comparison on the string-values of the two nodes is true. 6719 * 6720 * (needless to say, this is a costly operation) 6721 * 6722 * Returns 0 or 1 depending on the results of the test. 6723 */ 6724static int 6725xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6726 int i, j; 6727 unsigned int *hashs1; 6728 unsigned int *hashs2; 6729 xmlChar **values1; 6730 xmlChar **values2; 6731 int ret = 0; 6732 xmlNodeSetPtr ns1; 6733 xmlNodeSetPtr ns2; 6734 6735 if ((arg1 == NULL) || 6736 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6737 return(0); 6738 if ((arg2 == NULL) || 6739 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6740 return(0); 6741 6742 ns1 = arg1->nodesetval; 6743 ns2 = arg2->nodesetval; 6744 6745 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6746 return(0); 6747 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6748 return(0); 6749 6750 /* 6751 * for equal, check if there is a node pertaining to both sets 6752 */ 6753 if (neq == 0) 6754 for (i = 0;i < ns1->nodeNr;i++) 6755 for (j = 0;j < ns2->nodeNr;j++) 6756 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6757 return(1); 6758 6759 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6760 if (values1 == NULL) { 6761 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6762 return(0); 6763 } 6764 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6765 if (hashs1 == NULL) { 6766 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6767 xmlFree(values1); 6768 return(0); 6769 } 6770 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6771 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6772 if (values2 == NULL) { 6773 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6774 xmlFree(hashs1); 6775 xmlFree(values1); 6776 return(0); 6777 } 6778 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6779 if (hashs2 == NULL) { 6780 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6781 xmlFree(hashs1); 6782 xmlFree(values1); 6783 xmlFree(values2); 6784 return(0); 6785 } 6786 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6787 for (i = 0;i < ns1->nodeNr;i++) { 6788 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6789 for (j = 0;j < ns2->nodeNr;j++) { 6790 if (i == 0) 6791 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6792 if (hashs1[i] != hashs2[j]) { 6793 if (neq) { 6794 ret = 1; 6795 break; 6796 } 6797 } 6798 else { 6799 if (values1[i] == NULL) 6800 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6801 if (values2[j] == NULL) 6802 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6803 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6804 if (ret) 6805 break; 6806 } 6807 } 6808 if (ret) 6809 break; 6810 } 6811 for (i = 0;i < ns1->nodeNr;i++) 6812 if (values1[i] != NULL) 6813 xmlFree(values1[i]); 6814 for (j = 0;j < ns2->nodeNr;j++) 6815 if (values2[j] != NULL) 6816 xmlFree(values2[j]); 6817 xmlFree(values1); 6818 xmlFree(values2); 6819 xmlFree(hashs1); 6820 xmlFree(hashs2); 6821 return(ret); 6822} 6823 6824static int 6825xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6826 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6827 int ret = 0; 6828 /* 6829 *At this point we are assured neither arg1 nor arg2 6830 *is a nodeset, so we can just pick the appropriate routine. 6831 */ 6832 switch (arg1->type) { 6833 case XPATH_UNDEFINED: 6834#ifdef DEBUG_EXPR 6835 xmlGenericError(xmlGenericErrorContext, 6836 "Equal: undefined\n"); 6837#endif 6838 break; 6839 case XPATH_BOOLEAN: 6840 switch (arg2->type) { 6841 case XPATH_UNDEFINED: 6842#ifdef DEBUG_EXPR 6843 xmlGenericError(xmlGenericErrorContext, 6844 "Equal: undefined\n"); 6845#endif 6846 break; 6847 case XPATH_BOOLEAN: 6848#ifdef DEBUG_EXPR 6849 xmlGenericError(xmlGenericErrorContext, 6850 "Equal: %d boolean %d \n", 6851 arg1->boolval, arg2->boolval); 6852#endif 6853 ret = (arg1->boolval == arg2->boolval); 6854 break; 6855 case XPATH_NUMBER: 6856 ret = (arg1->boolval == 6857 xmlXPathCastNumberToBoolean(arg2->floatval)); 6858 break; 6859 case XPATH_STRING: 6860 if ((arg2->stringval == NULL) || 6861 (arg2->stringval[0] == 0)) ret = 0; 6862 else 6863 ret = 1; 6864 ret = (arg1->boolval == ret); 6865 break; 6866 case XPATH_USERS: 6867 case XPATH_POINT: 6868 case XPATH_RANGE: 6869 case XPATH_LOCATIONSET: 6870 TODO 6871 break; 6872 case XPATH_NODESET: 6873 case XPATH_XSLT_TREE: 6874 break; 6875 } 6876 break; 6877 case XPATH_NUMBER: 6878 switch (arg2->type) { 6879 case XPATH_UNDEFINED: 6880#ifdef DEBUG_EXPR 6881 xmlGenericError(xmlGenericErrorContext, 6882 "Equal: undefined\n"); 6883#endif 6884 break; 6885 case XPATH_BOOLEAN: 6886 ret = (arg2->boolval== 6887 xmlXPathCastNumberToBoolean(arg1->floatval)); 6888 break; 6889 case XPATH_STRING: 6890 valuePush(ctxt, arg2); 6891 xmlXPathNumberFunction(ctxt, 1); 6892 arg2 = valuePop(ctxt); 6893 /* no break on purpose */ 6894 case XPATH_NUMBER: 6895 /* Hand check NaN and Infinity equalities */ 6896 if (xmlXPathIsNaN(arg1->floatval) || 6897 xmlXPathIsNaN(arg2->floatval)) { 6898 ret = 0; 6899 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 6900 if (xmlXPathIsInf(arg2->floatval) == 1) 6901 ret = 1; 6902 else 6903 ret = 0; 6904 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 6905 if (xmlXPathIsInf(arg2->floatval) == -1) 6906 ret = 1; 6907 else 6908 ret = 0; 6909 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 6910 if (xmlXPathIsInf(arg1->floatval) == 1) 6911 ret = 1; 6912 else 6913 ret = 0; 6914 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 6915 if (xmlXPathIsInf(arg1->floatval) == -1) 6916 ret = 1; 6917 else 6918 ret = 0; 6919 } else { 6920 ret = (arg1->floatval == arg2->floatval); 6921 } 6922 break; 6923 case XPATH_USERS: 6924 case XPATH_POINT: 6925 case XPATH_RANGE: 6926 case XPATH_LOCATIONSET: 6927 TODO 6928 break; 6929 case XPATH_NODESET: 6930 case XPATH_XSLT_TREE: 6931 break; 6932 } 6933 break; 6934 case XPATH_STRING: 6935 switch (arg2->type) { 6936 case XPATH_UNDEFINED: 6937#ifdef DEBUG_EXPR 6938 xmlGenericError(xmlGenericErrorContext, 6939 "Equal: undefined\n"); 6940#endif 6941 break; 6942 case XPATH_BOOLEAN: 6943 if ((arg1->stringval == NULL) || 6944 (arg1->stringval[0] == 0)) ret = 0; 6945 else 6946 ret = 1; 6947 ret = (arg2->boolval == ret); 6948 break; 6949 case XPATH_STRING: 6950 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 6951 break; 6952 case XPATH_NUMBER: 6953 valuePush(ctxt, arg1); 6954 xmlXPathNumberFunction(ctxt, 1); 6955 arg1 = valuePop(ctxt); 6956 /* Hand check NaN and Infinity equalities */ 6957 if (xmlXPathIsNaN(arg1->floatval) || 6958 xmlXPathIsNaN(arg2->floatval)) { 6959 ret = 0; 6960 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 6961 if (xmlXPathIsInf(arg2->floatval) == 1) 6962 ret = 1; 6963 else 6964 ret = 0; 6965 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 6966 if (xmlXPathIsInf(arg2->floatval) == -1) 6967 ret = 1; 6968 else 6969 ret = 0; 6970 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 6971 if (xmlXPathIsInf(arg1->floatval) == 1) 6972 ret = 1; 6973 else 6974 ret = 0; 6975 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 6976 if (xmlXPathIsInf(arg1->floatval) == -1) 6977 ret = 1; 6978 else 6979 ret = 0; 6980 } else { 6981 ret = (arg1->floatval == arg2->floatval); 6982 } 6983 break; 6984 case XPATH_USERS: 6985 case XPATH_POINT: 6986 case XPATH_RANGE: 6987 case XPATH_LOCATIONSET: 6988 TODO 6989 break; 6990 case XPATH_NODESET: 6991 case XPATH_XSLT_TREE: 6992 break; 6993 } 6994 break; 6995 case XPATH_USERS: 6996 case XPATH_POINT: 6997 case XPATH_RANGE: 6998 case XPATH_LOCATIONSET: 6999 TODO 7000 break; 7001 case XPATH_NODESET: 7002 case XPATH_XSLT_TREE: 7003 break; 7004 } 7005 xmlXPathReleaseObject(ctxt->context, arg1); 7006 xmlXPathReleaseObject(ctxt->context, arg2); 7007 return(ret); 7008} 7009 7010/** 7011 * xmlXPathEqualValues: 7012 * @ctxt: the XPath Parser context 7013 * 7014 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7015 * 7016 * Returns 0 or 1 depending on the results of the test. 7017 */ 7018int 7019xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 7020 xmlXPathObjectPtr arg1, arg2, argtmp; 7021 int ret = 0; 7022 7023 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7024 arg2 = valuePop(ctxt); 7025 arg1 = valuePop(ctxt); 7026 if ((arg1 == NULL) || (arg2 == NULL)) { 7027 if (arg1 != NULL) 7028 xmlXPathReleaseObject(ctxt->context, arg1); 7029 else 7030 xmlXPathReleaseObject(ctxt->context, arg2); 7031 XP_ERROR0(XPATH_INVALID_OPERAND); 7032 } 7033 7034 if (arg1 == arg2) { 7035#ifdef DEBUG_EXPR 7036 xmlGenericError(xmlGenericErrorContext, 7037 "Equal: by pointer\n"); 7038#endif 7039 xmlXPathFreeObject(arg1); 7040 return(1); 7041 } 7042 7043 /* 7044 *If either argument is a nodeset, it's a 'special case' 7045 */ 7046 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7047 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7048 /* 7049 *Hack it to assure arg1 is the nodeset 7050 */ 7051 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7052 argtmp = arg2; 7053 arg2 = arg1; 7054 arg1 = argtmp; 7055 } 7056 switch (arg2->type) { 7057 case XPATH_UNDEFINED: 7058#ifdef DEBUG_EXPR 7059 xmlGenericError(xmlGenericErrorContext, 7060 "Equal: undefined\n"); 7061#endif 7062 break; 7063 case XPATH_NODESET: 7064 case XPATH_XSLT_TREE: 7065 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 7066 break; 7067 case XPATH_BOOLEAN: 7068 if ((arg1->nodesetval == NULL) || 7069 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7070 else 7071 ret = 1; 7072 ret = (ret == arg2->boolval); 7073 break; 7074 case XPATH_NUMBER: 7075 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 7076 break; 7077 case XPATH_STRING: 7078 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 7079 break; 7080 case XPATH_USERS: 7081 case XPATH_POINT: 7082 case XPATH_RANGE: 7083 case XPATH_LOCATIONSET: 7084 TODO 7085 break; 7086 } 7087 xmlXPathReleaseObject(ctxt->context, arg1); 7088 xmlXPathReleaseObject(ctxt->context, arg2); 7089 return(ret); 7090 } 7091 7092 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7093} 7094 7095/** 7096 * xmlXPathNotEqualValues: 7097 * @ctxt: the XPath Parser context 7098 * 7099 * Implement the equal operation on XPath objects content: @arg1 == @arg2 7100 * 7101 * Returns 0 or 1 depending on the results of the test. 7102 */ 7103int 7104xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 7105 xmlXPathObjectPtr arg1, arg2, argtmp; 7106 int ret = 0; 7107 7108 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7109 arg2 = valuePop(ctxt); 7110 arg1 = valuePop(ctxt); 7111 if ((arg1 == NULL) || (arg2 == NULL)) { 7112 if (arg1 != NULL) 7113 xmlXPathReleaseObject(ctxt->context, arg1); 7114 else 7115 xmlXPathReleaseObject(ctxt->context, arg2); 7116 XP_ERROR0(XPATH_INVALID_OPERAND); 7117 } 7118 7119 if (arg1 == arg2) { 7120#ifdef DEBUG_EXPR 7121 xmlGenericError(xmlGenericErrorContext, 7122 "NotEqual: by pointer\n"); 7123#endif 7124 xmlXPathReleaseObject(ctxt->context, arg1); 7125 return(0); 7126 } 7127 7128 /* 7129 *If either argument is a nodeset, it's a 'special case' 7130 */ 7131 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7132 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7133 /* 7134 *Hack it to assure arg1 is the nodeset 7135 */ 7136 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 7137 argtmp = arg2; 7138 arg2 = arg1; 7139 arg1 = argtmp; 7140 } 7141 switch (arg2->type) { 7142 case XPATH_UNDEFINED: 7143#ifdef DEBUG_EXPR 7144 xmlGenericError(xmlGenericErrorContext, 7145 "NotEqual: undefined\n"); 7146#endif 7147 break; 7148 case XPATH_NODESET: 7149 case XPATH_XSLT_TREE: 7150 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 7151 break; 7152 case XPATH_BOOLEAN: 7153 if ((arg1->nodesetval == NULL) || 7154 (arg1->nodesetval->nodeNr == 0)) ret = 0; 7155 else 7156 ret = 1; 7157 ret = (ret != arg2->boolval); 7158 break; 7159 case XPATH_NUMBER: 7160 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 7161 break; 7162 case XPATH_STRING: 7163 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 7164 break; 7165 case XPATH_USERS: 7166 case XPATH_POINT: 7167 case XPATH_RANGE: 7168 case XPATH_LOCATIONSET: 7169 TODO 7170 break; 7171 } 7172 xmlXPathReleaseObject(ctxt->context, arg1); 7173 xmlXPathReleaseObject(ctxt->context, arg2); 7174 return(ret); 7175 } 7176 7177 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 7178} 7179 7180/** 7181 * xmlXPathCompareValues: 7182 * @ctxt: the XPath Parser context 7183 * @inf: less than (1) or greater than (0) 7184 * @strict: is the comparison strict 7185 * 7186 * Implement the compare operation on XPath objects: 7187 * @arg1 < @arg2 (1, 1, ... 7188 * @arg1 <= @arg2 (1, 0, ... 7189 * @arg1 > @arg2 (0, 1, ... 7190 * @arg1 >= @arg2 (0, 0, ... 7191 * 7192 * When neither object to be compared is a node-set and the operator is 7193 * <=, <, >=, >, then the objects are compared by converted both objects 7194 * to numbers and comparing the numbers according to IEEE 754. The < 7195 * comparison will be true if and only if the first number is less than the 7196 * second number. The <= comparison will be true if and only if the first 7197 * number is less than or equal to the second number. The > comparison 7198 * will be true if and only if the first number is greater than the second 7199 * number. The >= comparison will be true if and only if the first number 7200 * is greater than or equal to the second number. 7201 * 7202 * Returns 1 if the comparison succeeded, 0 if it failed 7203 */ 7204int 7205xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 7206 int ret = 0, arg1i = 0, arg2i = 0; 7207 xmlXPathObjectPtr arg1, arg2; 7208 7209 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 7210 arg2 = valuePop(ctxt); 7211 arg1 = valuePop(ctxt); 7212 if ((arg1 == NULL) || (arg2 == NULL)) { 7213 if (arg1 != NULL) 7214 xmlXPathReleaseObject(ctxt->context, arg1); 7215 else 7216 xmlXPathReleaseObject(ctxt->context, arg2); 7217 XP_ERROR0(XPATH_INVALID_OPERAND); 7218 } 7219 7220 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 7221 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7222 /* 7223 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 7224 * are not freed from within this routine; they will be freed from the 7225 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 7226 */ 7227 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 7228 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 7229 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 7230 } else { 7231 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 7232 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 7233 arg1, arg2); 7234 } else { 7235 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 7236 arg2, arg1); 7237 } 7238 } 7239 return(ret); 7240 } 7241 7242 if (arg1->type != XPATH_NUMBER) { 7243 valuePush(ctxt, arg1); 7244 xmlXPathNumberFunction(ctxt, 1); 7245 arg1 = valuePop(ctxt); 7246 } 7247 if (arg1->type != XPATH_NUMBER) { 7248 xmlXPathFreeObject(arg1); 7249 xmlXPathFreeObject(arg2); 7250 XP_ERROR0(XPATH_INVALID_OPERAND); 7251 } 7252 if (arg2->type != XPATH_NUMBER) { 7253 valuePush(ctxt, arg2); 7254 xmlXPathNumberFunction(ctxt, 1); 7255 arg2 = valuePop(ctxt); 7256 } 7257 if (arg2->type != XPATH_NUMBER) { 7258 xmlXPathReleaseObject(ctxt->context, arg1); 7259 xmlXPathReleaseObject(ctxt->context, arg2); 7260 XP_ERROR0(XPATH_INVALID_OPERAND); 7261 } 7262 /* 7263 * Add tests for infinity and nan 7264 * => feedback on 3.4 for Inf and NaN 7265 */ 7266 /* Hand check NaN and Infinity comparisons */ 7267 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 7268 ret=0; 7269 } else { 7270 arg1i=xmlXPathIsInf(arg1->floatval); 7271 arg2i=xmlXPathIsInf(arg2->floatval); 7272 if (inf && strict) { 7273 if ((arg1i == -1 && arg2i != -1) || 7274 (arg2i == 1 && arg1i != 1)) { 7275 ret = 1; 7276 } else if (arg1i == 0 && arg2i == 0) { 7277 ret = (arg1->floatval < arg2->floatval); 7278 } else { 7279 ret = 0; 7280 } 7281 } 7282 else if (inf && !strict) { 7283 if (arg1i == -1 || arg2i == 1) { 7284 ret = 1; 7285 } else if (arg1i == 0 && arg2i == 0) { 7286 ret = (arg1->floatval <= arg2->floatval); 7287 } else { 7288 ret = 0; 7289 } 7290 } 7291 else if (!inf && strict) { 7292 if ((arg1i == 1 && arg2i != 1) || 7293 (arg2i == -1 && arg1i != -1)) { 7294 ret = 1; 7295 } else if (arg1i == 0 && arg2i == 0) { 7296 ret = (arg1->floatval > arg2->floatval); 7297 } else { 7298 ret = 0; 7299 } 7300 } 7301 else if (!inf && !strict) { 7302 if (arg1i == 1 || arg2i == -1) { 7303 ret = 1; 7304 } else if (arg1i == 0 && arg2i == 0) { 7305 ret = (arg1->floatval >= arg2->floatval); 7306 } else { 7307 ret = 0; 7308 } 7309 } 7310 } 7311 xmlXPathReleaseObject(ctxt->context, arg1); 7312 xmlXPathReleaseObject(ctxt->context, arg2); 7313 return(ret); 7314} 7315 7316/** 7317 * xmlXPathValueFlipSign: 7318 * @ctxt: the XPath Parser context 7319 * 7320 * Implement the unary - operation on an XPath object 7321 * The numeric operators convert their operands to numbers as if 7322 * by calling the number function. 7323 */ 7324void 7325xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7326 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7327 CAST_TO_NUMBER; 7328 CHECK_TYPE(XPATH_NUMBER); 7329 if (xmlXPathIsNaN(ctxt->value->floatval)) 7330 ctxt->value->floatval=xmlXPathNAN; 7331 else if (xmlXPathIsInf(ctxt->value->floatval) == 1) 7332 ctxt->value->floatval=xmlXPathNINF; 7333 else if (xmlXPathIsInf(ctxt->value->floatval) == -1) 7334 ctxt->value->floatval=xmlXPathPINF; 7335 else if (ctxt->value->floatval == 0) { 7336 if (xmlXPathGetSign(ctxt->value->floatval) == 0) 7337 ctxt->value->floatval = xmlXPathNZERO; 7338 else 7339 ctxt->value->floatval = 0; 7340 } 7341 else 7342 ctxt->value->floatval = - ctxt->value->floatval; 7343} 7344 7345/** 7346 * xmlXPathAddValues: 7347 * @ctxt: the XPath Parser context 7348 * 7349 * Implement the add operation on XPath objects: 7350 * The numeric operators convert their operands to numbers as if 7351 * by calling the number function. 7352 */ 7353void 7354xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7355 xmlXPathObjectPtr arg; 7356 double val; 7357 7358 arg = valuePop(ctxt); 7359 if (arg == NULL) 7360 XP_ERROR(XPATH_INVALID_OPERAND); 7361 val = xmlXPathCastToNumber(arg); 7362 xmlXPathReleaseObject(ctxt->context, arg); 7363 CAST_TO_NUMBER; 7364 CHECK_TYPE(XPATH_NUMBER); 7365 ctxt->value->floatval += val; 7366} 7367 7368/** 7369 * xmlXPathSubValues: 7370 * @ctxt: the XPath Parser context 7371 * 7372 * Implement the subtraction operation on XPath objects: 7373 * The numeric operators convert their operands to numbers as if 7374 * by calling the number function. 7375 */ 7376void 7377xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7378 xmlXPathObjectPtr arg; 7379 double val; 7380 7381 arg = valuePop(ctxt); 7382 if (arg == NULL) 7383 XP_ERROR(XPATH_INVALID_OPERAND); 7384 val = xmlXPathCastToNumber(arg); 7385 xmlXPathReleaseObject(ctxt->context, arg); 7386 CAST_TO_NUMBER; 7387 CHECK_TYPE(XPATH_NUMBER); 7388 ctxt->value->floatval -= val; 7389} 7390 7391/** 7392 * xmlXPathMultValues: 7393 * @ctxt: the XPath Parser context 7394 * 7395 * Implement the multiply operation on XPath objects: 7396 * The numeric operators convert their operands to numbers as if 7397 * by calling the number function. 7398 */ 7399void 7400xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7401 xmlXPathObjectPtr arg; 7402 double val; 7403 7404 arg = valuePop(ctxt); 7405 if (arg == NULL) 7406 XP_ERROR(XPATH_INVALID_OPERAND); 7407 val = xmlXPathCastToNumber(arg); 7408 xmlXPathReleaseObject(ctxt->context, arg); 7409 CAST_TO_NUMBER; 7410 CHECK_TYPE(XPATH_NUMBER); 7411 ctxt->value->floatval *= val; 7412} 7413 7414/** 7415 * xmlXPathDivValues: 7416 * @ctxt: the XPath Parser context 7417 * 7418 * Implement the div operation on XPath objects @arg1 / @arg2: 7419 * The numeric operators convert their operands to numbers as if 7420 * by calling the number function. 7421 */ 7422void 7423xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7424 xmlXPathObjectPtr arg; 7425 double val; 7426 7427 arg = valuePop(ctxt); 7428 if (arg == NULL) 7429 XP_ERROR(XPATH_INVALID_OPERAND); 7430 val = xmlXPathCastToNumber(arg); 7431 xmlXPathReleaseObject(ctxt->context, arg); 7432 CAST_TO_NUMBER; 7433 CHECK_TYPE(XPATH_NUMBER); 7434 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) 7435 ctxt->value->floatval = xmlXPathNAN; 7436 else if (val == 0 && xmlXPathGetSign(val) != 0) { 7437 if (ctxt->value->floatval == 0) 7438 ctxt->value->floatval = xmlXPathNAN; 7439 else if (ctxt->value->floatval > 0) 7440 ctxt->value->floatval = xmlXPathNINF; 7441 else if (ctxt->value->floatval < 0) 7442 ctxt->value->floatval = xmlXPathPINF; 7443 } 7444 else if (val == 0) { 7445 if (ctxt->value->floatval == 0) 7446 ctxt->value->floatval = xmlXPathNAN; 7447 else if (ctxt->value->floatval > 0) 7448 ctxt->value->floatval = xmlXPathPINF; 7449 else if (ctxt->value->floatval < 0) 7450 ctxt->value->floatval = xmlXPathNINF; 7451 } else 7452 ctxt->value->floatval /= val; 7453} 7454 7455/** 7456 * xmlXPathModValues: 7457 * @ctxt: the XPath Parser context 7458 * 7459 * Implement the mod operation on XPath objects: @arg1 / @arg2 7460 * The numeric operators convert their operands to numbers as if 7461 * by calling the number function. 7462 */ 7463void 7464xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7465 xmlXPathObjectPtr arg; 7466 double arg1, arg2; 7467 7468 arg = valuePop(ctxt); 7469 if (arg == NULL) 7470 XP_ERROR(XPATH_INVALID_OPERAND); 7471 arg2 = xmlXPathCastToNumber(arg); 7472 xmlXPathReleaseObject(ctxt->context, arg); 7473 CAST_TO_NUMBER; 7474 CHECK_TYPE(XPATH_NUMBER); 7475 arg1 = ctxt->value->floatval; 7476 if (arg2 == 0) 7477 ctxt->value->floatval = xmlXPathNAN; 7478 else { 7479 ctxt->value->floatval = fmod(arg1, arg2); 7480 } 7481} 7482 7483/************************************************************************ 7484 * * 7485 * The traversal functions * 7486 * * 7487 ************************************************************************/ 7488 7489/* 7490 * A traversal function enumerates nodes along an axis. 7491 * Initially it must be called with NULL, and it indicates 7492 * termination on the axis by returning NULL. 7493 */ 7494typedef xmlNodePtr (*xmlXPathTraversalFunction) 7495 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7496 7497/* 7498 * xmlXPathTraversalFunctionExt: 7499 * A traversal function enumerates nodes along an axis. 7500 * Initially it must be called with NULL, and it indicates 7501 * termination on the axis by returning NULL. 7502 * The context node of the traversal is specified via @contextNode. 7503 */ 7504typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7505 (xmlNodePtr cur, xmlNodePtr contextNode); 7506 7507/* 7508 * xmlXPathNodeSetMergeFunction: 7509 * Used for merging node sets in xmlXPathCollectAndTest(). 7510 */ 7511typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) 7512 (xmlNodeSetPtr, xmlNodeSetPtr, int); 7513 7514 7515/** 7516 * xmlXPathNextSelf: 7517 * @ctxt: the XPath Parser context 7518 * @cur: the current node in the traversal 7519 * 7520 * Traversal function for the "self" direction 7521 * The self axis contains just the context node itself 7522 * 7523 * Returns the next element following that axis 7524 */ 7525xmlNodePtr 7526xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7527 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7528 if (cur == NULL) 7529 return(ctxt->context->node); 7530 return(NULL); 7531} 7532 7533/** 7534 * xmlXPathNextChild: 7535 * @ctxt: the XPath Parser context 7536 * @cur: the current node in the traversal 7537 * 7538 * Traversal function for the "child" direction 7539 * The child axis contains the children of the context node in document order. 7540 * 7541 * Returns the next element following that axis 7542 */ 7543xmlNodePtr 7544xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7545 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7546 if (cur == NULL) { 7547 if (ctxt->context->node == NULL) return(NULL); 7548 switch (ctxt->context->node->type) { 7549 case XML_ELEMENT_NODE: 7550 case XML_TEXT_NODE: 7551 case XML_CDATA_SECTION_NODE: 7552 case XML_ENTITY_REF_NODE: 7553 case XML_ENTITY_NODE: 7554 case XML_PI_NODE: 7555 case XML_COMMENT_NODE: 7556 case XML_NOTATION_NODE: 7557 case XML_DTD_NODE: 7558 return(ctxt->context->node->children); 7559 case XML_DOCUMENT_NODE: 7560 case XML_DOCUMENT_TYPE_NODE: 7561 case XML_DOCUMENT_FRAG_NODE: 7562 case XML_HTML_DOCUMENT_NODE: 7563#ifdef LIBXML_DOCB_ENABLED 7564 case XML_DOCB_DOCUMENT_NODE: 7565#endif 7566 return(((xmlDocPtr) ctxt->context->node)->children); 7567 case XML_ELEMENT_DECL: 7568 case XML_ATTRIBUTE_DECL: 7569 case XML_ENTITY_DECL: 7570 case XML_ATTRIBUTE_NODE: 7571 case XML_NAMESPACE_DECL: 7572 case XML_XINCLUDE_START: 7573 case XML_XINCLUDE_END: 7574 return(NULL); 7575 } 7576 return(NULL); 7577 } 7578 if ((cur->type == XML_DOCUMENT_NODE) || 7579 (cur->type == XML_HTML_DOCUMENT_NODE)) 7580 return(NULL); 7581 return(cur->next); 7582} 7583 7584/** 7585 * xmlXPathNextChildElement: 7586 * @ctxt: the XPath Parser context 7587 * @cur: the current node in the traversal 7588 * 7589 * Traversal function for the "child" direction and nodes of type element. 7590 * The child axis contains the children of the context node in document order. 7591 * 7592 * Returns the next element following that axis 7593 */ 7594static xmlNodePtr 7595xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7596 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7597 if (cur == NULL) { 7598 cur = ctxt->context->node; 7599 if (cur == NULL) return(NULL); 7600 /* 7601 * Get the first element child. 7602 */ 7603 switch (cur->type) { 7604 case XML_ELEMENT_NODE: 7605 case XML_DOCUMENT_FRAG_NODE: 7606 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7607 case XML_ENTITY_NODE: 7608 cur = cur->children; 7609 if (cur != NULL) { 7610 if (cur->type == XML_ELEMENT_NODE) 7611 return(cur); 7612 do { 7613 cur = cur->next; 7614 } while ((cur != NULL) && 7615 (cur->type != XML_ELEMENT_NODE)); 7616 return(cur); 7617 } 7618 return(NULL); 7619 case XML_DOCUMENT_NODE: 7620 case XML_HTML_DOCUMENT_NODE: 7621#ifdef LIBXML_DOCB_ENABLED 7622 case XML_DOCB_DOCUMENT_NODE: 7623#endif 7624 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7625 default: 7626 return(NULL); 7627 } 7628 return(NULL); 7629 } 7630 /* 7631 * Get the next sibling element node. 7632 */ 7633 switch (cur->type) { 7634 case XML_ELEMENT_NODE: 7635 case XML_TEXT_NODE: 7636 case XML_ENTITY_REF_NODE: 7637 case XML_ENTITY_NODE: 7638 case XML_CDATA_SECTION_NODE: 7639 case XML_PI_NODE: 7640 case XML_COMMENT_NODE: 7641 case XML_XINCLUDE_END: 7642 break; 7643 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7644 default: 7645 return(NULL); 7646 } 7647 if (cur->next != NULL) { 7648 if (cur->next->type == XML_ELEMENT_NODE) 7649 return(cur->next); 7650 cur = cur->next; 7651 do { 7652 cur = cur->next; 7653 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7654 return(cur); 7655 } 7656 return(NULL); 7657} 7658 7659/** 7660 * xmlXPathNextDescendantOrSelfElemParent: 7661 * @ctxt: the XPath Parser context 7662 * @cur: the current node in the traversal 7663 * 7664 * Traversal function for the "descendant-or-self" axis. 7665 * Additionally it returns only nodes which can be parents of 7666 * element nodes. 7667 * 7668 * 7669 * Returns the next element following that axis 7670 */ 7671static xmlNodePtr 7672xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7673 xmlNodePtr contextNode) 7674{ 7675 if (cur == NULL) { 7676 if (contextNode == NULL) 7677 return(NULL); 7678 switch (contextNode->type) { 7679 case XML_ELEMENT_NODE: 7680 case XML_XINCLUDE_START: 7681 case XML_DOCUMENT_FRAG_NODE: 7682 case XML_DOCUMENT_NODE: 7683#ifdef LIBXML_DOCB_ENABLED 7684 case XML_DOCB_DOCUMENT_NODE: 7685#endif 7686 case XML_HTML_DOCUMENT_NODE: 7687 return(contextNode); 7688 default: 7689 return(NULL); 7690 } 7691 return(NULL); 7692 } else { 7693 xmlNodePtr start = cur; 7694 7695 while (cur != NULL) { 7696 switch (cur->type) { 7697 case XML_ELEMENT_NODE: 7698 /* TODO: OK to have XInclude here? */ 7699 case XML_XINCLUDE_START: 7700 case XML_DOCUMENT_FRAG_NODE: 7701 if (cur != start) 7702 return(cur); 7703 if (cur->children != NULL) { 7704 cur = cur->children; 7705 continue; 7706 } 7707 break; 7708 /* Not sure if we need those here. */ 7709 case XML_DOCUMENT_NODE: 7710#ifdef LIBXML_DOCB_ENABLED 7711 case XML_DOCB_DOCUMENT_NODE: 7712#endif 7713 case XML_HTML_DOCUMENT_NODE: 7714 if (cur != start) 7715 return(cur); 7716 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7717 default: 7718 break; 7719 } 7720 7721next_sibling: 7722 if ((cur == NULL) || (cur == contextNode)) 7723 return(NULL); 7724 if (cur->next != NULL) { 7725 cur = cur->next; 7726 } else { 7727 cur = cur->parent; 7728 goto next_sibling; 7729 } 7730 } 7731 } 7732 return(NULL); 7733} 7734 7735/** 7736 * xmlXPathNextDescendant: 7737 * @ctxt: the XPath Parser context 7738 * @cur: the current node in the traversal 7739 * 7740 * Traversal function for the "descendant" direction 7741 * the descendant axis contains the descendants of the context node in document 7742 * order; a descendant is a child or a child of a child and so on. 7743 * 7744 * Returns the next element following that axis 7745 */ 7746xmlNodePtr 7747xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7748 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7749 if (cur == NULL) { 7750 if (ctxt->context->node == NULL) 7751 return(NULL); 7752 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7753 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7754 return(NULL); 7755 7756 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7757 return(ctxt->context->doc->children); 7758 return(ctxt->context->node->children); 7759 } 7760 7761 if (cur->children != NULL) { 7762 /* 7763 * Do not descend on entities declarations 7764 */ 7765 if (cur->children->type != XML_ENTITY_DECL) { 7766 cur = cur->children; 7767 /* 7768 * Skip DTDs 7769 */ 7770 if (cur->type != XML_DTD_NODE) 7771 return(cur); 7772 } 7773 } 7774 7775 if (cur == ctxt->context->node) return(NULL); 7776 7777 while (cur->next != NULL) { 7778 cur = cur->next; 7779 if ((cur->type != XML_ENTITY_DECL) && 7780 (cur->type != XML_DTD_NODE)) 7781 return(cur); 7782 } 7783 7784 do { 7785 cur = cur->parent; 7786 if (cur == NULL) break; 7787 if (cur == ctxt->context->node) return(NULL); 7788 if (cur->next != NULL) { 7789 cur = cur->next; 7790 return(cur); 7791 } 7792 } while (cur != NULL); 7793 return(cur); 7794} 7795 7796/** 7797 * xmlXPathNextDescendantOrSelf: 7798 * @ctxt: the XPath Parser context 7799 * @cur: the current node in the traversal 7800 * 7801 * Traversal function for the "descendant-or-self" direction 7802 * the descendant-or-self axis contains the context node and the descendants 7803 * of the context node in document order; thus the context node is the first 7804 * node on the axis, and the first child of the context node is the second node 7805 * on the axis 7806 * 7807 * Returns the next element following that axis 7808 */ 7809xmlNodePtr 7810xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7811 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7812 if (cur == NULL) { 7813 if (ctxt->context->node == NULL) 7814 return(NULL); 7815 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7816 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7817 return(NULL); 7818 return(ctxt->context->node); 7819 } 7820 7821 return(xmlXPathNextDescendant(ctxt, cur)); 7822} 7823 7824/** 7825 * xmlXPathNextParent: 7826 * @ctxt: the XPath Parser context 7827 * @cur: the current node in the traversal 7828 * 7829 * Traversal function for the "parent" direction 7830 * The parent axis contains the parent of the context node, if there is one. 7831 * 7832 * Returns the next element following that axis 7833 */ 7834xmlNodePtr 7835xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7836 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7837 /* 7838 * the parent of an attribute or namespace node is the element 7839 * to which the attribute or namespace node is attached 7840 * Namespace handling !!! 7841 */ 7842 if (cur == NULL) { 7843 if (ctxt->context->node == NULL) return(NULL); 7844 switch (ctxt->context->node->type) { 7845 case XML_ELEMENT_NODE: 7846 case XML_TEXT_NODE: 7847 case XML_CDATA_SECTION_NODE: 7848 case XML_ENTITY_REF_NODE: 7849 case XML_ENTITY_NODE: 7850 case XML_PI_NODE: 7851 case XML_COMMENT_NODE: 7852 case XML_NOTATION_NODE: 7853 case XML_DTD_NODE: 7854 case XML_ELEMENT_DECL: 7855 case XML_ATTRIBUTE_DECL: 7856 case XML_XINCLUDE_START: 7857 case XML_XINCLUDE_END: 7858 case XML_ENTITY_DECL: 7859 if (ctxt->context->node->parent == NULL) 7860 return((xmlNodePtr) ctxt->context->doc); 7861 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7862 ((ctxt->context->node->parent->name[0] == ' ') || 7863 (xmlStrEqual(ctxt->context->node->parent->name, 7864 BAD_CAST "fake node libxslt")))) 7865 return(NULL); 7866 return(ctxt->context->node->parent); 7867 case XML_ATTRIBUTE_NODE: { 7868 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7869 7870 return(att->parent); 7871 } 7872 case XML_DOCUMENT_NODE: 7873 case XML_DOCUMENT_TYPE_NODE: 7874 case XML_DOCUMENT_FRAG_NODE: 7875 case XML_HTML_DOCUMENT_NODE: 7876#ifdef LIBXML_DOCB_ENABLED 7877 case XML_DOCB_DOCUMENT_NODE: 7878#endif 7879 return(NULL); 7880 case XML_NAMESPACE_DECL: { 7881 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7882 7883 if ((ns->next != NULL) && 7884 (ns->next->type != XML_NAMESPACE_DECL)) 7885 return((xmlNodePtr) ns->next); 7886 return(NULL); 7887 } 7888 } 7889 } 7890 return(NULL); 7891} 7892 7893/** 7894 * xmlXPathNextAncestor: 7895 * @ctxt: the XPath Parser context 7896 * @cur: the current node in the traversal 7897 * 7898 * Traversal function for the "ancestor" direction 7899 * the ancestor axis contains the ancestors of the context node; the ancestors 7900 * of the context node consist of the parent of context node and the parent's 7901 * parent and so on; the nodes are ordered in reverse document order; thus the 7902 * parent is the first node on the axis, and the parent's parent is the second 7903 * node on the axis 7904 * 7905 * Returns the next element following that axis 7906 */ 7907xmlNodePtr 7908xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7909 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7910 /* 7911 * the parent of an attribute or namespace node is the element 7912 * to which the attribute or namespace node is attached 7913 * !!!!!!!!!!!!! 7914 */ 7915 if (cur == NULL) { 7916 if (ctxt->context->node == NULL) return(NULL); 7917 switch (ctxt->context->node->type) { 7918 case XML_ELEMENT_NODE: 7919 case XML_TEXT_NODE: 7920 case XML_CDATA_SECTION_NODE: 7921 case XML_ENTITY_REF_NODE: 7922 case XML_ENTITY_NODE: 7923 case XML_PI_NODE: 7924 case XML_COMMENT_NODE: 7925 case XML_DTD_NODE: 7926 case XML_ELEMENT_DECL: 7927 case XML_ATTRIBUTE_DECL: 7928 case XML_ENTITY_DECL: 7929 case XML_NOTATION_NODE: 7930 case XML_XINCLUDE_START: 7931 case XML_XINCLUDE_END: 7932 if (ctxt->context->node->parent == NULL) 7933 return((xmlNodePtr) ctxt->context->doc); 7934 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7935 ((ctxt->context->node->parent->name[0] == ' ') || 7936 (xmlStrEqual(ctxt->context->node->parent->name, 7937 BAD_CAST "fake node libxslt")))) 7938 return(NULL); 7939 return(ctxt->context->node->parent); 7940 case XML_ATTRIBUTE_NODE: { 7941 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 7942 7943 return(tmp->parent); 7944 } 7945 case XML_DOCUMENT_NODE: 7946 case XML_DOCUMENT_TYPE_NODE: 7947 case XML_DOCUMENT_FRAG_NODE: 7948 case XML_HTML_DOCUMENT_NODE: 7949#ifdef LIBXML_DOCB_ENABLED 7950 case XML_DOCB_DOCUMENT_NODE: 7951#endif 7952 return(NULL); 7953 case XML_NAMESPACE_DECL: { 7954 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7955 7956 if ((ns->next != NULL) && 7957 (ns->next->type != XML_NAMESPACE_DECL)) 7958 return((xmlNodePtr) ns->next); 7959 /* Bad, how did that namespace end up here ? */ 7960 return(NULL); 7961 } 7962 } 7963 return(NULL); 7964 } 7965 if (cur == ctxt->context->doc->children) 7966 return((xmlNodePtr) ctxt->context->doc); 7967 if (cur == (xmlNodePtr) ctxt->context->doc) 7968 return(NULL); 7969 switch (cur->type) { 7970 case XML_ELEMENT_NODE: 7971 case XML_TEXT_NODE: 7972 case XML_CDATA_SECTION_NODE: 7973 case XML_ENTITY_REF_NODE: 7974 case XML_ENTITY_NODE: 7975 case XML_PI_NODE: 7976 case XML_COMMENT_NODE: 7977 case XML_NOTATION_NODE: 7978 case XML_DTD_NODE: 7979 case XML_ELEMENT_DECL: 7980 case XML_ATTRIBUTE_DECL: 7981 case XML_ENTITY_DECL: 7982 case XML_XINCLUDE_START: 7983 case XML_XINCLUDE_END: 7984 if (cur->parent == NULL) 7985 return(NULL); 7986 if ((cur->parent->type == XML_ELEMENT_NODE) && 7987 ((cur->parent->name[0] == ' ') || 7988 (xmlStrEqual(cur->parent->name, 7989 BAD_CAST "fake node libxslt")))) 7990 return(NULL); 7991 return(cur->parent); 7992 case XML_ATTRIBUTE_NODE: { 7993 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7994 7995 return(att->parent); 7996 } 7997 case XML_NAMESPACE_DECL: { 7998 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7999 8000 if ((ns->next != NULL) && 8001 (ns->next->type != XML_NAMESPACE_DECL)) 8002 return((xmlNodePtr) ns->next); 8003 /* Bad, how did that namespace end up here ? */ 8004 return(NULL); 8005 } 8006 case XML_DOCUMENT_NODE: 8007 case XML_DOCUMENT_TYPE_NODE: 8008 case XML_DOCUMENT_FRAG_NODE: 8009 case XML_HTML_DOCUMENT_NODE: 8010#ifdef LIBXML_DOCB_ENABLED 8011 case XML_DOCB_DOCUMENT_NODE: 8012#endif 8013 return(NULL); 8014 } 8015 return(NULL); 8016} 8017 8018/** 8019 * xmlXPathNextAncestorOrSelf: 8020 * @ctxt: the XPath Parser context 8021 * @cur: the current node in the traversal 8022 * 8023 * Traversal function for the "ancestor-or-self" direction 8024 * he ancestor-or-self axis contains the context node and ancestors of 8025 * the context node in reverse document order; thus the context node is 8026 * the first node on the axis, and the context node's parent the second; 8027 * parent here is defined the same as with the parent axis. 8028 * 8029 * Returns the next element following that axis 8030 */ 8031xmlNodePtr 8032xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8033 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8034 if (cur == NULL) 8035 return(ctxt->context->node); 8036 return(xmlXPathNextAncestor(ctxt, cur)); 8037} 8038 8039/** 8040 * xmlXPathNextFollowingSibling: 8041 * @ctxt: the XPath Parser context 8042 * @cur: the current node in the traversal 8043 * 8044 * Traversal function for the "following-sibling" direction 8045 * The following-sibling axis contains the following siblings of the context 8046 * node in document order. 8047 * 8048 * Returns the next element following that axis 8049 */ 8050xmlNodePtr 8051xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8052 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8053 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8054 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8055 return(NULL); 8056 if (cur == (xmlNodePtr) ctxt->context->doc) 8057 return(NULL); 8058 if (cur == NULL) 8059 return(ctxt->context->node->next); 8060 return(cur->next); 8061} 8062 8063/** 8064 * xmlXPathNextPrecedingSibling: 8065 * @ctxt: the XPath Parser context 8066 * @cur: the current node in the traversal 8067 * 8068 * Traversal function for the "preceding-sibling" direction 8069 * The preceding-sibling axis contains the preceding siblings of the context 8070 * node in reverse document order; the first preceding sibling is first on the 8071 * axis; the sibling preceding that node is the second on the axis and so on. 8072 * 8073 * Returns the next element following that axis 8074 */ 8075xmlNodePtr 8076xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8077 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8078 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 8079 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 8080 return(NULL); 8081 if (cur == (xmlNodePtr) ctxt->context->doc) 8082 return(NULL); 8083 if (cur == NULL) 8084 return(ctxt->context->node->prev); 8085 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 8086 cur = cur->prev; 8087 if (cur == NULL) 8088 return(ctxt->context->node->prev); 8089 } 8090 return(cur->prev); 8091} 8092 8093/** 8094 * xmlXPathNextFollowing: 8095 * @ctxt: the XPath Parser context 8096 * @cur: the current node in the traversal 8097 * 8098 * Traversal function for the "following" direction 8099 * The following axis contains all nodes in the same document as the context 8100 * node that are after the context node in document order, excluding any 8101 * descendants and excluding attribute nodes and namespace nodes; the nodes 8102 * are ordered in document order 8103 * 8104 * Returns the next element following that axis 8105 */ 8106xmlNodePtr 8107xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8108 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8109 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && 8110 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) 8111 return(cur->children); 8112 8113 if (cur == NULL) { 8114 cur = ctxt->context->node; 8115 if (cur->type == XML_NAMESPACE_DECL) 8116 return(NULL); 8117 if (cur->type == XML_ATTRIBUTE_NODE) 8118 cur = cur->parent; 8119 } 8120 if (cur == NULL) return(NULL) ; /* ERROR */ 8121 if (cur->next != NULL) return(cur->next) ; 8122 do { 8123 cur = cur->parent; 8124 if (cur == NULL) break; 8125 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 8126 if (cur->next != NULL) return(cur->next); 8127 } while (cur != NULL); 8128 return(cur); 8129} 8130 8131/* 8132 * xmlXPathIsAncestor: 8133 * @ancestor: the ancestor node 8134 * @node: the current node 8135 * 8136 * Check that @ancestor is a @node's ancestor 8137 * 8138 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 8139 */ 8140static int 8141xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 8142 if ((ancestor == NULL) || (node == NULL)) return(0); 8143 /* nodes need to be in the same document */ 8144 if (ancestor->doc != node->doc) return(0); 8145 /* avoid searching if ancestor or node is the root node */ 8146 if (ancestor == (xmlNodePtr) node->doc) return(1); 8147 if (node == (xmlNodePtr) ancestor->doc) return(0); 8148 while (node->parent != NULL) { 8149 if (node->parent == ancestor) 8150 return(1); 8151 node = node->parent; 8152 } 8153 return(0); 8154} 8155 8156/** 8157 * xmlXPathNextPreceding: 8158 * @ctxt: the XPath Parser context 8159 * @cur: the current node in the traversal 8160 * 8161 * Traversal function for the "preceding" direction 8162 * the preceding axis contains all nodes in the same document as the context 8163 * node that are before the context node in document order, excluding any 8164 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8165 * ordered in reverse document order 8166 * 8167 * Returns the next element following that axis 8168 */ 8169xmlNodePtr 8170xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 8171{ 8172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8173 if (cur == NULL) { 8174 cur = ctxt->context->node; 8175 if (cur->type == XML_NAMESPACE_DECL) 8176 return(NULL); 8177 if (cur->type == XML_ATTRIBUTE_NODE) 8178 return(cur->parent); 8179 } 8180 if (cur == NULL) 8181 return (NULL); 8182 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8183 cur = cur->prev; 8184 do { 8185 if (cur->prev != NULL) { 8186 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 8187 return (cur); 8188 } 8189 8190 cur = cur->parent; 8191 if (cur == NULL) 8192 return (NULL); 8193 if (cur == ctxt->context->doc->children) 8194 return (NULL); 8195 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 8196 return (cur); 8197} 8198 8199/** 8200 * xmlXPathNextPrecedingInternal: 8201 * @ctxt: the XPath Parser context 8202 * @cur: the current node in the traversal 8203 * 8204 * Traversal function for the "preceding" direction 8205 * the preceding axis contains all nodes in the same document as the context 8206 * node that are before the context node in document order, excluding any 8207 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 8208 * ordered in reverse document order 8209 * This is a faster implementation but internal only since it requires a 8210 * state kept in the parser context: ctxt->ancestor. 8211 * 8212 * Returns the next element following that axis 8213 */ 8214static xmlNodePtr 8215xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 8216 xmlNodePtr cur) 8217{ 8218 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8219 if (cur == NULL) { 8220 cur = ctxt->context->node; 8221 if (cur == NULL) 8222 return (NULL); 8223 if (cur->type == XML_NAMESPACE_DECL) 8224 return (NULL); 8225 ctxt->ancestor = cur->parent; 8226 } 8227 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 8228 cur = cur->prev; 8229 while (cur->prev == NULL) { 8230 cur = cur->parent; 8231 if (cur == NULL) 8232 return (NULL); 8233 if (cur == ctxt->context->doc->children) 8234 return (NULL); 8235 if (cur != ctxt->ancestor) 8236 return (cur); 8237 ctxt->ancestor = cur->parent; 8238 } 8239 cur = cur->prev; 8240 while (cur->last != NULL) 8241 cur = cur->last; 8242 return (cur); 8243} 8244 8245/** 8246 * xmlXPathNextNamespace: 8247 * @ctxt: the XPath Parser context 8248 * @cur: the current attribute in the traversal 8249 * 8250 * Traversal function for the "namespace" direction 8251 * the namespace axis contains the namespace nodes of the context node; 8252 * the order of nodes on this axis is implementation-defined; the axis will 8253 * be empty unless the context node is an element 8254 * 8255 * We keep the XML namespace node at the end of the list. 8256 * 8257 * Returns the next element following that axis 8258 */ 8259xmlNodePtr 8260xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8261 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8262 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 8263 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) { 8264 if (ctxt->context->tmpNsList != NULL) 8265 xmlFree(ctxt->context->tmpNsList); 8266 ctxt->context->tmpNsList = 8267 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 8268 ctxt->context->tmpNsNr = 0; 8269 if (ctxt->context->tmpNsList != NULL) { 8270 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 8271 ctxt->context->tmpNsNr++; 8272 } 8273 } 8274 return((xmlNodePtr) xmlXPathXMLNamespace); 8275 } 8276 if (ctxt->context->tmpNsNr > 0) { 8277 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 8278 } else { 8279 if (ctxt->context->tmpNsList != NULL) 8280 xmlFree(ctxt->context->tmpNsList); 8281 ctxt->context->tmpNsList = NULL; 8282 return(NULL); 8283 } 8284} 8285 8286/** 8287 * xmlXPathNextAttribute: 8288 * @ctxt: the XPath Parser context 8289 * @cur: the current attribute in the traversal 8290 * 8291 * Traversal function for the "attribute" direction 8292 * TODO: support DTD inherited default attributes 8293 * 8294 * Returns the next element following that axis 8295 */ 8296xmlNodePtr 8297xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 8298 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 8299 if (ctxt->context->node == NULL) 8300 return(NULL); 8301 if (ctxt->context->node->type != XML_ELEMENT_NODE) 8302 return(NULL); 8303 if (cur == NULL) { 8304 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8305 return(NULL); 8306 return((xmlNodePtr)ctxt->context->node->properties); 8307 } 8308 return((xmlNodePtr)cur->next); 8309} 8310 8311/************************************************************************ 8312 * * 8313 * NodeTest Functions * 8314 * * 8315 ************************************************************************/ 8316 8317#define IS_FUNCTION 200 8318 8319 8320/************************************************************************ 8321 * * 8322 * Implicit tree core function library * 8323 * * 8324 ************************************************************************/ 8325 8326/** 8327 * xmlXPathRoot: 8328 * @ctxt: the XPath Parser context 8329 * 8330 * Initialize the context to the root of the document 8331 */ 8332void 8333xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8334 if ((ctxt == NULL) || (ctxt->context == NULL)) 8335 return; 8336 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 8337 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8338 ctxt->context->node)); 8339} 8340 8341/************************************************************************ 8342 * * 8343 * The explicit core function library * 8344 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8345 * * 8346 ************************************************************************/ 8347 8348 8349/** 8350 * xmlXPathLastFunction: 8351 * @ctxt: the XPath Parser context 8352 * @nargs: the number of arguments 8353 * 8354 * Implement the last() XPath function 8355 * number last() 8356 * The last function returns the number of nodes in the context node list. 8357 */ 8358void 8359xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8360 CHECK_ARITY(0); 8361 if (ctxt->context->contextSize >= 0) { 8362 valuePush(ctxt, 8363 xmlXPathCacheNewFloat(ctxt->context, 8364 (double) ctxt->context->contextSize)); 8365#ifdef DEBUG_EXPR 8366 xmlGenericError(xmlGenericErrorContext, 8367 "last() : %d\n", ctxt->context->contextSize); 8368#endif 8369 } else { 8370 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8371 } 8372} 8373 8374/** 8375 * xmlXPathPositionFunction: 8376 * @ctxt: the XPath Parser context 8377 * @nargs: the number of arguments 8378 * 8379 * Implement the position() XPath function 8380 * number position() 8381 * The position function returns the position of the context node in the 8382 * context node list. The first position is 1, and so the last position 8383 * will be equal to last(). 8384 */ 8385void 8386xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8387 CHECK_ARITY(0); 8388 if (ctxt->context->proximityPosition >= 0) { 8389 valuePush(ctxt, 8390 xmlXPathCacheNewFloat(ctxt->context, 8391 (double) ctxt->context->proximityPosition)); 8392#ifdef DEBUG_EXPR 8393 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8394 ctxt->context->proximityPosition); 8395#endif 8396 } else { 8397 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8398 } 8399} 8400 8401/** 8402 * xmlXPathCountFunction: 8403 * @ctxt: the XPath Parser context 8404 * @nargs: the number of arguments 8405 * 8406 * Implement the count() XPath function 8407 * number count(node-set) 8408 */ 8409void 8410xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8411 xmlXPathObjectPtr cur; 8412 8413 CHECK_ARITY(1); 8414 if ((ctxt->value == NULL) || 8415 ((ctxt->value->type != XPATH_NODESET) && 8416 (ctxt->value->type != XPATH_XSLT_TREE))) 8417 XP_ERROR(XPATH_INVALID_TYPE); 8418 cur = valuePop(ctxt); 8419 8420 if ((cur == NULL) || (cur->nodesetval == NULL)) 8421 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8422 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 8423 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8424 (double) cur->nodesetval->nodeNr)); 8425 } else { 8426 if ((cur->nodesetval->nodeNr != 1) || 8427 (cur->nodesetval->nodeTab == NULL)) { 8428 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8429 } else { 8430 xmlNodePtr tmp; 8431 int i = 0; 8432 8433 tmp = cur->nodesetval->nodeTab[0]; 8434 if (tmp != NULL) { 8435 tmp = tmp->children; 8436 while (tmp != NULL) { 8437 tmp = tmp->next; 8438 i++; 8439 } 8440 } 8441 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); 8442 } 8443 } 8444 xmlXPathReleaseObject(ctxt->context, cur); 8445} 8446 8447/** 8448 * xmlXPathGetElementsByIds: 8449 * @doc: the document 8450 * @ids: a whitespace separated list of IDs 8451 * 8452 * Selects elements by their unique ID. 8453 * 8454 * Returns a node-set of selected elements. 8455 */ 8456static xmlNodeSetPtr 8457xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8458 xmlNodeSetPtr ret; 8459 const xmlChar *cur = ids; 8460 xmlChar *ID; 8461 xmlAttrPtr attr; 8462 xmlNodePtr elem = NULL; 8463 8464 if (ids == NULL) return(NULL); 8465 8466 ret = xmlXPathNodeSetCreate(NULL); 8467 if (ret == NULL) 8468 return(ret); 8469 8470 while (IS_BLANK_CH(*cur)) cur++; 8471 while (*cur != 0) { 8472 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8473 cur++; 8474 8475 ID = xmlStrndup(ids, cur - ids); 8476 if (ID != NULL) { 8477 /* 8478 * We used to check the fact that the value passed 8479 * was an NCName, but this generated much troubles for 8480 * me and Aleksey Sanin, people blatantly violated that 8481 * constaint, like Visa3D spec. 8482 * if (xmlValidateNCName(ID, 1) == 0) 8483 */ 8484 attr = xmlGetID(doc, ID); 8485 if (attr != NULL) { 8486 if (attr->type == XML_ATTRIBUTE_NODE) 8487 elem = attr->parent; 8488 else if (attr->type == XML_ELEMENT_NODE) 8489 elem = (xmlNodePtr) attr; 8490 else 8491 elem = NULL; 8492 if (elem != NULL) 8493 xmlXPathNodeSetAdd(ret, elem); 8494 } 8495 xmlFree(ID); 8496 } 8497 8498 while (IS_BLANK_CH(*cur)) cur++; 8499 ids = cur; 8500 } 8501 return(ret); 8502} 8503 8504/** 8505 * xmlXPathIdFunction: 8506 * @ctxt: the XPath Parser context 8507 * @nargs: the number of arguments 8508 * 8509 * Implement the id() XPath function 8510 * node-set id(object) 8511 * The id function selects elements by their unique ID 8512 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8513 * then the result is the union of the result of applying id to the 8514 * string value of each of the nodes in the argument node-set. When the 8515 * argument to id is of any other type, the argument is converted to a 8516 * string as if by a call to the string function; the string is split 8517 * into a whitespace-separated list of tokens (whitespace is any sequence 8518 * of characters matching the production S); the result is a node-set 8519 * containing the elements in the same document as the context node that 8520 * have a unique ID equal to any of the tokens in the list. 8521 */ 8522void 8523xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8524 xmlChar *tokens; 8525 xmlNodeSetPtr ret; 8526 xmlXPathObjectPtr obj; 8527 8528 CHECK_ARITY(1); 8529 obj = valuePop(ctxt); 8530 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8531 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8532 xmlNodeSetPtr ns; 8533 int i; 8534 8535 ret = xmlXPathNodeSetCreate(NULL); 8536 /* 8537 * FIXME -- in an out-of-memory condition this will behave badly. 8538 * The solution is not clear -- we already popped an item from 8539 * ctxt, so the object is in a corrupt state. 8540 */ 8541 8542 if (obj->nodesetval != NULL) { 8543 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8544 tokens = 8545 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8546 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8547 ret = xmlXPathNodeSetMerge(ret, ns); 8548 xmlXPathFreeNodeSet(ns); 8549 if (tokens != NULL) 8550 xmlFree(tokens); 8551 } 8552 } 8553 xmlXPathReleaseObject(ctxt->context, obj); 8554 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8555 return; 8556 } 8557 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8558 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8559 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8560 xmlXPathReleaseObject(ctxt->context, obj); 8561 return; 8562} 8563 8564/** 8565 * xmlXPathLocalNameFunction: 8566 * @ctxt: the XPath Parser context 8567 * @nargs: the number of arguments 8568 * 8569 * Implement the local-name() XPath function 8570 * string local-name(node-set?) 8571 * The local-name function returns a string containing the local part 8572 * of the name of the node in the argument node-set that is first in 8573 * document order. If the node-set is empty or the first node has no 8574 * name, an empty string is returned. If the argument is omitted it 8575 * defaults to the context node. 8576 */ 8577void 8578xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8579 xmlXPathObjectPtr cur; 8580 8581 if (ctxt == NULL) return; 8582 8583 if (nargs == 0) { 8584 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8585 ctxt->context->node)); 8586 nargs = 1; 8587 } 8588 8589 CHECK_ARITY(1); 8590 if ((ctxt->value == NULL) || 8591 ((ctxt->value->type != XPATH_NODESET) && 8592 (ctxt->value->type != XPATH_XSLT_TREE))) 8593 XP_ERROR(XPATH_INVALID_TYPE); 8594 cur = valuePop(ctxt); 8595 8596 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8597 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8598 } else { 8599 int i = 0; /* Should be first in document order !!!!! */ 8600 switch (cur->nodesetval->nodeTab[i]->type) { 8601 case XML_ELEMENT_NODE: 8602 case XML_ATTRIBUTE_NODE: 8603 case XML_PI_NODE: 8604 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8605 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8606 else 8607 valuePush(ctxt, 8608 xmlXPathCacheNewString(ctxt->context, 8609 cur->nodesetval->nodeTab[i]->name)); 8610 break; 8611 case XML_NAMESPACE_DECL: 8612 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8613 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8614 break; 8615 default: 8616 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8617 } 8618 } 8619 xmlXPathReleaseObject(ctxt->context, cur); 8620} 8621 8622/** 8623 * xmlXPathNamespaceURIFunction: 8624 * @ctxt: the XPath Parser context 8625 * @nargs: the number of arguments 8626 * 8627 * Implement the namespace-uri() XPath function 8628 * string namespace-uri(node-set?) 8629 * The namespace-uri function returns a string containing the 8630 * namespace URI of the expanded name of the node in the argument 8631 * node-set that is first in document order. If the node-set is empty, 8632 * the first node has no name, or the expanded name has no namespace 8633 * URI, an empty string is returned. If the argument is omitted it 8634 * defaults to the context node. 8635 */ 8636void 8637xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8638 xmlXPathObjectPtr cur; 8639 8640 if (ctxt == NULL) return; 8641 8642 if (nargs == 0) { 8643 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8644 ctxt->context->node)); 8645 nargs = 1; 8646 } 8647 CHECK_ARITY(1); 8648 if ((ctxt->value == NULL) || 8649 ((ctxt->value->type != XPATH_NODESET) && 8650 (ctxt->value->type != XPATH_XSLT_TREE))) 8651 XP_ERROR(XPATH_INVALID_TYPE); 8652 cur = valuePop(ctxt); 8653 8654 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8655 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8656 } else { 8657 int i = 0; /* Should be first in document order !!!!! */ 8658 switch (cur->nodesetval->nodeTab[i]->type) { 8659 case XML_ELEMENT_NODE: 8660 case XML_ATTRIBUTE_NODE: 8661 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8662 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8663 else 8664 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8665 cur->nodesetval->nodeTab[i]->ns->href)); 8666 break; 8667 default: 8668 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8669 } 8670 } 8671 xmlXPathReleaseObject(ctxt->context, cur); 8672} 8673 8674/** 8675 * xmlXPathNameFunction: 8676 * @ctxt: the XPath Parser context 8677 * @nargs: the number of arguments 8678 * 8679 * Implement the name() XPath function 8680 * string name(node-set?) 8681 * The name function returns a string containing a QName representing 8682 * the name of the node in the argument node-set that is first in document 8683 * order. The QName must represent the name with respect to the namespace 8684 * declarations in effect on the node whose name is being represented. 8685 * Typically, this will be the form in which the name occurred in the XML 8686 * source. This need not be the case if there are namespace declarations 8687 * in effect on the node that associate multiple prefixes with the same 8688 * namespace. However, an implementation may include information about 8689 * the original prefix in its representation of nodes; in this case, an 8690 * implementation can ensure that the returned string is always the same 8691 * as the QName used in the XML source. If the argument it omitted it 8692 * defaults to the context node. 8693 * Libxml keep the original prefix so the "real qualified name" used is 8694 * returned. 8695 */ 8696static void 8697xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8698{ 8699 xmlXPathObjectPtr cur; 8700 8701 if (nargs == 0) { 8702 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8703 ctxt->context->node)); 8704 nargs = 1; 8705 } 8706 8707 CHECK_ARITY(1); 8708 if ((ctxt->value == NULL) || 8709 ((ctxt->value->type != XPATH_NODESET) && 8710 (ctxt->value->type != XPATH_XSLT_TREE))) 8711 XP_ERROR(XPATH_INVALID_TYPE); 8712 cur = valuePop(ctxt); 8713 8714 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8715 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8716 } else { 8717 int i = 0; /* Should be first in document order !!!!! */ 8718 8719 switch (cur->nodesetval->nodeTab[i]->type) { 8720 case XML_ELEMENT_NODE: 8721 case XML_ATTRIBUTE_NODE: 8722 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8723 valuePush(ctxt, 8724 xmlXPathCacheNewCString(ctxt->context, "")); 8725 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8726 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8727 valuePush(ctxt, 8728 xmlXPathCacheNewString(ctxt->context, 8729 cur->nodesetval->nodeTab[i]->name)); 8730 } else { 8731 xmlChar *fullname; 8732 8733 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8734 cur->nodesetval->nodeTab[i]->ns->prefix, 8735 NULL, 0); 8736 if (fullname == cur->nodesetval->nodeTab[i]->name) 8737 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8738 if (fullname == NULL) { 8739 XP_ERROR(XPATH_MEMORY_ERROR); 8740 } 8741 valuePush(ctxt, xmlXPathCacheWrapString( 8742 ctxt->context, fullname)); 8743 } 8744 break; 8745 default: 8746 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8747 cur->nodesetval->nodeTab[i])); 8748 xmlXPathLocalNameFunction(ctxt, 1); 8749 } 8750 } 8751 xmlXPathReleaseObject(ctxt->context, cur); 8752} 8753 8754 8755/** 8756 * xmlXPathStringFunction: 8757 * @ctxt: the XPath Parser context 8758 * @nargs: the number of arguments 8759 * 8760 * Implement the string() XPath function 8761 * string string(object?) 8762 * The string function converts an object to a string as follows: 8763 * - A node-set is converted to a string by returning the value of 8764 * the node in the node-set that is first in document order. 8765 * If the node-set is empty, an empty string is returned. 8766 * - A number is converted to a string as follows 8767 * + NaN is converted to the string NaN 8768 * + positive zero is converted to the string 0 8769 * + negative zero is converted to the string 0 8770 * + positive infinity is converted to the string Infinity 8771 * + negative infinity is converted to the string -Infinity 8772 * + if the number is an integer, the number is represented in 8773 * decimal form as a Number with no decimal point and no leading 8774 * zeros, preceded by a minus sign (-) if the number is negative 8775 * + otherwise, the number is represented in decimal form as a 8776 * Number including a decimal point with at least one digit 8777 * before the decimal point and at least one digit after the 8778 * decimal point, preceded by a minus sign (-) if the number 8779 * is negative; there must be no leading zeros before the decimal 8780 * point apart possibly from the one required digit immediately 8781 * before the decimal point; beyond the one required digit 8782 * after the decimal point there must be as many, but only as 8783 * many, more digits as are needed to uniquely distinguish the 8784 * number from all other IEEE 754 numeric values. 8785 * - The boolean false value is converted to the string false. 8786 * The boolean true value is converted to the string true. 8787 * 8788 * If the argument is omitted, it defaults to a node-set with the 8789 * context node as its only member. 8790 */ 8791void 8792xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8793 xmlXPathObjectPtr cur; 8794 8795 if (ctxt == NULL) return; 8796 if (nargs == 0) { 8797 valuePush(ctxt, 8798 xmlXPathCacheWrapString(ctxt->context, 8799 xmlXPathCastNodeToString(ctxt->context->node))); 8800 return; 8801 } 8802 8803 CHECK_ARITY(1); 8804 cur = valuePop(ctxt); 8805 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8806 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8807} 8808 8809/** 8810 * xmlXPathStringLengthFunction: 8811 * @ctxt: the XPath Parser context 8812 * @nargs: the number of arguments 8813 * 8814 * Implement the string-length() XPath function 8815 * number string-length(string?) 8816 * The string-length returns the number of characters in the string 8817 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8818 * the context node converted to a string, in other words the value 8819 * of the context node. 8820 */ 8821void 8822xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8823 xmlXPathObjectPtr cur; 8824 8825 if (nargs == 0) { 8826 if ((ctxt == NULL) || (ctxt->context == NULL)) 8827 return; 8828 if (ctxt->context->node == NULL) { 8829 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8830 } else { 8831 xmlChar *content; 8832 8833 content = xmlXPathCastNodeToString(ctxt->context->node); 8834 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8835 xmlUTF8Strlen(content))); 8836 xmlFree(content); 8837 } 8838 return; 8839 } 8840 CHECK_ARITY(1); 8841 CAST_TO_STRING; 8842 CHECK_TYPE(XPATH_STRING); 8843 cur = valuePop(ctxt); 8844 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8845 xmlUTF8Strlen(cur->stringval))); 8846 xmlXPathReleaseObject(ctxt->context, cur); 8847} 8848 8849/** 8850 * xmlXPathConcatFunction: 8851 * @ctxt: the XPath Parser context 8852 * @nargs: the number of arguments 8853 * 8854 * Implement the concat() XPath function 8855 * string concat(string, string, string*) 8856 * The concat function returns the concatenation of its arguments. 8857 */ 8858void 8859xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8860 xmlXPathObjectPtr cur, newobj; 8861 xmlChar *tmp; 8862 8863 if (ctxt == NULL) return; 8864 if (nargs < 2) { 8865 CHECK_ARITY(2); 8866 } 8867 8868 CAST_TO_STRING; 8869 cur = valuePop(ctxt); 8870 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 8871 xmlXPathReleaseObject(ctxt->context, cur); 8872 return; 8873 } 8874 nargs--; 8875 8876 while (nargs > 0) { 8877 CAST_TO_STRING; 8878 newobj = valuePop(ctxt); 8879 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 8880 xmlXPathReleaseObject(ctxt->context, newobj); 8881 xmlXPathReleaseObject(ctxt->context, cur); 8882 XP_ERROR(XPATH_INVALID_TYPE); 8883 } 8884 tmp = xmlStrcat(newobj->stringval, cur->stringval); 8885 newobj->stringval = cur->stringval; 8886 cur->stringval = tmp; 8887 xmlXPathReleaseObject(ctxt->context, newobj); 8888 nargs--; 8889 } 8890 valuePush(ctxt, cur); 8891} 8892 8893/** 8894 * xmlXPathContainsFunction: 8895 * @ctxt: the XPath Parser context 8896 * @nargs: the number of arguments 8897 * 8898 * Implement the contains() XPath function 8899 * boolean contains(string, string) 8900 * The contains function returns true if the first argument string 8901 * contains the second argument string, and otherwise returns false. 8902 */ 8903void 8904xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8905 xmlXPathObjectPtr hay, needle; 8906 8907 CHECK_ARITY(2); 8908 CAST_TO_STRING; 8909 CHECK_TYPE(XPATH_STRING); 8910 needle = valuePop(ctxt); 8911 CAST_TO_STRING; 8912 hay = valuePop(ctxt); 8913 8914 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 8915 xmlXPathReleaseObject(ctxt->context, hay); 8916 xmlXPathReleaseObject(ctxt->context, needle); 8917 XP_ERROR(XPATH_INVALID_TYPE); 8918 } 8919 if (xmlStrstr(hay->stringval, needle->stringval)) 8920 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 8921 else 8922 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 8923 xmlXPathReleaseObject(ctxt->context, hay); 8924 xmlXPathReleaseObject(ctxt->context, needle); 8925} 8926 8927/** 8928 * xmlXPathStartsWithFunction: 8929 * @ctxt: the XPath Parser context 8930 * @nargs: the number of arguments 8931 * 8932 * Implement the starts-with() XPath function 8933 * boolean starts-with(string, string) 8934 * The starts-with function returns true if the first argument string 8935 * starts with the second argument string, and otherwise returns false. 8936 */ 8937void 8938xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8939 xmlXPathObjectPtr hay, needle; 8940 int n; 8941 8942 CHECK_ARITY(2); 8943 CAST_TO_STRING; 8944 CHECK_TYPE(XPATH_STRING); 8945 needle = valuePop(ctxt); 8946 CAST_TO_STRING; 8947 hay = valuePop(ctxt); 8948 8949 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 8950 xmlXPathReleaseObject(ctxt->context, hay); 8951 xmlXPathReleaseObject(ctxt->context, needle); 8952 XP_ERROR(XPATH_INVALID_TYPE); 8953 } 8954 n = xmlStrlen(needle->stringval); 8955 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 8956 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 8957 else 8958 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 8959 xmlXPathReleaseObject(ctxt->context, hay); 8960 xmlXPathReleaseObject(ctxt->context, needle); 8961} 8962 8963/** 8964 * xmlXPathSubstringFunction: 8965 * @ctxt: the XPath Parser context 8966 * @nargs: the number of arguments 8967 * 8968 * Implement the substring() XPath function 8969 * string substring(string, number, number?) 8970 * The substring function returns the substring of the first argument 8971 * starting at the position specified in the second argument with 8972 * length specified in the third argument. For example, 8973 * substring("12345",2,3) returns "234". If the third argument is not 8974 * specified, it returns the substring starting at the position specified 8975 * in the second argument and continuing to the end of the string. For 8976 * example, substring("12345",2) returns "2345". More precisely, each 8977 * character in the string (see [3.6 Strings]) is considered to have a 8978 * numeric position: the position of the first character is 1, the position 8979 * of the second character is 2 and so on. The returned substring contains 8980 * those characters for which the position of the character is greater than 8981 * or equal to the second argument and, if the third argument is specified, 8982 * less than the sum of the second and third arguments; the comparisons 8983 * and addition used for the above follow the standard IEEE 754 rules. Thus: 8984 * - substring("12345", 1.5, 2.6) returns "234" 8985 * - substring("12345", 0, 3) returns "12" 8986 * - substring("12345", 0 div 0, 3) returns "" 8987 * - substring("12345", 1, 0 div 0) returns "" 8988 * - substring("12345", -42, 1 div 0) returns "12345" 8989 * - substring("12345", -1 div 0, 1 div 0) returns "" 8990 */ 8991void 8992xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8993 xmlXPathObjectPtr str, start, len; 8994 double le=0, in; 8995 int i, l, m; 8996 xmlChar *ret; 8997 8998 if (nargs < 2) { 8999 CHECK_ARITY(2); 9000 } 9001 if (nargs > 3) { 9002 CHECK_ARITY(3); 9003 } 9004 /* 9005 * take care of possible last (position) argument 9006 */ 9007 if (nargs == 3) { 9008 CAST_TO_NUMBER; 9009 CHECK_TYPE(XPATH_NUMBER); 9010 len = valuePop(ctxt); 9011 le = len->floatval; 9012 xmlXPathReleaseObject(ctxt->context, len); 9013 } 9014 9015 CAST_TO_NUMBER; 9016 CHECK_TYPE(XPATH_NUMBER); 9017 start = valuePop(ctxt); 9018 in = start->floatval; 9019 xmlXPathReleaseObject(ctxt->context, start); 9020 CAST_TO_STRING; 9021 CHECK_TYPE(XPATH_STRING); 9022 str = valuePop(ctxt); 9023 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 9024 9025 /* 9026 * If last pos not present, calculate last position 9027 */ 9028 if (nargs != 3) { 9029 le = (double)m; 9030 if (in < 1.0) 9031 in = 1.0; 9032 } 9033 9034 /* Need to check for the special cases where either 9035 * the index is NaN, the length is NaN, or both 9036 * arguments are infinity (relying on Inf + -Inf = NaN) 9037 */ 9038 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) { 9039 /* 9040 * To meet the requirements of the spec, the arguments 9041 * must be converted to integer format before 9042 * initial index calculations are done 9043 * 9044 * First we go to integer form, rounding up 9045 * and checking for special cases 9046 */ 9047 i = (int) in; 9048 if (((double)i)+0.5 <= in) i++; 9049 9050 if (xmlXPathIsInf(le) == 1) { 9051 l = m; 9052 if (i < 1) 9053 i = 1; 9054 } 9055 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 9056 l = 0; 9057 else { 9058 l = (int) le; 9059 if (((double)l)+0.5 <= le) l++; 9060 } 9061 9062 /* Now we normalize inidices */ 9063 i -= 1; 9064 l += i; 9065 if (i < 0) 9066 i = 0; 9067 if (l > m) 9068 l = m; 9069 9070 /* number of chars to copy */ 9071 l -= i; 9072 9073 ret = xmlUTF8Strsub(str->stringval, i, l); 9074 } 9075 else { 9076 ret = NULL; 9077 } 9078 if (ret == NULL) 9079 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 9080 else { 9081 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 9082 xmlFree(ret); 9083 } 9084 xmlXPathReleaseObject(ctxt->context, str); 9085} 9086 9087/** 9088 * xmlXPathSubstringBeforeFunction: 9089 * @ctxt: the XPath Parser context 9090 * @nargs: the number of arguments 9091 * 9092 * Implement the substring-before() XPath function 9093 * string substring-before(string, string) 9094 * The substring-before function returns the substring of the first 9095 * argument string that precedes the first occurrence of the second 9096 * argument string in the first argument string, or the empty string 9097 * if the first argument string does not contain the second argument 9098 * string. For example, substring-before("1999/04/01","/") returns 1999. 9099 */ 9100void 9101xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9102 xmlXPathObjectPtr str; 9103 xmlXPathObjectPtr find; 9104 xmlBufferPtr target; 9105 const xmlChar *point; 9106 int offset; 9107 9108 CHECK_ARITY(2); 9109 CAST_TO_STRING; 9110 find = valuePop(ctxt); 9111 CAST_TO_STRING; 9112 str = valuePop(ctxt); 9113 9114 target = xmlBufferCreate(); 9115 if (target) { 9116 point = xmlStrstr(str->stringval, find->stringval); 9117 if (point) { 9118 offset = (int)(point - str->stringval); 9119 xmlBufferAdd(target, str->stringval, offset); 9120 } 9121 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9122 xmlBufferContent(target))); 9123 xmlBufferFree(target); 9124 } 9125 xmlXPathReleaseObject(ctxt->context, str); 9126 xmlXPathReleaseObject(ctxt->context, find); 9127} 9128 9129/** 9130 * xmlXPathSubstringAfterFunction: 9131 * @ctxt: the XPath Parser context 9132 * @nargs: the number of arguments 9133 * 9134 * Implement the substring-after() XPath function 9135 * string substring-after(string, string) 9136 * The substring-after function returns the substring of the first 9137 * argument string that follows the first occurrence of the second 9138 * argument string in the first argument string, or the empty stringi 9139 * if the first argument string does not contain the second argument 9140 * string. For example, substring-after("1999/04/01","/") returns 04/01, 9141 * and substring-after("1999/04/01","19") returns 99/04/01. 9142 */ 9143void 9144xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9145 xmlXPathObjectPtr str; 9146 xmlXPathObjectPtr find; 9147 xmlBufferPtr target; 9148 const xmlChar *point; 9149 int offset; 9150 9151 CHECK_ARITY(2); 9152 CAST_TO_STRING; 9153 find = valuePop(ctxt); 9154 CAST_TO_STRING; 9155 str = valuePop(ctxt); 9156 9157 target = xmlBufferCreate(); 9158 if (target) { 9159 point = xmlStrstr(str->stringval, find->stringval); 9160 if (point) { 9161 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 9162 xmlBufferAdd(target, &str->stringval[offset], 9163 xmlStrlen(str->stringval) - offset); 9164 } 9165 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9166 xmlBufferContent(target))); 9167 xmlBufferFree(target); 9168 } 9169 xmlXPathReleaseObject(ctxt->context, str); 9170 xmlXPathReleaseObject(ctxt->context, find); 9171} 9172 9173/** 9174 * xmlXPathNormalizeFunction: 9175 * @ctxt: the XPath Parser context 9176 * @nargs: the number of arguments 9177 * 9178 * Implement the normalize-space() XPath function 9179 * string normalize-space(string?) 9180 * The normalize-space function returns the argument string with white 9181 * space normalized by stripping leading and trailing whitespace 9182 * and replacing sequences of whitespace characters by a single 9183 * space. Whitespace characters are the same allowed by the S production 9184 * in XML. If the argument is omitted, it defaults to the context 9185 * node converted to a string, in other words the value of the context node. 9186 */ 9187void 9188xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9189 xmlXPathObjectPtr obj = NULL; 9190 xmlChar *source = NULL; 9191 xmlBufferPtr target; 9192 xmlChar blank; 9193 9194 if (ctxt == NULL) return; 9195 if (nargs == 0) { 9196 /* Use current context node */ 9197 valuePush(ctxt, 9198 xmlXPathCacheWrapString(ctxt->context, 9199 xmlXPathCastNodeToString(ctxt->context->node))); 9200 nargs = 1; 9201 } 9202 9203 CHECK_ARITY(1); 9204 CAST_TO_STRING; 9205 CHECK_TYPE(XPATH_STRING); 9206 obj = valuePop(ctxt); 9207 source = obj->stringval; 9208 9209 target = xmlBufferCreate(); 9210 if (target && source) { 9211 9212 /* Skip leading whitespaces */ 9213 while (IS_BLANK_CH(*source)) 9214 source++; 9215 9216 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 9217 blank = 0; 9218 while (*source) { 9219 if (IS_BLANK_CH(*source)) { 9220 blank = 0x20; 9221 } else { 9222 if (blank) { 9223 xmlBufferAdd(target, &blank, 1); 9224 blank = 0; 9225 } 9226 xmlBufferAdd(target, source, 1); 9227 } 9228 source++; 9229 } 9230 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9231 xmlBufferContent(target))); 9232 xmlBufferFree(target); 9233 } 9234 xmlXPathReleaseObject(ctxt->context, obj); 9235} 9236 9237/** 9238 * xmlXPathTranslateFunction: 9239 * @ctxt: the XPath Parser context 9240 * @nargs: the number of arguments 9241 * 9242 * Implement the translate() XPath function 9243 * string translate(string, string, string) 9244 * The translate function returns the first argument string with 9245 * occurrences of characters in the second argument string replaced 9246 * by the character at the corresponding position in the third argument 9247 * string. For example, translate("bar","abc","ABC") returns the string 9248 * BAr. If there is a character in the second argument string with no 9249 * character at a corresponding position in the third argument string 9250 * (because the second argument string is longer than the third argument 9251 * string), then occurrences of that character in the first argument 9252 * string are removed. For example, translate("--aaa--","abc-","ABC") 9253 * returns "AAA". If a character occurs more than once in second 9254 * argument string, then the first occurrence determines the replacement 9255 * character. If the third argument string is longer than the second 9256 * argument string, then excess characters are ignored. 9257 */ 9258void 9259xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9260 xmlXPathObjectPtr str; 9261 xmlXPathObjectPtr from; 9262 xmlXPathObjectPtr to; 9263 xmlBufferPtr target; 9264 int offset, max; 9265 xmlChar ch; 9266 const xmlChar *point; 9267 xmlChar *cptr; 9268 9269 CHECK_ARITY(3); 9270 9271 CAST_TO_STRING; 9272 to = valuePop(ctxt); 9273 CAST_TO_STRING; 9274 from = valuePop(ctxt); 9275 CAST_TO_STRING; 9276 str = valuePop(ctxt); 9277 9278 target = xmlBufferCreate(); 9279 if (target) { 9280 max = xmlUTF8Strlen(to->stringval); 9281 for (cptr = str->stringval; (ch=*cptr); ) { 9282 offset = xmlUTF8Strloc(from->stringval, cptr); 9283 if (offset >= 0) { 9284 if (offset < max) { 9285 point = xmlUTF8Strpos(to->stringval, offset); 9286 if (point) 9287 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1)); 9288 } 9289 } else 9290 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 9291 9292 /* Step to next character in input */ 9293 cptr++; 9294 if ( ch & 0x80 ) { 9295 /* if not simple ascii, verify proper format */ 9296 if ( (ch & 0xc0) != 0xc0 ) { 9297 xmlGenericError(xmlGenericErrorContext, 9298 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9299 break; 9300 } 9301 /* then skip over remaining bytes for this char */ 9302 while ( (ch <<= 1) & 0x80 ) 9303 if ( (*cptr++ & 0xc0) != 0x80 ) { 9304 xmlGenericError(xmlGenericErrorContext, 9305 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 9306 break; 9307 } 9308 if (ch & 0x80) /* must have had error encountered */ 9309 break; 9310 } 9311 } 9312 } 9313 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9314 xmlBufferContent(target))); 9315 xmlBufferFree(target); 9316 xmlXPathReleaseObject(ctxt->context, str); 9317 xmlXPathReleaseObject(ctxt->context, from); 9318 xmlXPathReleaseObject(ctxt->context, to); 9319} 9320 9321/** 9322 * xmlXPathBooleanFunction: 9323 * @ctxt: the XPath Parser context 9324 * @nargs: the number of arguments 9325 * 9326 * Implement the boolean() XPath function 9327 * boolean boolean(object) 9328 * The boolean function converts its argument to a boolean as follows: 9329 * - a number is true if and only if it is neither positive or 9330 * negative zero nor NaN 9331 * - a node-set is true if and only if it is non-empty 9332 * - a string is true if and only if its length is non-zero 9333 */ 9334void 9335xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9336 xmlXPathObjectPtr cur; 9337 9338 CHECK_ARITY(1); 9339 cur = valuePop(ctxt); 9340 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9341 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9342 valuePush(ctxt, cur); 9343} 9344 9345/** 9346 * xmlXPathNotFunction: 9347 * @ctxt: the XPath Parser context 9348 * @nargs: the number of arguments 9349 * 9350 * Implement the not() XPath function 9351 * boolean not(boolean) 9352 * The not function returns true if its argument is false, 9353 * and false otherwise. 9354 */ 9355void 9356xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9357 CHECK_ARITY(1); 9358 CAST_TO_BOOLEAN; 9359 CHECK_TYPE(XPATH_BOOLEAN); 9360 ctxt->value->boolval = ! ctxt->value->boolval; 9361} 9362 9363/** 9364 * xmlXPathTrueFunction: 9365 * @ctxt: the XPath Parser context 9366 * @nargs: the number of arguments 9367 * 9368 * Implement the true() XPath function 9369 * boolean true() 9370 */ 9371void 9372xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9373 CHECK_ARITY(0); 9374 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9375} 9376 9377/** 9378 * xmlXPathFalseFunction: 9379 * @ctxt: the XPath Parser context 9380 * @nargs: the number of arguments 9381 * 9382 * Implement the false() XPath function 9383 * boolean false() 9384 */ 9385void 9386xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9387 CHECK_ARITY(0); 9388 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9389} 9390 9391/** 9392 * xmlXPathLangFunction: 9393 * @ctxt: the XPath Parser context 9394 * @nargs: the number of arguments 9395 * 9396 * Implement the lang() XPath function 9397 * boolean lang(string) 9398 * The lang function returns true or false depending on whether the 9399 * language of the context node as specified by xml:lang attributes 9400 * is the same as or is a sublanguage of the language specified by 9401 * the argument string. The language of the context node is determined 9402 * by the value of the xml:lang attribute on the context node, or, if 9403 * the context node has no xml:lang attribute, by the value of the 9404 * xml:lang attribute on the nearest ancestor of the context node that 9405 * has an xml:lang attribute. If there is no such attribute, then lang 9406 * returns false. If there is such an attribute, then lang returns 9407 * true if the attribute value is equal to the argument ignoring case, 9408 * or if there is some suffix starting with - such that the attribute 9409 * value is equal to the argument ignoring that suffix of the attribute 9410 * value and ignoring case. 9411 */ 9412void 9413xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9414 xmlXPathObjectPtr val = NULL; 9415 const xmlChar *theLang = NULL; 9416 const xmlChar *lang; 9417 int ret = 0; 9418 int i; 9419 9420 CHECK_ARITY(1); 9421 CAST_TO_STRING; 9422 CHECK_TYPE(XPATH_STRING); 9423 val = valuePop(ctxt); 9424 lang = val->stringval; 9425 theLang = xmlNodeGetLang(ctxt->context->node); 9426 if ((theLang != NULL) && (lang != NULL)) { 9427 for (i = 0;lang[i] != 0;i++) 9428 if (toupper(lang[i]) != toupper(theLang[i])) 9429 goto not_equal; 9430 if ((theLang[i] == 0) || (theLang[i] == '-')) 9431 ret = 1; 9432 } 9433not_equal: 9434 if (theLang != NULL) 9435 xmlFree((void *)theLang); 9436 9437 xmlXPathReleaseObject(ctxt->context, val); 9438 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9439} 9440 9441/** 9442 * xmlXPathNumberFunction: 9443 * @ctxt: the XPath Parser context 9444 * @nargs: the number of arguments 9445 * 9446 * Implement the number() XPath function 9447 * number number(object?) 9448 */ 9449void 9450xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9451 xmlXPathObjectPtr cur; 9452 double res; 9453 9454 if (ctxt == NULL) return; 9455 if (nargs == 0) { 9456 if (ctxt->context->node == NULL) { 9457 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9458 } else { 9459 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9460 9461 res = xmlXPathStringEvalNumber(content); 9462 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9463 xmlFree(content); 9464 } 9465 return; 9466 } 9467 9468 CHECK_ARITY(1); 9469 cur = valuePop(ctxt); 9470 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9471} 9472 9473/** 9474 * xmlXPathSumFunction: 9475 * @ctxt: the XPath Parser context 9476 * @nargs: the number of arguments 9477 * 9478 * Implement the sum() XPath function 9479 * number sum(node-set) 9480 * The sum function returns the sum of the values of the nodes in 9481 * the argument node-set. 9482 */ 9483void 9484xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9485 xmlXPathObjectPtr cur; 9486 int i; 9487 double res = 0.0; 9488 9489 CHECK_ARITY(1); 9490 if ((ctxt->value == NULL) || 9491 ((ctxt->value->type != XPATH_NODESET) && 9492 (ctxt->value->type != XPATH_XSLT_TREE))) 9493 XP_ERROR(XPATH_INVALID_TYPE); 9494 cur = valuePop(ctxt); 9495 9496 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9497 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9498 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9499 } 9500 } 9501 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9502 xmlXPathReleaseObject(ctxt->context, cur); 9503} 9504 9505/* 9506 * To assure working code on multiple platforms, we want to only depend 9507 * upon the characteristic truncation of converting a floating point value 9508 * to an integer. Unfortunately, because of the different storage sizes 9509 * of our internal floating point value (double) and integer (int), we 9510 * can't directly convert (see bug 301162). This macro is a messy 9511 * 'workaround' 9512 */ 9513#define XTRUNC(f, v) \ 9514 f = fmod((v), INT_MAX); \ 9515 f = (v) - (f) + (double)((int)(f)); 9516 9517/** 9518 * xmlXPathFloorFunction: 9519 * @ctxt: the XPath Parser context 9520 * @nargs: the number of arguments 9521 * 9522 * Implement the floor() XPath function 9523 * number floor(number) 9524 * The floor function returns the largest (closest to positive infinity) 9525 * number that is not greater than the argument and that is an integer. 9526 */ 9527void 9528xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9529 double f; 9530 9531 CHECK_ARITY(1); 9532 CAST_TO_NUMBER; 9533 CHECK_TYPE(XPATH_NUMBER); 9534 9535 XTRUNC(f, ctxt->value->floatval); 9536 if (f != ctxt->value->floatval) { 9537 if (ctxt->value->floatval > 0) 9538 ctxt->value->floatval = f; 9539 else 9540 ctxt->value->floatval = f - 1; 9541 } 9542} 9543 9544/** 9545 * xmlXPathCeilingFunction: 9546 * @ctxt: the XPath Parser context 9547 * @nargs: the number of arguments 9548 * 9549 * Implement the ceiling() XPath function 9550 * number ceiling(number) 9551 * The ceiling function returns the smallest (closest to negative infinity) 9552 * number that is not less than the argument and that is an integer. 9553 */ 9554void 9555xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9556 double f; 9557 9558 CHECK_ARITY(1); 9559 CAST_TO_NUMBER; 9560 CHECK_TYPE(XPATH_NUMBER); 9561 9562#if 0 9563 ctxt->value->floatval = ceil(ctxt->value->floatval); 9564#else 9565 XTRUNC(f, ctxt->value->floatval); 9566 if (f != ctxt->value->floatval) { 9567 if (ctxt->value->floatval > 0) 9568 ctxt->value->floatval = f + 1; 9569 else { 9570 if (ctxt->value->floatval < 0 && f == 0) 9571 ctxt->value->floatval = xmlXPathNZERO; 9572 else 9573 ctxt->value->floatval = f; 9574 } 9575 9576 } 9577#endif 9578} 9579 9580/** 9581 * xmlXPathRoundFunction: 9582 * @ctxt: the XPath Parser context 9583 * @nargs: the number of arguments 9584 * 9585 * Implement the round() XPath function 9586 * number round(number) 9587 * The round function returns the number that is closest to the 9588 * argument and that is an integer. If there are two such numbers, 9589 * then the one that is even is returned. 9590 */ 9591void 9592xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9593 double f; 9594 9595 CHECK_ARITY(1); 9596 CAST_TO_NUMBER; 9597 CHECK_TYPE(XPATH_NUMBER); 9598 9599 if ((xmlXPathIsNaN(ctxt->value->floatval)) || 9600 (xmlXPathIsInf(ctxt->value->floatval) == 1) || 9601 (xmlXPathIsInf(ctxt->value->floatval) == -1) || 9602 (ctxt->value->floatval == 0.0)) 9603 return; 9604 9605 XTRUNC(f, ctxt->value->floatval); 9606 if (ctxt->value->floatval < 0) { 9607 if (ctxt->value->floatval < f - 0.5) 9608 ctxt->value->floatval = f - 1; 9609 else 9610 ctxt->value->floatval = f; 9611 if (ctxt->value->floatval == 0) 9612 ctxt->value->floatval = xmlXPathNZERO; 9613 } else { 9614 if (ctxt->value->floatval < f + 0.5) 9615 ctxt->value->floatval = f; 9616 else 9617 ctxt->value->floatval = f + 1; 9618 } 9619} 9620 9621/************************************************************************ 9622 * * 9623 * The Parser * 9624 * * 9625 ************************************************************************/ 9626 9627/* 9628 * a few forward declarations since we use a recursive call based 9629 * implementation. 9630 */ 9631static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9632static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9633static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9634static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9635static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9636 int qualified); 9637 9638/** 9639 * xmlXPathCurrentChar: 9640 * @ctxt: the XPath parser context 9641 * @cur: pointer to the beginning of the char 9642 * @len: pointer to the length of the char read 9643 * 9644 * The current char value, if using UTF-8 this may actually span multiple 9645 * bytes in the input buffer. 9646 * 9647 * Returns the current char value and its length 9648 */ 9649 9650static int 9651xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9652 unsigned char c; 9653 unsigned int val; 9654 const xmlChar *cur; 9655 9656 if (ctxt == NULL) 9657 return(0); 9658 cur = ctxt->cur; 9659 9660 /* 9661 * We are supposed to handle UTF8, check it's valid 9662 * From rfc2044: encoding of the Unicode values on UTF-8: 9663 * 9664 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9665 * 0000 0000-0000 007F 0xxxxxxx 9666 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9667 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9668 * 9669 * Check for the 0x110000 limit too 9670 */ 9671 c = *cur; 9672 if (c & 0x80) { 9673 if ((cur[1] & 0xc0) != 0x80) 9674 goto encoding_error; 9675 if ((c & 0xe0) == 0xe0) { 9676 9677 if ((cur[2] & 0xc0) != 0x80) 9678 goto encoding_error; 9679 if ((c & 0xf0) == 0xf0) { 9680 if (((c & 0xf8) != 0xf0) || 9681 ((cur[3] & 0xc0) != 0x80)) 9682 goto encoding_error; 9683 /* 4-byte code */ 9684 *len = 4; 9685 val = (cur[0] & 0x7) << 18; 9686 val |= (cur[1] & 0x3f) << 12; 9687 val |= (cur[2] & 0x3f) << 6; 9688 val |= cur[3] & 0x3f; 9689 } else { 9690 /* 3-byte code */ 9691 *len = 3; 9692 val = (cur[0] & 0xf) << 12; 9693 val |= (cur[1] & 0x3f) << 6; 9694 val |= cur[2] & 0x3f; 9695 } 9696 } else { 9697 /* 2-byte code */ 9698 *len = 2; 9699 val = (cur[0] & 0x1f) << 6; 9700 val |= cur[1] & 0x3f; 9701 } 9702 if (!IS_CHAR(val)) { 9703 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9704 } 9705 return(val); 9706 } else { 9707 /* 1-byte code */ 9708 *len = 1; 9709 return((int) *cur); 9710 } 9711encoding_error: 9712 /* 9713 * If we detect an UTF8 error that probably means that the 9714 * input encoding didn't get properly advertised in the 9715 * declaration header. Report the error and switch the encoding 9716 * to ISO-Latin-1 (if you don't like this policy, just declare the 9717 * encoding !) 9718 */ 9719 *len = 0; 9720 XP_ERROR0(XPATH_ENCODING_ERROR); 9721} 9722 9723/** 9724 * xmlXPathParseNCName: 9725 * @ctxt: the XPath Parser context 9726 * 9727 * parse an XML namespace non qualified name. 9728 * 9729 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9730 * 9731 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9732 * CombiningChar | Extender 9733 * 9734 * Returns the namespace name or NULL 9735 */ 9736 9737xmlChar * 9738xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9739 const xmlChar *in; 9740 xmlChar *ret; 9741 int count = 0; 9742 9743 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9744 /* 9745 * Accelerator for simple ASCII names 9746 */ 9747 in = ctxt->cur; 9748 if (((*in >= 0x61) && (*in <= 0x7A)) || 9749 ((*in >= 0x41) && (*in <= 0x5A)) || 9750 (*in == '_')) { 9751 in++; 9752 while (((*in >= 0x61) && (*in <= 0x7A)) || 9753 ((*in >= 0x41) && (*in <= 0x5A)) || 9754 ((*in >= 0x30) && (*in <= 0x39)) || 9755 (*in == '_') || (*in == '.') || 9756 (*in == '-')) 9757 in++; 9758 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9759 (*in == '[') || (*in == ']') || (*in == ':') || 9760 (*in == '@') || (*in == '*')) { 9761 count = in - ctxt->cur; 9762 if (count == 0) 9763 return(NULL); 9764 ret = xmlStrndup(ctxt->cur, count); 9765 ctxt->cur = in; 9766 return(ret); 9767 } 9768 } 9769 return(xmlXPathParseNameComplex(ctxt, 0)); 9770} 9771 9772 9773/** 9774 * xmlXPathParseQName: 9775 * @ctxt: the XPath Parser context 9776 * @prefix: a xmlChar ** 9777 * 9778 * parse an XML qualified name 9779 * 9780 * [NS 5] QName ::= (Prefix ':')? LocalPart 9781 * 9782 * [NS 6] Prefix ::= NCName 9783 * 9784 * [NS 7] LocalPart ::= NCName 9785 * 9786 * Returns the function returns the local part, and prefix is updated 9787 * to get the Prefix if any. 9788 */ 9789 9790static xmlChar * 9791xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9792 xmlChar *ret = NULL; 9793 9794 *prefix = NULL; 9795 ret = xmlXPathParseNCName(ctxt); 9796 if (ret && CUR == ':') { 9797 *prefix = ret; 9798 NEXT; 9799 ret = xmlXPathParseNCName(ctxt); 9800 } 9801 return(ret); 9802} 9803 9804/** 9805 * xmlXPathParseName: 9806 * @ctxt: the XPath Parser context 9807 * 9808 * parse an XML name 9809 * 9810 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9811 * CombiningChar | Extender 9812 * 9813 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9814 * 9815 * Returns the namespace name or NULL 9816 */ 9817 9818xmlChar * 9819xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9820 const xmlChar *in; 9821 xmlChar *ret; 9822 int count = 0; 9823 9824 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9825 /* 9826 * Accelerator for simple ASCII names 9827 */ 9828 in = ctxt->cur; 9829 if (((*in >= 0x61) && (*in <= 0x7A)) || 9830 ((*in >= 0x41) && (*in <= 0x5A)) || 9831 (*in == '_') || (*in == ':')) { 9832 in++; 9833 while (((*in >= 0x61) && (*in <= 0x7A)) || 9834 ((*in >= 0x41) && (*in <= 0x5A)) || 9835 ((*in >= 0x30) && (*in <= 0x39)) || 9836 (*in == '_') || (*in == '-') || 9837 (*in == ':') || (*in == '.')) 9838 in++; 9839 if ((*in > 0) && (*in < 0x80)) { 9840 count = in - ctxt->cur; 9841 ret = xmlStrndup(ctxt->cur, count); 9842 ctxt->cur = in; 9843 return(ret); 9844 } 9845 } 9846 return(xmlXPathParseNameComplex(ctxt, 1)); 9847} 9848 9849static xmlChar * 9850xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9851 xmlChar buf[XML_MAX_NAMELEN + 5]; 9852 int len = 0, l; 9853 int c; 9854 9855 /* 9856 * Handler for more complex cases 9857 */ 9858 c = CUR_CHAR(l); 9859 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 9860 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 9861 (c == '*') || /* accelerators */ 9862 (!IS_LETTER(c) && (c != '_') && 9863 ((qualified) && (c != ':')))) { 9864 return(NULL); 9865 } 9866 9867 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 9868 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 9869 (c == '.') || (c == '-') || 9870 (c == '_') || ((qualified) && (c == ':')) || 9871 (IS_COMBINING(c)) || 9872 (IS_EXTENDER(c)))) { 9873 COPY_BUF(l,buf,len,c); 9874 NEXTL(l); 9875 c = CUR_CHAR(l); 9876 if (len >= XML_MAX_NAMELEN) { 9877 /* 9878 * Okay someone managed to make a huge name, so he's ready to pay 9879 * for the processing speed. 9880 */ 9881 xmlChar *buffer; 9882 int max = len * 2; 9883 9884 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 9885 if (buffer == NULL) { 9886 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9887 } 9888 memcpy(buffer, buf, len); 9889 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 9890 (c == '.') || (c == '-') || 9891 (c == '_') || ((qualified) && (c == ':')) || 9892 (IS_COMBINING(c)) || 9893 (IS_EXTENDER(c))) { 9894 if (len + 10 > max) { 9895 max *= 2; 9896 buffer = (xmlChar *) xmlRealloc(buffer, 9897 max * sizeof(xmlChar)); 9898 if (buffer == NULL) { 9899 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9900 } 9901 } 9902 COPY_BUF(l,buffer,len,c); 9903 NEXTL(l); 9904 c = CUR_CHAR(l); 9905 } 9906 buffer[len] = 0; 9907 return(buffer); 9908 } 9909 } 9910 if (len == 0) 9911 return(NULL); 9912 return(xmlStrndup(buf, len)); 9913} 9914 9915#define MAX_FRAC 20 9916 9917/* 9918 * These are used as divisors for the fractional part of a number. 9919 * Since the table includes 1.0 (representing '0' fractional digits), 9920 * it must be dimensioned at MAX_FRAC+1 (bug 133921) 9921 */ 9922static double my_pow10[MAX_FRAC+1] = { 9923 1.0, 10.0, 100.0, 1000.0, 10000.0, 9924 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 9925 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 9926 100000000000000.0, 9927 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 9928 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0 9929}; 9930 9931/** 9932 * xmlXPathStringEvalNumber: 9933 * @str: A string to scan 9934 * 9935 * [30a] Float ::= Number ('e' Digits?)? 9936 * 9937 * [30] Number ::= Digits ('.' Digits?)? 9938 * | '.' Digits 9939 * [31] Digits ::= [0-9]+ 9940 * 9941 * Compile a Number in the string 9942 * In complement of the Number expression, this function also handles 9943 * negative values : '-' Number. 9944 * 9945 * Returns the double value. 9946 */ 9947double 9948xmlXPathStringEvalNumber(const xmlChar *str) { 9949 const xmlChar *cur = str; 9950 double ret; 9951 int ok = 0; 9952 int isneg = 0; 9953 int exponent = 0; 9954 int is_exponent_negative = 0; 9955#ifdef __GNUC__ 9956 unsigned long tmp = 0; 9957 double temp; 9958#endif 9959 if (cur == NULL) return(0); 9960 while (IS_BLANK_CH(*cur)) cur++; 9961 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 9962 return(xmlXPathNAN); 9963 } 9964 if (*cur == '-') { 9965 isneg = 1; 9966 cur++; 9967 } 9968 9969#ifdef __GNUC__ 9970 /* 9971 * tmp/temp is a workaround against a gcc compiler bug 9972 * http://veillard.com/gcc.bug 9973 */ 9974 ret = 0; 9975 while ((*cur >= '0') && (*cur <= '9')) { 9976 ret = ret * 10; 9977 tmp = (*cur - '0'); 9978 ok = 1; 9979 cur++; 9980 temp = (double) tmp; 9981 ret = ret + temp; 9982 } 9983#else 9984 ret = 0; 9985 while ((*cur >= '0') && (*cur <= '9')) { 9986 ret = ret * 10 + (*cur - '0'); 9987 ok = 1; 9988 cur++; 9989 } 9990#endif 9991 9992 if (*cur == '.') { 9993 int v, frac = 0; 9994 double fraction = 0; 9995 9996 cur++; 9997 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 9998 return(xmlXPathNAN); 9999 } 10000 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { 10001 v = (*cur - '0'); 10002 fraction = fraction * 10 + v; 10003 frac = frac + 1; 10004 cur++; 10005 } 10006 fraction /= my_pow10[frac]; 10007 ret = ret + fraction; 10008 while ((*cur >= '0') && (*cur <= '9')) 10009 cur++; 10010 } 10011 if ((*cur == 'e') || (*cur == 'E')) { 10012 cur++; 10013 if (*cur == '-') { 10014 is_exponent_negative = 1; 10015 cur++; 10016 } else if (*cur == '+') { 10017 cur++; 10018 } 10019 while ((*cur >= '0') && (*cur <= '9')) { 10020 exponent = exponent * 10 + (*cur - '0'); 10021 cur++; 10022 } 10023 } 10024 while (IS_BLANK_CH(*cur)) cur++; 10025 if (*cur != 0) return(xmlXPathNAN); 10026 if (isneg) ret = -ret; 10027 if (is_exponent_negative) exponent = -exponent; 10028 ret *= pow(10.0, (double)exponent); 10029 return(ret); 10030} 10031 10032/** 10033 * xmlXPathCompNumber: 10034 * @ctxt: the XPath Parser context 10035 * 10036 * [30] Number ::= Digits ('.' Digits?)? 10037 * | '.' Digits 10038 * [31] Digits ::= [0-9]+ 10039 * 10040 * Compile a Number, then push it on the stack 10041 * 10042 */ 10043static void 10044xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 10045{ 10046 double ret = 0.0; 10047 double mult = 1; 10048 int ok = 0; 10049 int exponent = 0; 10050 int is_exponent_negative = 0; 10051#ifdef __GNUC__ 10052 unsigned long tmp = 0; 10053 double temp; 10054#endif 10055 10056 CHECK_ERROR; 10057 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 10058 XP_ERROR(XPATH_NUMBER_ERROR); 10059 } 10060#ifdef __GNUC__ 10061 /* 10062 * tmp/temp is a workaround against a gcc compiler bug 10063 * http://veillard.com/gcc.bug 10064 */ 10065 ret = 0; 10066 while ((CUR >= '0') && (CUR <= '9')) { 10067 ret = ret * 10; 10068 tmp = (CUR - '0'); 10069 ok = 1; 10070 NEXT; 10071 temp = (double) tmp; 10072 ret = ret + temp; 10073 } 10074#else 10075 ret = 0; 10076 while ((CUR >= '0') && (CUR <= '9')) { 10077 ret = ret * 10 + (CUR - '0'); 10078 ok = 1; 10079 NEXT; 10080 } 10081#endif 10082 if (CUR == '.') { 10083 NEXT; 10084 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 10085 XP_ERROR(XPATH_NUMBER_ERROR); 10086 } 10087 while ((CUR >= '0') && (CUR <= '9')) { 10088 mult /= 10; 10089 ret = ret + (CUR - '0') * mult; 10090 NEXT; 10091 } 10092 } 10093 if ((CUR == 'e') || (CUR == 'E')) { 10094 NEXT; 10095 if (CUR == '-') { 10096 is_exponent_negative = 1; 10097 NEXT; 10098 } else if (CUR == '+') { 10099 NEXT; 10100 } 10101 while ((CUR >= '0') && (CUR <= '9')) { 10102 exponent = exponent * 10 + (CUR - '0'); 10103 NEXT; 10104 } 10105 if (is_exponent_negative) 10106 exponent = -exponent; 10107 ret *= pow(10.0, (double) exponent); 10108 } 10109 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 10110 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 10111} 10112 10113/** 10114 * xmlXPathParseLiteral: 10115 * @ctxt: the XPath Parser context 10116 * 10117 * Parse a Literal 10118 * 10119 * [29] Literal ::= '"' [^"]* '"' 10120 * | "'" [^']* "'" 10121 * 10122 * Returns the value found or NULL in case of error 10123 */ 10124static xmlChar * 10125xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 10126 const xmlChar *q; 10127 xmlChar *ret = NULL; 10128 10129 if (CUR == '"') { 10130 NEXT; 10131 q = CUR_PTR; 10132 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10133 NEXT; 10134 if (!IS_CHAR_CH(CUR)) { 10135 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10136 } else { 10137 ret = xmlStrndup(q, CUR_PTR - q); 10138 NEXT; 10139 } 10140 } else if (CUR == '\'') { 10141 NEXT; 10142 q = CUR_PTR; 10143 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10144 NEXT; 10145 if (!IS_CHAR_CH(CUR)) { 10146 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 10147 } else { 10148 ret = xmlStrndup(q, CUR_PTR - q); 10149 NEXT; 10150 } 10151 } else { 10152 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 10153 } 10154 return(ret); 10155} 10156 10157/** 10158 * xmlXPathCompLiteral: 10159 * @ctxt: the XPath Parser context 10160 * 10161 * Parse a Literal and push it on the stack. 10162 * 10163 * [29] Literal ::= '"' [^"]* '"' 10164 * | "'" [^']* "'" 10165 * 10166 * TODO: xmlXPathCompLiteral memory allocation could be improved. 10167 */ 10168static void 10169xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 10170 const xmlChar *q; 10171 xmlChar *ret = NULL; 10172 10173 if (CUR == '"') { 10174 NEXT; 10175 q = CUR_PTR; 10176 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 10177 NEXT; 10178 if (!IS_CHAR_CH(CUR)) { 10179 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10180 } else { 10181 ret = xmlStrndup(q, CUR_PTR - q); 10182 NEXT; 10183 } 10184 } else if (CUR == '\'') { 10185 NEXT; 10186 q = CUR_PTR; 10187 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 10188 NEXT; 10189 if (!IS_CHAR_CH(CUR)) { 10190 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 10191 } else { 10192 ret = xmlStrndup(q, CUR_PTR - q); 10193 NEXT; 10194 } 10195 } else { 10196 XP_ERROR(XPATH_START_LITERAL_ERROR); 10197 } 10198 if (ret == NULL) return; 10199 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 10200 xmlXPathCacheNewString(ctxt->context, ret), NULL); 10201 xmlFree(ret); 10202} 10203 10204/** 10205 * xmlXPathCompVariableReference: 10206 * @ctxt: the XPath Parser context 10207 * 10208 * Parse a VariableReference, evaluate it and push it on the stack. 10209 * 10210 * The variable bindings consist of a mapping from variable names 10211 * to variable values. The value of a variable is an object, which can be 10212 * of any of the types that are possible for the value of an expression, 10213 * and may also be of additional types not specified here. 10214 * 10215 * Early evaluation is possible since: 10216 * The variable bindings [...] used to evaluate a subexpression are 10217 * always the same as those used to evaluate the containing expression. 10218 * 10219 * [36] VariableReference ::= '$' QName 10220 */ 10221static void 10222xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 10223 xmlChar *name; 10224 xmlChar *prefix; 10225 10226 SKIP_BLANKS; 10227 if (CUR != '$') { 10228 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10229 } 10230 NEXT; 10231 name = xmlXPathParseQName(ctxt, &prefix); 10232 if (name == NULL) { 10233 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 10234 } 10235 ctxt->comp->last = -1; 10236 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 10237 name, prefix); 10238 SKIP_BLANKS; 10239 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 10240 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR); 10241 } 10242} 10243 10244/** 10245 * xmlXPathIsNodeType: 10246 * @name: a name string 10247 * 10248 * Is the name given a NodeType one. 10249 * 10250 * [38] NodeType ::= 'comment' 10251 * | 'text' 10252 * | 'processing-instruction' 10253 * | 'node' 10254 * 10255 * Returns 1 if true 0 otherwise 10256 */ 10257int 10258xmlXPathIsNodeType(const xmlChar *name) { 10259 if (name == NULL) 10260 return(0); 10261 10262 if (xmlStrEqual(name, BAD_CAST "node")) 10263 return(1); 10264 if (xmlStrEqual(name, BAD_CAST "text")) 10265 return(1); 10266 if (xmlStrEqual(name, BAD_CAST "comment")) 10267 return(1); 10268 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10269 return(1); 10270 return(0); 10271} 10272 10273/** 10274 * xmlXPathCompFunctionCall: 10275 * @ctxt: the XPath Parser context 10276 * 10277 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 10278 * [17] Argument ::= Expr 10279 * 10280 * Compile a function call, the evaluation of all arguments are 10281 * pushed on the stack 10282 */ 10283static void 10284xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 10285 xmlChar *name; 10286 xmlChar *prefix; 10287 int nbargs = 0; 10288 int sort = 1; 10289 10290 name = xmlXPathParseQName(ctxt, &prefix); 10291 if (name == NULL) { 10292 xmlFree(prefix); 10293 XP_ERROR(XPATH_EXPR_ERROR); 10294 } 10295 SKIP_BLANKS; 10296#ifdef DEBUG_EXPR 10297 if (prefix == NULL) 10298 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 10299 name); 10300 else 10301 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 10302 prefix, name); 10303#endif 10304 10305 if (CUR != '(') { 10306 XP_ERROR(XPATH_EXPR_ERROR); 10307 } 10308 NEXT; 10309 SKIP_BLANKS; 10310 10311 /* 10312 * Optimization for count(): we don't need the node-set to be sorted. 10313 */ 10314 if ((prefix == NULL) && (name[0] == 'c') && 10315 xmlStrEqual(name, BAD_CAST "count")) 10316 { 10317 sort = 0; 10318 } 10319 ctxt->comp->last = -1; 10320 if (CUR != ')') { 10321 while (CUR != 0) { 10322 int op1 = ctxt->comp->last; 10323 ctxt->comp->last = -1; 10324 xmlXPathCompileExpr(ctxt, sort); 10325 if (ctxt->error != XPATH_EXPRESSION_OK) { 10326 xmlFree(name); 10327 xmlFree(prefix); 10328 return; 10329 } 10330 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10331 nbargs++; 10332 if (CUR == ')') break; 10333 if (CUR != ',') { 10334 XP_ERROR(XPATH_EXPR_ERROR); 10335 } 10336 NEXT; 10337 SKIP_BLANKS; 10338 } 10339 } 10340 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10341 name, prefix); 10342 NEXT; 10343 SKIP_BLANKS; 10344} 10345 10346/** 10347 * xmlXPathCompPrimaryExpr: 10348 * @ctxt: the XPath Parser context 10349 * 10350 * [15] PrimaryExpr ::= VariableReference 10351 * | '(' Expr ')' 10352 * | Literal 10353 * | Number 10354 * | FunctionCall 10355 * 10356 * Compile a primary expression. 10357 */ 10358static void 10359xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10360 SKIP_BLANKS; 10361 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10362 else if (CUR == '(') { 10363 NEXT; 10364 SKIP_BLANKS; 10365 xmlXPathCompileExpr(ctxt, 1); 10366 CHECK_ERROR; 10367 if (CUR != ')') { 10368 XP_ERROR(XPATH_EXPR_ERROR); 10369 } 10370 NEXT; 10371 SKIP_BLANKS; 10372 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10373 xmlXPathCompNumber(ctxt); 10374 } else if ((CUR == '\'') || (CUR == '"')) { 10375 xmlXPathCompLiteral(ctxt); 10376 } else { 10377 xmlXPathCompFunctionCall(ctxt); 10378 } 10379 SKIP_BLANKS; 10380} 10381 10382/** 10383 * xmlXPathCompFilterExpr: 10384 * @ctxt: the XPath Parser context 10385 * 10386 * [20] FilterExpr ::= PrimaryExpr 10387 * | FilterExpr Predicate 10388 * 10389 * Compile a filter expression. 10390 * Square brackets are used to filter expressions in the same way that 10391 * they are used in location paths. It is an error if the expression to 10392 * be filtered does not evaluate to a node-set. The context node list 10393 * used for evaluating the expression in square brackets is the node-set 10394 * to be filtered listed in document order. 10395 */ 10396 10397static void 10398xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10399 xmlXPathCompPrimaryExpr(ctxt); 10400 CHECK_ERROR; 10401 SKIP_BLANKS; 10402 10403 while (CUR == '[') { 10404 xmlXPathCompPredicate(ctxt, 1); 10405 SKIP_BLANKS; 10406 } 10407 10408 10409} 10410 10411/** 10412 * xmlXPathScanName: 10413 * @ctxt: the XPath Parser context 10414 * 10415 * Trickery: parse an XML name but without consuming the input flow 10416 * Needed to avoid insanity in the parser state. 10417 * 10418 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10419 * CombiningChar | Extender 10420 * 10421 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10422 * 10423 * [6] Names ::= Name (S Name)* 10424 * 10425 * Returns the Name parsed or NULL 10426 */ 10427 10428static xmlChar * 10429xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10430 int len = 0, l; 10431 int c; 10432 const xmlChar *cur; 10433 xmlChar *ret; 10434 10435 cur = ctxt->cur; 10436 10437 c = CUR_CHAR(l); 10438 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10439 (!IS_LETTER(c) && (c != '_') && 10440 (c != ':'))) { 10441 return(NULL); 10442 } 10443 10444 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10445 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10446 (c == '.') || (c == '-') || 10447 (c == '_') || (c == ':') || 10448 (IS_COMBINING(c)) || 10449 (IS_EXTENDER(c)))) { 10450 len += l; 10451 NEXTL(l); 10452 c = CUR_CHAR(l); 10453 } 10454 ret = xmlStrndup(cur, ctxt->cur - cur); 10455 ctxt->cur = cur; 10456 return(ret); 10457} 10458 10459/** 10460 * xmlXPathCompPathExpr: 10461 * @ctxt: the XPath Parser context 10462 * 10463 * [19] PathExpr ::= LocationPath 10464 * | FilterExpr 10465 * | FilterExpr '/' RelativeLocationPath 10466 * | FilterExpr '//' RelativeLocationPath 10467 * 10468 * Compile a path expression. 10469 * The / operator and // operators combine an arbitrary expression 10470 * and a relative location path. It is an error if the expression 10471 * does not evaluate to a node-set. 10472 * The / operator does composition in the same way as when / is 10473 * used in a location path. As in location paths, // is short for 10474 * /descendant-or-self::node()/. 10475 */ 10476 10477static void 10478xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10479 int lc = 1; /* Should we branch to LocationPath ? */ 10480 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10481 10482 SKIP_BLANKS; 10483 if ((CUR == '$') || (CUR == '(') || 10484 (IS_ASCII_DIGIT(CUR)) || 10485 (CUR == '\'') || (CUR == '"') || 10486 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10487 lc = 0; 10488 } else if (CUR == '*') { 10489 /* relative or absolute location path */ 10490 lc = 1; 10491 } else if (CUR == '/') { 10492 /* relative or absolute location path */ 10493 lc = 1; 10494 } else if (CUR == '@') { 10495 /* relative abbreviated attribute location path */ 10496 lc = 1; 10497 } else if (CUR == '.') { 10498 /* relative abbreviated attribute location path */ 10499 lc = 1; 10500 } else { 10501 /* 10502 * Problem is finding if we have a name here whether it's: 10503 * - a nodetype 10504 * - a function call in which case it's followed by '(' 10505 * - an axis in which case it's followed by ':' 10506 * - a element name 10507 * We do an a priori analysis here rather than having to 10508 * maintain parsed token content through the recursive function 10509 * calls. This looks uglier but makes the code easier to 10510 * read/write/debug. 10511 */ 10512 SKIP_BLANKS; 10513 name = xmlXPathScanName(ctxt); 10514 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10515#ifdef DEBUG_STEP 10516 xmlGenericError(xmlGenericErrorContext, 10517 "PathExpr: Axis\n"); 10518#endif 10519 lc = 1; 10520 xmlFree(name); 10521 } else if (name != NULL) { 10522 int len =xmlStrlen(name); 10523 10524 10525 while (NXT(len) != 0) { 10526 if (NXT(len) == '/') { 10527 /* element name */ 10528#ifdef DEBUG_STEP 10529 xmlGenericError(xmlGenericErrorContext, 10530 "PathExpr: AbbrRelLocation\n"); 10531#endif 10532 lc = 1; 10533 break; 10534 } else if (IS_BLANK_CH(NXT(len))) { 10535 /* ignore blanks */ 10536 ; 10537 } else if (NXT(len) == ':') { 10538#ifdef DEBUG_STEP 10539 xmlGenericError(xmlGenericErrorContext, 10540 "PathExpr: AbbrRelLocation\n"); 10541#endif 10542 lc = 1; 10543 break; 10544 } else if ((NXT(len) == '(')) { 10545 /* Note Type or Function */ 10546 if (xmlXPathIsNodeType(name)) { 10547#ifdef DEBUG_STEP 10548 xmlGenericError(xmlGenericErrorContext, 10549 "PathExpr: Type search\n"); 10550#endif 10551 lc = 1; 10552 } else { 10553#ifdef DEBUG_STEP 10554 xmlGenericError(xmlGenericErrorContext, 10555 "PathExpr: function call\n"); 10556#endif 10557 lc = 0; 10558 } 10559 break; 10560 } else if ((NXT(len) == '[')) { 10561 /* element name */ 10562#ifdef DEBUG_STEP 10563 xmlGenericError(xmlGenericErrorContext, 10564 "PathExpr: AbbrRelLocation\n"); 10565#endif 10566 lc = 1; 10567 break; 10568 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10569 (NXT(len) == '=')) { 10570 lc = 1; 10571 break; 10572 } else { 10573 lc = 1; 10574 break; 10575 } 10576 len++; 10577 } 10578 if (NXT(len) == 0) { 10579#ifdef DEBUG_STEP 10580 xmlGenericError(xmlGenericErrorContext, 10581 "PathExpr: AbbrRelLocation\n"); 10582#endif 10583 /* element name */ 10584 lc = 1; 10585 } 10586 xmlFree(name); 10587 } else { 10588 /* make sure all cases are covered explicitly */ 10589 XP_ERROR(XPATH_EXPR_ERROR); 10590 } 10591 } 10592 10593 if (lc) { 10594 if (CUR == '/') { 10595 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10596 } else { 10597 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10598 } 10599 xmlXPathCompLocationPath(ctxt); 10600 } else { 10601 xmlXPathCompFilterExpr(ctxt); 10602 CHECK_ERROR; 10603 if ((CUR == '/') && (NXT(1) == '/')) { 10604 SKIP(2); 10605 SKIP_BLANKS; 10606 10607 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10608 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10609 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 10610 10611 xmlXPathCompRelativeLocationPath(ctxt); 10612 } else if (CUR == '/') { 10613 xmlXPathCompRelativeLocationPath(ctxt); 10614 } 10615 } 10616 SKIP_BLANKS; 10617} 10618 10619/** 10620 * xmlXPathCompUnionExpr: 10621 * @ctxt: the XPath Parser context 10622 * 10623 * [18] UnionExpr ::= PathExpr 10624 * | UnionExpr '|' PathExpr 10625 * 10626 * Compile an union expression. 10627 */ 10628 10629static void 10630xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10631 xmlXPathCompPathExpr(ctxt); 10632 CHECK_ERROR; 10633 SKIP_BLANKS; 10634 while (CUR == '|') { 10635 int op1 = ctxt->comp->last; 10636 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10637 10638 NEXT; 10639 SKIP_BLANKS; 10640 xmlXPathCompPathExpr(ctxt); 10641 10642 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10643 10644 SKIP_BLANKS; 10645 } 10646} 10647 10648/** 10649 * xmlXPathCompUnaryExpr: 10650 * @ctxt: the XPath Parser context 10651 * 10652 * [27] UnaryExpr ::= UnionExpr 10653 * | '-' UnaryExpr 10654 * 10655 * Compile an unary expression. 10656 */ 10657 10658static void 10659xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10660 int minus = 0; 10661 int found = 0; 10662 10663 SKIP_BLANKS; 10664 while (CUR == '-') { 10665 minus = 1 - minus; 10666 found = 1; 10667 NEXT; 10668 SKIP_BLANKS; 10669 } 10670 10671 xmlXPathCompUnionExpr(ctxt); 10672 CHECK_ERROR; 10673 if (found) { 10674 if (minus) 10675 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10676 else 10677 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10678 } 10679} 10680 10681/** 10682 * xmlXPathCompMultiplicativeExpr: 10683 * @ctxt: the XPath Parser context 10684 * 10685 * [26] MultiplicativeExpr ::= UnaryExpr 10686 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10687 * | MultiplicativeExpr 'div' UnaryExpr 10688 * | MultiplicativeExpr 'mod' UnaryExpr 10689 * [34] MultiplyOperator ::= '*' 10690 * 10691 * Compile an Additive expression. 10692 */ 10693 10694static void 10695xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10696 xmlXPathCompUnaryExpr(ctxt); 10697 CHECK_ERROR; 10698 SKIP_BLANKS; 10699 while ((CUR == '*') || 10700 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10701 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10702 int op = -1; 10703 int op1 = ctxt->comp->last; 10704 10705 if (CUR == '*') { 10706 op = 0; 10707 NEXT; 10708 } else if (CUR == 'd') { 10709 op = 1; 10710 SKIP(3); 10711 } else if (CUR == 'm') { 10712 op = 2; 10713 SKIP(3); 10714 } 10715 SKIP_BLANKS; 10716 xmlXPathCompUnaryExpr(ctxt); 10717 CHECK_ERROR; 10718 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10719 SKIP_BLANKS; 10720 } 10721} 10722 10723/** 10724 * xmlXPathCompAdditiveExpr: 10725 * @ctxt: the XPath Parser context 10726 * 10727 * [25] AdditiveExpr ::= MultiplicativeExpr 10728 * | AdditiveExpr '+' MultiplicativeExpr 10729 * | AdditiveExpr '-' MultiplicativeExpr 10730 * 10731 * Compile an Additive expression. 10732 */ 10733 10734static void 10735xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10736 10737 xmlXPathCompMultiplicativeExpr(ctxt); 10738 CHECK_ERROR; 10739 SKIP_BLANKS; 10740 while ((CUR == '+') || (CUR == '-')) { 10741 int plus; 10742 int op1 = ctxt->comp->last; 10743 10744 if (CUR == '+') plus = 1; 10745 else plus = 0; 10746 NEXT; 10747 SKIP_BLANKS; 10748 xmlXPathCompMultiplicativeExpr(ctxt); 10749 CHECK_ERROR; 10750 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10751 SKIP_BLANKS; 10752 } 10753} 10754 10755/** 10756 * xmlXPathCompRelationalExpr: 10757 * @ctxt: the XPath Parser context 10758 * 10759 * [24] RelationalExpr ::= AdditiveExpr 10760 * | RelationalExpr '<' AdditiveExpr 10761 * | RelationalExpr '>' AdditiveExpr 10762 * | RelationalExpr '<=' AdditiveExpr 10763 * | RelationalExpr '>=' AdditiveExpr 10764 * 10765 * A <= B > C is allowed ? Answer from James, yes with 10766 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10767 * which is basically what got implemented. 10768 * 10769 * Compile a Relational expression, then push the result 10770 * on the stack 10771 */ 10772 10773static void 10774xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10775 xmlXPathCompAdditiveExpr(ctxt); 10776 CHECK_ERROR; 10777 SKIP_BLANKS; 10778 while ((CUR == '<') || 10779 (CUR == '>') || 10780 ((CUR == '<') && (NXT(1) == '=')) || 10781 ((CUR == '>') && (NXT(1) == '='))) { 10782 int inf, strict; 10783 int op1 = ctxt->comp->last; 10784 10785 if (CUR == '<') inf = 1; 10786 else inf = 0; 10787 if (NXT(1) == '=') strict = 0; 10788 else strict = 1; 10789 NEXT; 10790 if (!strict) NEXT; 10791 SKIP_BLANKS; 10792 xmlXPathCompAdditiveExpr(ctxt); 10793 CHECK_ERROR; 10794 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10795 SKIP_BLANKS; 10796 } 10797} 10798 10799/** 10800 * xmlXPathCompEqualityExpr: 10801 * @ctxt: the XPath Parser context 10802 * 10803 * [23] EqualityExpr ::= RelationalExpr 10804 * | EqualityExpr '=' RelationalExpr 10805 * | EqualityExpr '!=' RelationalExpr 10806 * 10807 * A != B != C is allowed ? Answer from James, yes with 10808 * (RelationalExpr = RelationalExpr) = RelationalExpr 10809 * (RelationalExpr != RelationalExpr) != RelationalExpr 10810 * which is basically what got implemented. 10811 * 10812 * Compile an Equality expression. 10813 * 10814 */ 10815static void 10816xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10817 xmlXPathCompRelationalExpr(ctxt); 10818 CHECK_ERROR; 10819 SKIP_BLANKS; 10820 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10821 int eq; 10822 int op1 = ctxt->comp->last; 10823 10824 if (CUR == '=') eq = 1; 10825 else eq = 0; 10826 NEXT; 10827 if (!eq) NEXT; 10828 SKIP_BLANKS; 10829 xmlXPathCompRelationalExpr(ctxt); 10830 CHECK_ERROR; 10831 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10832 SKIP_BLANKS; 10833 } 10834} 10835 10836/** 10837 * xmlXPathCompAndExpr: 10838 * @ctxt: the XPath Parser context 10839 * 10840 * [22] AndExpr ::= EqualityExpr 10841 * | AndExpr 'and' EqualityExpr 10842 * 10843 * Compile an AND expression. 10844 * 10845 */ 10846static void 10847xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10848 xmlXPathCompEqualityExpr(ctxt); 10849 CHECK_ERROR; 10850 SKIP_BLANKS; 10851 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10852 int op1 = ctxt->comp->last; 10853 SKIP(3); 10854 SKIP_BLANKS; 10855 xmlXPathCompEqualityExpr(ctxt); 10856 CHECK_ERROR; 10857 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 10858 SKIP_BLANKS; 10859 } 10860} 10861 10862/** 10863 * xmlXPathCompileExpr: 10864 * @ctxt: the XPath Parser context 10865 * 10866 * [14] Expr ::= OrExpr 10867 * [21] OrExpr ::= AndExpr 10868 * | OrExpr 'or' AndExpr 10869 * 10870 * Parse and compile an expression 10871 */ 10872static void 10873xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 10874 xmlXPathCompAndExpr(ctxt); 10875 CHECK_ERROR; 10876 SKIP_BLANKS; 10877 while ((CUR == 'o') && (NXT(1) == 'r')) { 10878 int op1 = ctxt->comp->last; 10879 SKIP(2); 10880 SKIP_BLANKS; 10881 xmlXPathCompAndExpr(ctxt); 10882 CHECK_ERROR; 10883 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 10884 SKIP_BLANKS; 10885 } 10886 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 10887 /* more ops could be optimized too */ 10888 /* 10889 * This is the main place to eliminate sorting for 10890 * operations which don't require a sorted node-set. 10891 * E.g. count(). 10892 */ 10893 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 10894 } 10895} 10896 10897/** 10898 * xmlXPathCompPredicate: 10899 * @ctxt: the XPath Parser context 10900 * @filter: act as a filter 10901 * 10902 * [8] Predicate ::= '[' PredicateExpr ']' 10903 * [9] PredicateExpr ::= Expr 10904 * 10905 * Compile a predicate expression 10906 */ 10907static void 10908xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 10909 int op1 = ctxt->comp->last; 10910 10911 SKIP_BLANKS; 10912 if (CUR != '[') { 10913 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10914 } 10915 NEXT; 10916 SKIP_BLANKS; 10917 10918 ctxt->comp->last = -1; 10919 /* 10920 * This call to xmlXPathCompileExpr() will deactivate sorting 10921 * of the predicate result. 10922 * TODO: Sorting is still activated for filters, since I'm not 10923 * sure if needed. Normally sorting should not be needed, since 10924 * a filter can only diminish the number of items in a sequence, 10925 * but won't change its order; so if the initial sequence is sorted, 10926 * subsequent sorting is not needed. 10927 */ 10928 if (! filter) 10929 xmlXPathCompileExpr(ctxt, 0); 10930 else 10931 xmlXPathCompileExpr(ctxt, 1); 10932 CHECK_ERROR; 10933 10934 if (CUR != ']') { 10935 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10936 } 10937 10938 if (filter) 10939 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 10940 else 10941 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 10942 10943 NEXT; 10944 SKIP_BLANKS; 10945} 10946 10947/** 10948 * xmlXPathCompNodeTest: 10949 * @ctxt: the XPath Parser context 10950 * @test: pointer to a xmlXPathTestVal 10951 * @type: pointer to a xmlXPathTypeVal 10952 * @prefix: placeholder for a possible name prefix 10953 * 10954 * [7] NodeTest ::= NameTest 10955 * | NodeType '(' ')' 10956 * | 'processing-instruction' '(' Literal ')' 10957 * 10958 * [37] NameTest ::= '*' 10959 * | NCName ':' '*' 10960 * | QName 10961 * [38] NodeType ::= 'comment' 10962 * | 'text' 10963 * | 'processing-instruction' 10964 * | 'node' 10965 * 10966 * Returns the name found and updates @test, @type and @prefix appropriately 10967 */ 10968static xmlChar * 10969xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 10970 xmlXPathTypeVal *type, const xmlChar **prefix, 10971 xmlChar *name) { 10972 int blanks; 10973 10974 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 10975 STRANGE; 10976 return(NULL); 10977 } 10978 *type = (xmlXPathTypeVal) 0; 10979 *test = (xmlXPathTestVal) 0; 10980 *prefix = NULL; 10981 SKIP_BLANKS; 10982 10983 if ((name == NULL) && (CUR == '*')) { 10984 /* 10985 * All elements 10986 */ 10987 NEXT; 10988 *test = NODE_TEST_ALL; 10989 return(NULL); 10990 } 10991 10992 if (name == NULL) 10993 name = xmlXPathParseNCName(ctxt); 10994 if (name == NULL) { 10995 XP_ERRORNULL(XPATH_EXPR_ERROR); 10996 } 10997 10998 blanks = IS_BLANK_CH(CUR); 10999 SKIP_BLANKS; 11000 if (CUR == '(') { 11001 NEXT; 11002 /* 11003 * NodeType or PI search 11004 */ 11005 if (xmlStrEqual(name, BAD_CAST "comment")) 11006 *type = NODE_TYPE_COMMENT; 11007 else if (xmlStrEqual(name, BAD_CAST "node")) 11008 *type = NODE_TYPE_NODE; 11009 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 11010 *type = NODE_TYPE_PI; 11011 else if (xmlStrEqual(name, BAD_CAST "text")) 11012 *type = NODE_TYPE_TEXT; 11013 else { 11014 if (name != NULL) 11015 xmlFree(name); 11016 XP_ERRORNULL(XPATH_EXPR_ERROR); 11017 } 11018 11019 *test = NODE_TEST_TYPE; 11020 11021 SKIP_BLANKS; 11022 if (*type == NODE_TYPE_PI) { 11023 /* 11024 * Specific case: search a PI by name. 11025 */ 11026 if (name != NULL) 11027 xmlFree(name); 11028 name = NULL; 11029 if (CUR != ')') { 11030 name = xmlXPathParseLiteral(ctxt); 11031 CHECK_ERROR NULL; 11032 *test = NODE_TEST_PI; 11033 SKIP_BLANKS; 11034 } 11035 } 11036 if (CUR != ')') { 11037 if (name != NULL) 11038 xmlFree(name); 11039 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 11040 } 11041 NEXT; 11042 return(name); 11043 } 11044 *test = NODE_TEST_NAME; 11045 if ((!blanks) && (CUR == ':')) { 11046 NEXT; 11047 11048 /* 11049 * Since currently the parser context don't have a 11050 * namespace list associated: 11051 * The namespace name for this prefix can be computed 11052 * only at evaluation time. The compilation is done 11053 * outside of any context. 11054 */ 11055#if 0 11056 *prefix = xmlXPathNsLookup(ctxt->context, name); 11057 if (name != NULL) 11058 xmlFree(name); 11059 if (*prefix == NULL) { 11060 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11061 } 11062#else 11063 *prefix = name; 11064#endif 11065 11066 if (CUR == '*') { 11067 /* 11068 * All elements 11069 */ 11070 NEXT; 11071 *test = NODE_TEST_ALL; 11072 return(NULL); 11073 } 11074 11075 name = xmlXPathParseNCName(ctxt); 11076 if (name == NULL) { 11077 XP_ERRORNULL(XPATH_EXPR_ERROR); 11078 } 11079 } 11080 return(name); 11081} 11082 11083/** 11084 * xmlXPathIsAxisName: 11085 * @name: a preparsed name token 11086 * 11087 * [6] AxisName ::= 'ancestor' 11088 * | 'ancestor-or-self' 11089 * | 'attribute' 11090 * | 'child' 11091 * | 'descendant' 11092 * | 'descendant-or-self' 11093 * | 'following' 11094 * | 'following-sibling' 11095 * | 'namespace' 11096 * | 'parent' 11097 * | 'preceding' 11098 * | 'preceding-sibling' 11099 * | 'self' 11100 * 11101 * Returns the axis or 0 11102 */ 11103static xmlXPathAxisVal 11104xmlXPathIsAxisName(const xmlChar *name) { 11105 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 11106 switch (name[0]) { 11107 case 'a': 11108 if (xmlStrEqual(name, BAD_CAST "ancestor")) 11109 ret = AXIS_ANCESTOR; 11110 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 11111 ret = AXIS_ANCESTOR_OR_SELF; 11112 if (xmlStrEqual(name, BAD_CAST "attribute")) 11113 ret = AXIS_ATTRIBUTE; 11114 break; 11115 case 'c': 11116 if (xmlStrEqual(name, BAD_CAST "child")) 11117 ret = AXIS_CHILD; 11118 break; 11119 case 'd': 11120 if (xmlStrEqual(name, BAD_CAST "descendant")) 11121 ret = AXIS_DESCENDANT; 11122 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 11123 ret = AXIS_DESCENDANT_OR_SELF; 11124 break; 11125 case 'f': 11126 if (xmlStrEqual(name, BAD_CAST "following")) 11127 ret = AXIS_FOLLOWING; 11128 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 11129 ret = AXIS_FOLLOWING_SIBLING; 11130 break; 11131 case 'n': 11132 if (xmlStrEqual(name, BAD_CAST "namespace")) 11133 ret = AXIS_NAMESPACE; 11134 break; 11135 case 'p': 11136 if (xmlStrEqual(name, BAD_CAST "parent")) 11137 ret = AXIS_PARENT; 11138 if (xmlStrEqual(name, BAD_CAST "preceding")) 11139 ret = AXIS_PRECEDING; 11140 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 11141 ret = AXIS_PRECEDING_SIBLING; 11142 break; 11143 case 's': 11144 if (xmlStrEqual(name, BAD_CAST "self")) 11145 ret = AXIS_SELF; 11146 break; 11147 } 11148 return(ret); 11149} 11150 11151/** 11152 * xmlXPathCompStep: 11153 * @ctxt: the XPath Parser context 11154 * 11155 * [4] Step ::= AxisSpecifier NodeTest Predicate* 11156 * | AbbreviatedStep 11157 * 11158 * [12] AbbreviatedStep ::= '.' | '..' 11159 * 11160 * [5] AxisSpecifier ::= AxisName '::' 11161 * | AbbreviatedAxisSpecifier 11162 * 11163 * [13] AbbreviatedAxisSpecifier ::= '@'? 11164 * 11165 * Modified for XPtr range support as: 11166 * 11167 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 11168 * | AbbreviatedStep 11169 * | 'range-to' '(' Expr ')' Predicate* 11170 * 11171 * Compile one step in a Location Path 11172 * A location step of . is short for self::node(). This is 11173 * particularly useful in conjunction with //. For example, the 11174 * location path .//para is short for 11175 * self::node()/descendant-or-self::node()/child::para 11176 * and so will select all para descendant elements of the context 11177 * node. 11178 * Similarly, a location step of .. is short for parent::node(). 11179 * For example, ../title is short for parent::node()/child::title 11180 * and so will select the title children of the parent of the context 11181 * node. 11182 */ 11183static void 11184xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 11185#ifdef LIBXML_XPTR_ENABLED 11186 int rangeto = 0; 11187 int op2 = -1; 11188#endif 11189 11190 SKIP_BLANKS; 11191 if ((CUR == '.') && (NXT(1) == '.')) { 11192 SKIP(2); 11193 SKIP_BLANKS; 11194 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 11195 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11196 } else if (CUR == '.') { 11197 NEXT; 11198 SKIP_BLANKS; 11199 } else { 11200 xmlChar *name = NULL; 11201 const xmlChar *prefix = NULL; 11202 xmlXPathTestVal test = (xmlXPathTestVal) 0; 11203 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 11204 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 11205 int op1; 11206 11207 /* 11208 * The modification needed for XPointer change to the production 11209 */ 11210#ifdef LIBXML_XPTR_ENABLED 11211 if (ctxt->xptr) { 11212 name = xmlXPathParseNCName(ctxt); 11213 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 11214 op2 = ctxt->comp->last; 11215 xmlFree(name); 11216 SKIP_BLANKS; 11217 if (CUR != '(') { 11218 XP_ERROR(XPATH_EXPR_ERROR); 11219 } 11220 NEXT; 11221 SKIP_BLANKS; 11222 11223 xmlXPathCompileExpr(ctxt, 1); 11224 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 11225 CHECK_ERROR; 11226 11227 SKIP_BLANKS; 11228 if (CUR != ')') { 11229 XP_ERROR(XPATH_EXPR_ERROR); 11230 } 11231 NEXT; 11232 rangeto = 1; 11233 goto eval_predicates; 11234 } 11235 } 11236#endif 11237 if (CUR == '*') { 11238 axis = AXIS_CHILD; 11239 } else { 11240 if (name == NULL) 11241 name = xmlXPathParseNCName(ctxt); 11242 if (name != NULL) { 11243 axis = xmlXPathIsAxisName(name); 11244 if (axis != 0) { 11245 SKIP_BLANKS; 11246 if ((CUR == ':') && (NXT(1) == ':')) { 11247 SKIP(2); 11248 xmlFree(name); 11249 name = NULL; 11250 } else { 11251 /* an element name can conflict with an axis one :-\ */ 11252 axis = AXIS_CHILD; 11253 } 11254 } else { 11255 axis = AXIS_CHILD; 11256 } 11257 } else if (CUR == '@') { 11258 NEXT; 11259 axis = AXIS_ATTRIBUTE; 11260 } else { 11261 axis = AXIS_CHILD; 11262 } 11263 } 11264 11265 CHECK_ERROR; 11266 11267 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 11268 if (test == 0) 11269 return; 11270 11271 if ((prefix != NULL) && (ctxt->context != NULL) && 11272 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 11273 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 11274 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 11275 } 11276 } 11277#ifdef DEBUG_STEP 11278 xmlGenericError(xmlGenericErrorContext, 11279 "Basis : computing new set\n"); 11280#endif 11281 11282#ifdef DEBUG_STEP 11283 xmlGenericError(xmlGenericErrorContext, "Basis : "); 11284 if (ctxt->value == NULL) 11285 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11286 else if (ctxt->value->nodesetval == NULL) 11287 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11288 else 11289 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 11290#endif 11291 11292#ifdef LIBXML_XPTR_ENABLED 11293eval_predicates: 11294#endif 11295 op1 = ctxt->comp->last; 11296 ctxt->comp->last = -1; 11297 11298 SKIP_BLANKS; 11299 while (CUR == '[') { 11300 xmlXPathCompPredicate(ctxt, 0); 11301 } 11302 11303#ifdef LIBXML_XPTR_ENABLED 11304 if (rangeto) { 11305 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 11306 } else 11307#endif 11308 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 11309 test, type, (void *)prefix, (void *)name); 11310 11311 } 11312#ifdef DEBUG_STEP 11313 xmlGenericError(xmlGenericErrorContext, "Step : "); 11314 if (ctxt->value == NULL) 11315 xmlGenericError(xmlGenericErrorContext, "no value\n"); 11316 else if (ctxt->value->nodesetval == NULL) 11317 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 11318 else 11319 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 11320 ctxt->value->nodesetval); 11321#endif 11322} 11323 11324/** 11325 * xmlXPathCompRelativeLocationPath: 11326 * @ctxt: the XPath Parser context 11327 * 11328 * [3] RelativeLocationPath ::= Step 11329 * | RelativeLocationPath '/' Step 11330 * | AbbreviatedRelativeLocationPath 11331 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11332 * 11333 * Compile a relative location path. 11334 */ 11335static void 11336xmlXPathCompRelativeLocationPath 11337(xmlXPathParserContextPtr ctxt) { 11338 SKIP_BLANKS; 11339 if ((CUR == '/') && (NXT(1) == '/')) { 11340 SKIP(2); 11341 SKIP_BLANKS; 11342 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11343 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11344 } else if (CUR == '/') { 11345 NEXT; 11346 SKIP_BLANKS; 11347 } 11348 xmlXPathCompStep(ctxt); 11349 CHECK_ERROR; 11350 SKIP_BLANKS; 11351 while (CUR == '/') { 11352 if ((CUR == '/') && (NXT(1) == '/')) { 11353 SKIP(2); 11354 SKIP_BLANKS; 11355 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11356 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11357 xmlXPathCompStep(ctxt); 11358 } else if (CUR == '/') { 11359 NEXT; 11360 SKIP_BLANKS; 11361 xmlXPathCompStep(ctxt); 11362 } 11363 SKIP_BLANKS; 11364 } 11365} 11366 11367/** 11368 * xmlXPathCompLocationPath: 11369 * @ctxt: the XPath Parser context 11370 * 11371 * [1] LocationPath ::= RelativeLocationPath 11372 * | AbsoluteLocationPath 11373 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11374 * | AbbreviatedAbsoluteLocationPath 11375 * [10] AbbreviatedAbsoluteLocationPath ::= 11376 * '//' RelativeLocationPath 11377 * 11378 * Compile a location path 11379 * 11380 * // is short for /descendant-or-self::node()/. For example, 11381 * //para is short for /descendant-or-self::node()/child::para and 11382 * so will select any para element in the document (even a para element 11383 * that is a document element will be selected by //para since the 11384 * document element node is a child of the root node); div//para is 11385 * short for div/descendant-or-self::node()/child::para and so will 11386 * select all para descendants of div children. 11387 */ 11388static void 11389xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11390 SKIP_BLANKS; 11391 if (CUR != '/') { 11392 xmlXPathCompRelativeLocationPath(ctxt); 11393 } else { 11394 while (CUR == '/') { 11395 if ((CUR == '/') && (NXT(1) == '/')) { 11396 SKIP(2); 11397 SKIP_BLANKS; 11398 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11399 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11400 xmlXPathCompRelativeLocationPath(ctxt); 11401 } else if (CUR == '/') { 11402 NEXT; 11403 SKIP_BLANKS; 11404 if ((CUR != 0 ) && 11405 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11406 (CUR == '@') || (CUR == '*'))) 11407 xmlXPathCompRelativeLocationPath(ctxt); 11408 } 11409 CHECK_ERROR; 11410 } 11411 } 11412} 11413 11414/************************************************************************ 11415 * * 11416 * XPath precompiled expression evaluation * 11417 * * 11418 ************************************************************************/ 11419 11420static int 11421xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11422 11423#ifdef DEBUG_STEP 11424static void 11425xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, 11426 int nbNodes) 11427{ 11428 xmlGenericError(xmlGenericErrorContext, "new step : "); 11429 switch (op->value) { 11430 case AXIS_ANCESTOR: 11431 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11432 break; 11433 case AXIS_ANCESTOR_OR_SELF: 11434 xmlGenericError(xmlGenericErrorContext, 11435 "axis 'ancestors-or-self' "); 11436 break; 11437 case AXIS_ATTRIBUTE: 11438 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11439 break; 11440 case AXIS_CHILD: 11441 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11442 break; 11443 case AXIS_DESCENDANT: 11444 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11445 break; 11446 case AXIS_DESCENDANT_OR_SELF: 11447 xmlGenericError(xmlGenericErrorContext, 11448 "axis 'descendant-or-self' "); 11449 break; 11450 case AXIS_FOLLOWING: 11451 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11452 break; 11453 case AXIS_FOLLOWING_SIBLING: 11454 xmlGenericError(xmlGenericErrorContext, 11455 "axis 'following-siblings' "); 11456 break; 11457 case AXIS_NAMESPACE: 11458 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11459 break; 11460 case AXIS_PARENT: 11461 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11462 break; 11463 case AXIS_PRECEDING: 11464 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11465 break; 11466 case AXIS_PRECEDING_SIBLING: 11467 xmlGenericError(xmlGenericErrorContext, 11468 "axis 'preceding-sibling' "); 11469 break; 11470 case AXIS_SELF: 11471 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11472 break; 11473 } 11474 xmlGenericError(xmlGenericErrorContext, 11475 " context contains %d nodes\n", nbNodes); 11476 switch (op->value2) { 11477 case NODE_TEST_NONE: 11478 xmlGenericError(xmlGenericErrorContext, 11479 " searching for none !!!\n"); 11480 break; 11481 case NODE_TEST_TYPE: 11482 xmlGenericError(xmlGenericErrorContext, 11483 " searching for type %d\n", op->value3); 11484 break; 11485 case NODE_TEST_PI: 11486 xmlGenericError(xmlGenericErrorContext, 11487 " searching for PI !!!\n"); 11488 break; 11489 case NODE_TEST_ALL: 11490 xmlGenericError(xmlGenericErrorContext, 11491 " searching for *\n"); 11492 break; 11493 case NODE_TEST_NS: 11494 xmlGenericError(xmlGenericErrorContext, 11495 " searching for namespace %s\n", 11496 op->value5); 11497 break; 11498 case NODE_TEST_NAME: 11499 xmlGenericError(xmlGenericErrorContext, 11500 " searching for name %s\n", op->value5); 11501 if (op->value4) 11502 xmlGenericError(xmlGenericErrorContext, 11503 " with namespace %s\n", op->value4); 11504 break; 11505 } 11506 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11507} 11508#endif /* DEBUG_STEP */ 11509 11510static int 11511xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, 11512 xmlXPathStepOpPtr op, 11513 xmlNodeSetPtr set, 11514 int contextSize, 11515 int hasNsNodes) 11516{ 11517 if (op->ch1 != -1) { 11518 xmlXPathCompExprPtr comp = ctxt->comp; 11519 /* 11520 * Process inner predicates first. 11521 */ 11522 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11523 /* 11524 * TODO: raise an internal error. 11525 */ 11526 } 11527 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11528 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11529 CHECK_ERROR0; 11530 if (contextSize <= 0) 11531 return(0); 11532 } 11533 if (op->ch2 != -1) { 11534 xmlXPathContextPtr xpctxt = ctxt->context; 11535 xmlNodePtr contextNode, oldContextNode; 11536 xmlDocPtr oldContextDoc; 11537 int i, res, contextPos = 0, newContextSize; 11538 xmlXPathStepOpPtr exprOp; 11539 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11540 11541#ifdef LIBXML_XPTR_ENABLED 11542 /* 11543 * URGENT TODO: Check the following: 11544 * We don't expect location sets if evaluating prediates, right? 11545 * Only filters should expect location sets, right? 11546 */ 11547#endif 11548 /* 11549 * SPEC XPath 1.0: 11550 * "For each node in the node-set to be filtered, the 11551 * PredicateExpr is evaluated with that node as the 11552 * context node, with the number of nodes in the 11553 * node-set as the context size, and with the proximity 11554 * position of the node in the node-set with respect to 11555 * the axis as the context position;" 11556 * @oldset is the node-set" to be filtered. 11557 * 11558 * SPEC XPath 1.0: 11559 * "only predicates change the context position and 11560 * context size (see [2.4 Predicates])." 11561 * Example: 11562 * node-set context pos 11563 * nA 1 11564 * nB 2 11565 * nC 3 11566 * After applying predicate [position() > 1] : 11567 * node-set context pos 11568 * nB 1 11569 * nC 2 11570 */ 11571 oldContextNode = xpctxt->node; 11572 oldContextDoc = xpctxt->doc; 11573 /* 11574 * Get the expression of this predicate. 11575 */ 11576 exprOp = &ctxt->comp->steps[op->ch2]; 11577 newContextSize = 0; 11578 for (i = 0; i < set->nodeNr; i++) { 11579 if (set->nodeTab[i] == NULL) 11580 continue; 11581 11582 contextNode = set->nodeTab[i]; 11583 xpctxt->node = contextNode; 11584 xpctxt->contextSize = contextSize; 11585 xpctxt->proximityPosition = ++contextPos; 11586 11587 /* 11588 * Also set the xpath document in case things like 11589 * key() are evaluated in the predicate. 11590 */ 11591 if ((contextNode->type != XML_NAMESPACE_DECL) && 11592 (contextNode->doc != NULL)) 11593 xpctxt->doc = contextNode->doc; 11594 /* 11595 * Evaluate the predicate expression with 1 context node 11596 * at a time; this node is packaged into a node set; this 11597 * node set is handed over to the evaluation mechanism. 11598 */ 11599 if (contextObj == NULL) 11600 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11601 else 11602 xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11603 contextNode); 11604 11605 valuePush(ctxt, contextObj); 11606 11607 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11608 11609 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11610 xmlXPathNodeSetClear(set, hasNsNodes); 11611 newContextSize = 0; 11612 goto evaluation_exit; 11613 } 11614 11615 if (res != 0) { 11616 newContextSize++; 11617 } else { 11618 /* 11619 * Remove the entry from the initial node set. 11620 */ 11621 set->nodeTab[i] = NULL; 11622 if (contextNode->type == XML_NAMESPACE_DECL) 11623 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11624 } 11625 if (ctxt->value == contextObj) { 11626 /* 11627 * Don't free the temporary XPath object holding the 11628 * context node, in order to avoid massive recreation 11629 * inside this loop. 11630 */ 11631 valuePop(ctxt); 11632 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11633 } else { 11634 /* 11635 * TODO: The object was lost in the evaluation machinery. 11636 * Can this happen? Maybe in internal-error cases. 11637 */ 11638 contextObj = NULL; 11639 } 11640 } 11641 11642 if (contextObj != NULL) { 11643 if (ctxt->value == contextObj) 11644 valuePop(ctxt); 11645 xmlXPathReleaseObject(xpctxt, contextObj); 11646 } 11647evaluation_exit: 11648 if (exprRes != NULL) 11649 xmlXPathReleaseObject(ctxt->context, exprRes); 11650 /* 11651 * Reset/invalidate the context. 11652 */ 11653 xpctxt->node = oldContextNode; 11654 xpctxt->doc = oldContextDoc; 11655 xpctxt->contextSize = -1; 11656 xpctxt->proximityPosition = -1; 11657 return(newContextSize); 11658 } 11659 return(contextSize); 11660} 11661 11662static int 11663xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, 11664 xmlXPathStepOpPtr op, 11665 xmlNodeSetPtr set, 11666 int contextSize, 11667 int minPos, 11668 int maxPos, 11669 int hasNsNodes) 11670{ 11671 if (op->ch1 != -1) { 11672 xmlXPathCompExprPtr comp = ctxt->comp; 11673 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { 11674 /* 11675 * TODO: raise an internal error. 11676 */ 11677 } 11678 contextSize = xmlXPathCompOpEvalPredicate(ctxt, 11679 &comp->steps[op->ch1], set, contextSize, hasNsNodes); 11680 CHECK_ERROR0; 11681 if (contextSize <= 0) 11682 return(0); 11683 } 11684 /* 11685 * Check if the node set contains a sufficient number of nodes for 11686 * the requested range. 11687 */ 11688 if (contextSize < minPos) { 11689 xmlXPathNodeSetClear(set, hasNsNodes); 11690 return(0); 11691 } 11692 if (op->ch2 == -1) { 11693 /* 11694 * TODO: Can this ever happen? 11695 */ 11696 return (contextSize); 11697 } else { 11698 xmlDocPtr oldContextDoc; 11699 int i, pos = 0, newContextSize = 0, contextPos = 0, res; 11700 xmlXPathStepOpPtr exprOp; 11701 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; 11702 xmlNodePtr oldContextNode, contextNode = NULL; 11703 xmlXPathContextPtr xpctxt = ctxt->context; 11704 11705#ifdef LIBXML_XPTR_ENABLED 11706 /* 11707 * URGENT TODO: Check the following: 11708 * We don't expect location sets if evaluating prediates, right? 11709 * Only filters should expect location sets, right? 11710 */ 11711#endif /* LIBXML_XPTR_ENABLED */ 11712 11713 /* 11714 * Save old context. 11715 */ 11716 oldContextNode = xpctxt->node; 11717 oldContextDoc = xpctxt->doc; 11718 /* 11719 * Get the expression of this predicate. 11720 */ 11721 exprOp = &ctxt->comp->steps[op->ch2]; 11722 for (i = 0; i < set->nodeNr; i++) { 11723 if (set->nodeTab[i] == NULL) 11724 continue; 11725 11726 contextNode = set->nodeTab[i]; 11727 xpctxt->node = contextNode; 11728 xpctxt->contextSize = contextSize; 11729 xpctxt->proximityPosition = ++contextPos; 11730 11731 /* 11732 * Initialize the new set. 11733 * Also set the xpath document in case things like 11734 * key() evaluation are attempted on the predicate 11735 */ 11736 if ((contextNode->type != XML_NAMESPACE_DECL) && 11737 (contextNode->doc != NULL)) 11738 xpctxt->doc = contextNode->doc; 11739 /* 11740 * Evaluate the predicate expression with 1 context node 11741 * at a time; this node is packaged into a node set; this 11742 * node set is handed over to the evaluation mechanism. 11743 */ 11744 if (contextObj == NULL) 11745 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); 11746 else 11747 xmlXPathNodeSetAddUnique(contextObj->nodesetval, 11748 contextNode); 11749 11750 valuePush(ctxt, contextObj); 11751 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); 11752 11753 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { 11754 xmlXPathObjectPtr tmp; 11755 /* pop the result if any */ 11756 tmp = valuePop(ctxt); 11757 while (tmp != contextObj) { 11758 /* 11759 * Free up the result 11760 * then pop off contextObj, which will be freed later 11761 */ 11762 xmlXPathReleaseObject(xpctxt, tmp); 11763 tmp = valuePop(ctxt); 11764 } 11765 goto evaluation_error; 11766 } 11767 11768 if (res) 11769 pos++; 11770 11771 if (res && (pos >= minPos) && (pos <= maxPos)) { 11772 /* 11773 * Fits in the requested range. 11774 */ 11775 newContextSize++; 11776 if (minPos == maxPos) { 11777 /* 11778 * Only 1 node was requested. 11779 */ 11780 if (contextNode->type == XML_NAMESPACE_DECL) { 11781 /* 11782 * As always: take care of those nasty 11783 * namespace nodes. 11784 */ 11785 set->nodeTab[i] = NULL; 11786 } 11787 xmlXPathNodeSetClear(set, hasNsNodes); 11788 set->nodeNr = 1; 11789 set->nodeTab[0] = contextNode; 11790 goto evaluation_exit; 11791 } 11792 if (pos == maxPos) { 11793 /* 11794 * We are done. 11795 */ 11796 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes); 11797 goto evaluation_exit; 11798 } 11799 } else { 11800 /* 11801 * Remove the entry from the initial node set. 11802 */ 11803 set->nodeTab[i] = NULL; 11804 if (contextNode->type == XML_NAMESPACE_DECL) 11805 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); 11806 } 11807 if (exprRes != NULL) { 11808 xmlXPathReleaseObject(ctxt->context, exprRes); 11809 exprRes = NULL; 11810 } 11811 if (ctxt->value == contextObj) { 11812 /* 11813 * Don't free the temporary XPath object holding the 11814 * context node, in order to avoid massive recreation 11815 * inside this loop. 11816 */ 11817 valuePop(ctxt); 11818 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); 11819 } else { 11820 /* 11821 * The object was lost in the evaluation machinery. 11822 * Can this happen? Maybe in case of internal-errors. 11823 */ 11824 contextObj = NULL; 11825 } 11826 } 11827 goto evaluation_exit; 11828 11829evaluation_error: 11830 xmlXPathNodeSetClear(set, hasNsNodes); 11831 newContextSize = 0; 11832 11833evaluation_exit: 11834 if (contextObj != NULL) { 11835 if (ctxt->value == contextObj) 11836 valuePop(ctxt); 11837 xmlXPathReleaseObject(xpctxt, contextObj); 11838 } 11839 if (exprRes != NULL) 11840 xmlXPathReleaseObject(ctxt->context, exprRes); 11841 /* 11842 * Reset/invalidate the context. 11843 */ 11844 xpctxt->node = oldContextNode; 11845 xpctxt->doc = oldContextDoc; 11846 xpctxt->contextSize = -1; 11847 xpctxt->proximityPosition = -1; 11848 return(newContextSize); 11849 } 11850 return(contextSize); 11851} 11852 11853static int 11854xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, 11855 xmlXPathStepOpPtr op, 11856 int *maxPos) 11857{ 11858 11859 xmlXPathStepOpPtr exprOp; 11860 11861 /* 11862 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! 11863 */ 11864 11865 /* 11866 * If not -1, then ch1 will point to: 11867 * 1) For predicates (XPATH_OP_PREDICATE): 11868 * - an inner predicate operator 11869 * 2) For filters (XPATH_OP_FILTER): 11870 * - an inner filter operater OR 11871 * - an expression selecting the node set. 11872 * E.g. "key('a', 'b')" or "(//foo | //bar)". 11873 */ 11874 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) 11875 return(0); 11876 11877 if (op->ch2 != -1) { 11878 exprOp = &ctxt->comp->steps[op->ch2]; 11879 } else 11880 return(0); 11881 11882 if ((exprOp != NULL) && 11883 (exprOp->op == XPATH_OP_VALUE) && 11884 (exprOp->value4 != NULL) && 11885 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) 11886 { 11887 /* 11888 * We have a "[n]" predicate here. 11889 * TODO: Unfortunately this simplistic test here is not 11890 * able to detect a position() predicate in compound 11891 * expressions like "[@attr = 'a" and position() = 1], 11892 * and even not the usage of position() in 11893 * "[position() = 1]"; thus - obviously - a position-range, 11894 * like it "[position() < 5]", is also not detected. 11895 * Maybe we could rewrite the AST to ease the optimization. 11896 */ 11897 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval; 11898 11899 if (((xmlXPathObjectPtr) exprOp->value4)->floatval == 11900 (float) *maxPos) 11901 { 11902 return(1); 11903 } 11904 } 11905 return(0); 11906} 11907 11908static int 11909xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 11910 xmlXPathStepOpPtr op, 11911 xmlNodePtr * first, xmlNodePtr * last, 11912 int toBool) 11913{ 11914 11915#define XP_TEST_HIT \ 11916 if (hasAxisRange != 0) { \ 11917 if (++pos == maxPos) { \ 11918 addNode(seq, cur); \ 11919 goto axis_range_end; } \ 11920 } else { \ 11921 addNode(seq, cur); \ 11922 if (breakOnFirstHit) goto first_hit; } 11923 11924#define XP_TEST_HIT_NS \ 11925 if (hasAxisRange != 0) { \ 11926 if (++pos == maxPos) { \ 11927 hasNsNodes = 1; \ 11928 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \ 11929 goto axis_range_end; } \ 11930 } else { \ 11931 hasNsNodes = 1; \ 11932 xmlXPathNodeSetAddNs(seq, \ 11933 xpctxt->node, (xmlNsPtr) cur); \ 11934 if (breakOnFirstHit) goto first_hit; } 11935 11936 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 11937 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 11938 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 11939 const xmlChar *prefix = op->value4; 11940 const xmlChar *name = op->value5; 11941 const xmlChar *URI = NULL; 11942 11943#ifdef DEBUG_STEP 11944 int nbMatches = 0, prevMatches = 0; 11945#endif 11946 int total = 0, hasNsNodes = 0; 11947 /* The popped object holding the context nodes */ 11948 xmlXPathObjectPtr obj; 11949 /* The set of context nodes for the node tests */ 11950 xmlNodeSetPtr contextSeq; 11951 int contextIdx; 11952 xmlNodePtr contextNode; 11953 /* The context node for a compound traversal */ 11954 xmlNodePtr outerContextNode; 11955 /* The final resulting node set wrt to all context nodes */ 11956 xmlNodeSetPtr outSeq; 11957 /* 11958 * The temporary resulting node set wrt 1 context node. 11959 * Used to feed predicate evaluation. 11960 */ 11961 xmlNodeSetPtr seq; 11962 xmlNodePtr cur; 11963 /* First predicate operator */ 11964 xmlXPathStepOpPtr predOp; 11965 int maxPos; /* The requested position() (when a "[n]" predicate) */ 11966 int hasPredicateRange, hasAxisRange, pos, size, newSize; 11967 int breakOnFirstHit; 11968 11969 xmlXPathTraversalFunction next = NULL; 11970 /* compound axis traversal */ 11971 xmlXPathTraversalFunctionExt outerNext = NULL; 11972 void (*addNode) (xmlNodeSetPtr, xmlNodePtr); 11973 xmlXPathNodeSetMergeFunction mergeAndClear; 11974 xmlNodePtr oldContextNode; 11975 xmlXPathContextPtr xpctxt = ctxt->context; 11976 11977 11978 CHECK_TYPE0(XPATH_NODESET); 11979 obj = valuePop(ctxt); 11980 /* 11981 * Setup namespaces. 11982 */ 11983 if (prefix != NULL) { 11984 URI = xmlXPathNsLookup(xpctxt, prefix); 11985 if (URI == NULL) { 11986 xmlXPathReleaseObject(xpctxt, obj); 11987 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11988 } 11989 } 11990 /* 11991 * Setup axis. 11992 * 11993 * MAYBE FUTURE TODO: merging optimizations: 11994 * - If the nodes to be traversed wrt to the initial nodes and 11995 * the current axis cannot overlap, then we could avoid searching 11996 * for duplicates during the merge. 11997 * But the question is how/when to evaluate if they cannot overlap. 11998 * Example: if we know that for two initial nodes, the one is 11999 * not in the ancestor-or-self axis of the other, then we could safely 12000 * avoid a duplicate-aware merge, if the axis to be traversed is e.g. 12001 * the descendant-or-self axis. 12002 */ 12003 mergeAndClear = xmlXPathNodeSetMergeAndClear; 12004 switch (axis) { 12005 case AXIS_ANCESTOR: 12006 first = NULL; 12007 next = xmlXPathNextAncestor; 12008 break; 12009 case AXIS_ANCESTOR_OR_SELF: 12010 first = NULL; 12011 next = xmlXPathNextAncestorOrSelf; 12012 break; 12013 case AXIS_ATTRIBUTE: 12014 first = NULL; 12015 last = NULL; 12016 next = xmlXPathNextAttribute; 12017 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12018 break; 12019 case AXIS_CHILD: 12020 last = NULL; 12021 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) { 12022 /* 12023 * This iterator will give us only nodes which can 12024 * hold element nodes. 12025 */ 12026 outerNext = xmlXPathNextDescendantOrSelfElemParent; 12027 } 12028 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && 12029 (type == NODE_TYPE_NODE)) 12030 { 12031 /* 12032 * Optimization if an element node type is 'element'. 12033 */ 12034 next = xmlXPathNextChildElement; 12035 } else 12036 next = xmlXPathNextChild; 12037 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12038 break; 12039 case AXIS_DESCENDANT: 12040 last = NULL; 12041 next = xmlXPathNextDescendant; 12042 break; 12043 case AXIS_DESCENDANT_OR_SELF: 12044 last = NULL; 12045 next = xmlXPathNextDescendantOrSelf; 12046 break; 12047 case AXIS_FOLLOWING: 12048 last = NULL; 12049 next = xmlXPathNextFollowing; 12050 break; 12051 case AXIS_FOLLOWING_SIBLING: 12052 last = NULL; 12053 next = xmlXPathNextFollowingSibling; 12054 break; 12055 case AXIS_NAMESPACE: 12056 first = NULL; 12057 last = NULL; 12058 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 12059 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12060 break; 12061 case AXIS_PARENT: 12062 first = NULL; 12063 next = xmlXPathNextParent; 12064 break; 12065 case AXIS_PRECEDING: 12066 first = NULL; 12067 next = xmlXPathNextPrecedingInternal; 12068 break; 12069 case AXIS_PRECEDING_SIBLING: 12070 first = NULL; 12071 next = xmlXPathNextPrecedingSibling; 12072 break; 12073 case AXIS_SELF: 12074 first = NULL; 12075 last = NULL; 12076 next = xmlXPathNextSelf; 12077 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; 12078 break; 12079 } 12080 12081#ifdef DEBUG_STEP 12082 xmlXPathDebugDumpStepAxis(op, 12083 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); 12084#endif 12085 12086 if (next == NULL) { 12087 xmlXPathReleaseObject(xpctxt, obj); 12088 return(0); 12089 } 12090 contextSeq = obj->nodesetval; 12091 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { 12092 xmlXPathReleaseObject(xpctxt, obj); 12093 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 12094 return(0); 12095 } 12096 /* 12097 * Predicate optimization --------------------------------------------- 12098 * If this step has a last predicate, which contains a position(), 12099 * then we'll optimize (although not exactly "position()", but only 12100 * the short-hand form, i.e., "[n]". 12101 * 12102 * Example - expression "/foo[parent::bar][1]": 12103 * 12104 * COLLECT 'child' 'name' 'node' foo -- op (we are here) 12105 * ROOT -- op->ch1 12106 * PREDICATE -- op->ch2 (predOp) 12107 * PREDICATE -- predOp->ch1 = [parent::bar] 12108 * SORT 12109 * COLLECT 'parent' 'name' 'node' bar 12110 * NODE 12111 * ELEM Object is a number : 1 -- predOp->ch2 = [1] 12112 * 12113 */ 12114 maxPos = 0; 12115 predOp = NULL; 12116 hasPredicateRange = 0; 12117 hasAxisRange = 0; 12118 if (op->ch2 != -1) { 12119 /* 12120 * There's at least one predicate. 16 == XPATH_OP_PREDICATE 12121 */ 12122 predOp = &ctxt->comp->steps[op->ch2]; 12123 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { 12124 if (predOp->ch1 != -1) { 12125 /* 12126 * Use the next inner predicate operator. 12127 */ 12128 predOp = &ctxt->comp->steps[predOp->ch1]; 12129 hasPredicateRange = 1; 12130 } else { 12131 /* 12132 * There's no other predicate than the [n] predicate. 12133 */ 12134 predOp = NULL; 12135 hasAxisRange = 1; 12136 } 12137 } 12138 } 12139 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; 12140 /* 12141 * Axis traversal ----------------------------------------------------- 12142 */ 12143 /* 12144 * 2.3 Node Tests 12145 * - For the attribute axis, the principal node type is attribute. 12146 * - For the namespace axis, the principal node type is namespace. 12147 * - For other axes, the principal node type is element. 12148 * 12149 * A node test * is true for any node of the 12150 * principal node type. For example, child::* will 12151 * select all element children of the context node 12152 */ 12153 oldContextNode = xpctxt->node; 12154 addNode = xmlXPathNodeSetAddUnique; 12155 outSeq = NULL; 12156 seq = NULL; 12157 outerContextNode = NULL; 12158 contextNode = NULL; 12159 contextIdx = 0; 12160 12161 12162 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) { 12163 if (outerNext != NULL) { 12164 /* 12165 * This is a compound traversal. 12166 */ 12167 if (contextNode == NULL) { 12168 /* 12169 * Set the context for the outer traversal. 12170 */ 12171 outerContextNode = contextSeq->nodeTab[contextIdx++]; 12172 contextNode = outerNext(NULL, outerContextNode); 12173 } else 12174 contextNode = outerNext(contextNode, outerContextNode); 12175 if (contextNode == NULL) 12176 continue; 12177 /* 12178 * Set the context for the main traversal. 12179 */ 12180 xpctxt->node = contextNode; 12181 } else 12182 xpctxt->node = contextSeq->nodeTab[contextIdx++]; 12183 12184 if (seq == NULL) { 12185 seq = xmlXPathNodeSetCreate(NULL); 12186 if (seq == NULL) { 12187 total = 0; 12188 goto error; 12189 } 12190 } 12191 /* 12192 * Traverse the axis and test the nodes. 12193 */ 12194 pos = 0; 12195 cur = NULL; 12196 hasNsNodes = 0; 12197 do { 12198 cur = next(ctxt, cur); 12199 if (cur == NULL) 12200 break; 12201 12202 /* 12203 * QUESTION TODO: What does the "first" and "last" stuff do? 12204 */ 12205 if ((first != NULL) && (*first != NULL)) { 12206 if (*first == cur) 12207 break; 12208 if (((total % 256) == 0) && 12209#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12210 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 12211#else 12212 (xmlXPathCmpNodes(*first, cur) >= 0)) 12213#endif 12214 { 12215 break; 12216 } 12217 } 12218 if ((last != NULL) && (*last != NULL)) { 12219 if (*last == cur) 12220 break; 12221 if (((total % 256) == 0) && 12222#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 12223 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 12224#else 12225 (xmlXPathCmpNodes(cur, *last) >= 0)) 12226#endif 12227 { 12228 break; 12229 } 12230 } 12231 12232 total++; 12233 12234#ifdef DEBUG_STEP 12235 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 12236#endif 12237 12238 switch (test) { 12239 case NODE_TEST_NONE: 12240 total = 0; 12241 STRANGE 12242 goto error; 12243 case NODE_TEST_TYPE: 12244 /* 12245 * TODO: Don't we need to use 12246 * xmlXPathNodeSetAddNs() for namespace nodes here? 12247 * Surprisingly, some c14n tests fail, if we do this. 12248 */ 12249 if (type == NODE_TYPE_NODE) { 12250 switch (cur->type) { 12251 case XML_DOCUMENT_NODE: 12252 case XML_HTML_DOCUMENT_NODE: 12253#ifdef LIBXML_DOCB_ENABLED 12254 case XML_DOCB_DOCUMENT_NODE: 12255#endif 12256 case XML_ELEMENT_NODE: 12257 case XML_ATTRIBUTE_NODE: 12258 case XML_PI_NODE: 12259 case XML_COMMENT_NODE: 12260 case XML_CDATA_SECTION_NODE: 12261 case XML_TEXT_NODE: 12262 case XML_NAMESPACE_DECL: 12263 XP_TEST_HIT 12264 break; 12265 default: 12266 break; 12267 } 12268 } else if (cur->type == type) { 12269 if (cur->type == XML_NAMESPACE_DECL) 12270 XP_TEST_HIT_NS 12271 else 12272 XP_TEST_HIT 12273 } else if ((type == NODE_TYPE_TEXT) && 12274 (cur->type == XML_CDATA_SECTION_NODE)) 12275 { 12276 XP_TEST_HIT 12277 } 12278 break; 12279 case NODE_TEST_PI: 12280 if ((cur->type == XML_PI_NODE) && 12281 ((name == NULL) || xmlStrEqual(name, cur->name))) 12282 { 12283 XP_TEST_HIT 12284 } 12285 break; 12286 case NODE_TEST_ALL: 12287 if (axis == AXIS_ATTRIBUTE) { 12288 if (cur->type == XML_ATTRIBUTE_NODE) 12289 { 12290 XP_TEST_HIT 12291 } 12292 } else if (axis == AXIS_NAMESPACE) { 12293 if (cur->type == XML_NAMESPACE_DECL) 12294 { 12295 XP_TEST_HIT_NS 12296 } 12297 } else { 12298 if (cur->type == XML_ELEMENT_NODE) { 12299 if (prefix == NULL) 12300 { 12301 XP_TEST_HIT 12302 12303 } else if ((cur->ns != NULL) && 12304 (xmlStrEqual(URI, cur->ns->href))) 12305 { 12306 XP_TEST_HIT 12307 } 12308 } 12309 } 12310 break; 12311 case NODE_TEST_NS:{ 12312 TODO; 12313 break; 12314 } 12315 case NODE_TEST_NAME: 12316 if (axis == AXIS_ATTRIBUTE) { 12317 if (cur->type != XML_ATTRIBUTE_NODE) 12318 break; 12319 } else if (axis == AXIS_NAMESPACE) { 12320 if (cur->type != XML_NAMESPACE_DECL) 12321 break; 12322 } else { 12323 if (cur->type != XML_ELEMENT_NODE) 12324 break; 12325 } 12326 switch (cur->type) { 12327 case XML_ELEMENT_NODE: 12328 if (xmlStrEqual(name, cur->name)) { 12329 if (prefix == NULL) { 12330 if (cur->ns == NULL) 12331 { 12332 XP_TEST_HIT 12333 } 12334 } else { 12335 if ((cur->ns != NULL) && 12336 (xmlStrEqual(URI, cur->ns->href))) 12337 { 12338 XP_TEST_HIT 12339 } 12340 } 12341 } 12342 break; 12343 case XML_ATTRIBUTE_NODE:{ 12344 xmlAttrPtr attr = (xmlAttrPtr) cur; 12345 12346 if (xmlStrEqual(name, attr->name)) { 12347 if (prefix == NULL) { 12348 if ((attr->ns == NULL) || 12349 (attr->ns->prefix == NULL)) 12350 { 12351 XP_TEST_HIT 12352 } 12353 } else { 12354 if ((attr->ns != NULL) && 12355 (xmlStrEqual(URI, 12356 attr->ns->href))) 12357 { 12358 XP_TEST_HIT 12359 } 12360 } 12361 } 12362 break; 12363 } 12364 case XML_NAMESPACE_DECL: 12365 if (cur->type == XML_NAMESPACE_DECL) { 12366 xmlNsPtr ns = (xmlNsPtr) cur; 12367 12368 if ((ns->prefix != NULL) && (name != NULL) 12369 && (xmlStrEqual(ns->prefix, name))) 12370 { 12371 XP_TEST_HIT_NS 12372 } 12373 } 12374 break; 12375 default: 12376 break; 12377 } 12378 break; 12379 } /* switch(test) */ 12380 } while (cur != NULL); 12381 12382 goto apply_predicates; 12383 12384axis_range_end: /* ----------------------------------------------------- */ 12385 /* 12386 * We have a "/foo[n]", and position() = n was reached. 12387 * Note that we can have as well "/foo/::parent::foo[1]", so 12388 * a duplicate-aware merge is still needed. 12389 * Merge with the result. 12390 */ 12391 if (outSeq == NULL) { 12392 outSeq = seq; 12393 seq = NULL; 12394 } else 12395 outSeq = mergeAndClear(outSeq, seq, 0); 12396 /* 12397 * Break if only a true/false result was requested. 12398 */ 12399 if (toBool) 12400 break; 12401 continue; 12402 12403first_hit: /* ---------------------------------------------------------- */ 12404 /* 12405 * Break if only a true/false result was requested and 12406 * no predicates existed and a node test succeeded. 12407 */ 12408 if (outSeq == NULL) { 12409 outSeq = seq; 12410 seq = NULL; 12411 } else 12412 outSeq = mergeAndClear(outSeq, seq, 0); 12413 break; 12414 12415#ifdef DEBUG_STEP 12416 if (seq != NULL) 12417 nbMatches += seq->nodeNr; 12418#endif 12419 12420apply_predicates: /* --------------------------------------------------- */ 12421 /* 12422 * Apply predicates. 12423 */ 12424 if ((predOp != NULL) && (seq->nodeNr > 0)) { 12425 /* 12426 * E.g. when we have a "/foo[some expression][n]". 12427 */ 12428 /* 12429 * QUESTION TODO: The old predicate evaluation took into 12430 * account location-sets. 12431 * (E.g. ctxt->value->type == XPATH_LOCATIONSET) 12432 * Do we expect such a set here? 12433 * All what I learned now from the evaluation semantics 12434 * does not indicate that a location-set will be processed 12435 * here, so this looks OK. 12436 */ 12437 /* 12438 * Iterate over all predicates, starting with the outermost 12439 * predicate. 12440 * TODO: Problem: we cannot execute the inner predicates first 12441 * since we cannot go back *up* the operator tree! 12442 * Options we have: 12443 * 1) Use of recursive functions (like is it currently done 12444 * via xmlXPathCompOpEval()) 12445 * 2) Add a predicate evaluation information stack to the 12446 * context struct 12447 * 3) Change the way the operators are linked; we need a 12448 * "parent" field on xmlXPathStepOp 12449 * 12450 * For the moment, I'll try to solve this with a recursive 12451 * function: xmlXPathCompOpEvalPredicate(). 12452 */ 12453 size = seq->nodeNr; 12454 if (hasPredicateRange != 0) 12455 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt, 12456 predOp, seq, size, maxPos, maxPos, hasNsNodes); 12457 else 12458 newSize = xmlXPathCompOpEvalPredicate(ctxt, 12459 predOp, seq, size, hasNsNodes); 12460 12461 if (ctxt->error != XPATH_EXPRESSION_OK) { 12462 total = 0; 12463 goto error; 12464 } 12465 /* 12466 * Add the filtered set of nodes to the result node set. 12467 */ 12468 if (newSize == 0) { 12469 /* 12470 * The predicates filtered all nodes out. 12471 */ 12472 xmlXPathNodeSetClear(seq, hasNsNodes); 12473 } else if (seq->nodeNr > 0) { 12474 /* 12475 * Add to result set. 12476 */ 12477 if (outSeq == NULL) { 12478 if (size != newSize) { 12479 /* 12480 * We need to merge and clear here, since 12481 * the sequence will contained NULLed entries. 12482 */ 12483 outSeq = mergeAndClear(NULL, seq, 1); 12484 } else { 12485 outSeq = seq; 12486 seq = NULL; 12487 } 12488 } else 12489 outSeq = mergeAndClear(outSeq, seq, 12490 (size != newSize) ? 1: 0); 12491 /* 12492 * Break if only a true/false result was requested. 12493 */ 12494 if (toBool) 12495 break; 12496 } 12497 } else if (seq->nodeNr > 0) { 12498 /* 12499 * Add to result set. 12500 */ 12501 if (outSeq == NULL) { 12502 outSeq = seq; 12503 seq = NULL; 12504 } else { 12505 outSeq = mergeAndClear(outSeq, seq, 0); 12506 } 12507 } 12508 } 12509 12510error: 12511 if ((obj->boolval) && (obj->user != NULL)) { 12512 /* 12513 * QUESTION TODO: What does this do and why? 12514 * TODO: Do we have to do this also for the "error" 12515 * cleanup further down? 12516 */ 12517 ctxt->value->boolval = 1; 12518 ctxt->value->user = obj->user; 12519 obj->user = NULL; 12520 obj->boolval = 0; 12521 } 12522 xmlXPathReleaseObject(xpctxt, obj); 12523 12524 /* 12525 * Ensure we return at least an emtpy set. 12526 */ 12527 if (outSeq == NULL) { 12528 if ((seq != NULL) && (seq->nodeNr == 0)) 12529 outSeq = seq; 12530 else 12531 outSeq = xmlXPathNodeSetCreate(NULL); 12532 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */ 12533 } 12534 if ((seq != NULL) && (seq != outSeq)) { 12535 xmlXPathFreeNodeSet(seq); 12536 } 12537 /* 12538 * Hand over the result. Better to push the set also in 12539 * case of errors. 12540 */ 12541 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); 12542 /* 12543 * Reset the context node. 12544 */ 12545 xpctxt->node = oldContextNode; 12546 12547#ifdef DEBUG_STEP 12548 xmlGenericError(xmlGenericErrorContext, 12549 "\nExamined %d nodes, found %d nodes at that step\n", 12550 total, nbMatches); 12551#endif 12552 12553 return(total); 12554} 12555 12556static int 12557xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12558 xmlXPathStepOpPtr op, xmlNodePtr * first); 12559 12560/** 12561 * xmlXPathCompOpEvalFirst: 12562 * @ctxt: the XPath parser context with the compiled expression 12563 * @op: an XPath compiled operation 12564 * @first: the first elem found so far 12565 * 12566 * Evaluate the Precompiled XPath operation searching only the first 12567 * element in document order 12568 * 12569 * Returns the number of examined objects. 12570 */ 12571static int 12572xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12573 xmlXPathStepOpPtr op, xmlNodePtr * first) 12574{ 12575 int total = 0, cur; 12576 xmlXPathCompExprPtr comp; 12577 xmlXPathObjectPtr arg1, arg2; 12578 12579 CHECK_ERROR0; 12580 comp = ctxt->comp; 12581 switch (op->op) { 12582 case XPATH_OP_END: 12583 return (0); 12584 case XPATH_OP_UNION: 12585 total = 12586 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12587 first); 12588 CHECK_ERROR0; 12589 if ((ctxt->value != NULL) 12590 && (ctxt->value->type == XPATH_NODESET) 12591 && (ctxt->value->nodesetval != NULL) 12592 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12593 /* 12594 * limit tree traversing to first node in the result 12595 */ 12596 /* 12597 * OPTIMIZE TODO: This implicitely sorts 12598 * the result, even if not needed. E.g. if the argument 12599 * of the count() function, no sorting is needed. 12600 * OPTIMIZE TODO: How do we know if the node-list wasn't 12601 * aready sorted? 12602 */ 12603 if (ctxt->value->nodesetval->nodeNr > 1) 12604 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12605 *first = ctxt->value->nodesetval->nodeTab[0]; 12606 } 12607 cur = 12608 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12609 first); 12610 CHECK_ERROR0; 12611 CHECK_TYPE0(XPATH_NODESET); 12612 arg2 = valuePop(ctxt); 12613 12614 CHECK_TYPE0(XPATH_NODESET); 12615 arg1 = valuePop(ctxt); 12616 12617 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12618 arg2->nodesetval); 12619 valuePush(ctxt, arg1); 12620 xmlXPathReleaseObject(ctxt->context, arg2); 12621 /* optimizer */ 12622 if (total > cur) 12623 xmlXPathCompSwap(op); 12624 return (total + cur); 12625 case XPATH_OP_ROOT: 12626 xmlXPathRoot(ctxt); 12627 return (0); 12628 case XPATH_OP_NODE: 12629 if (op->ch1 != -1) 12630 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12631 CHECK_ERROR0; 12632 if (op->ch2 != -1) 12633 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12634 CHECK_ERROR0; 12635 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12636 ctxt->context->node)); 12637 return (total); 12638 case XPATH_OP_RESET: 12639 if (op->ch1 != -1) 12640 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12641 CHECK_ERROR0; 12642 if (op->ch2 != -1) 12643 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12644 CHECK_ERROR0; 12645 ctxt->context->node = NULL; 12646 return (total); 12647 case XPATH_OP_COLLECT:{ 12648 if (op->ch1 == -1) 12649 return (total); 12650 12651 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12652 CHECK_ERROR0; 12653 12654 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); 12655 return (total); 12656 } 12657 case XPATH_OP_VALUE: 12658 valuePush(ctxt, 12659 xmlXPathCacheObjectCopy(ctxt->context, 12660 (xmlXPathObjectPtr) op->value4)); 12661 return (0); 12662 case XPATH_OP_SORT: 12663 if (op->ch1 != -1) 12664 total += 12665 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12666 first); 12667 CHECK_ERROR0; 12668 if ((ctxt->value != NULL) 12669 && (ctxt->value->type == XPATH_NODESET) 12670 && (ctxt->value->nodesetval != NULL) 12671 && (ctxt->value->nodesetval->nodeNr > 1)) 12672 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12673 return (total); 12674#ifdef XP_OPTIMIZED_FILTER_FIRST 12675 case XPATH_OP_FILTER: 12676 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12677 return (total); 12678#endif 12679 default: 12680 return (xmlXPathCompOpEval(ctxt, op)); 12681 } 12682} 12683 12684/** 12685 * xmlXPathCompOpEvalLast: 12686 * @ctxt: the XPath parser context with the compiled expression 12687 * @op: an XPath compiled operation 12688 * @last: the last elem found so far 12689 * 12690 * Evaluate the Precompiled XPath operation searching only the last 12691 * element in document order 12692 * 12693 * Returns the number of nodes traversed 12694 */ 12695static int 12696xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12697 xmlNodePtr * last) 12698{ 12699 int total = 0, cur; 12700 xmlXPathCompExprPtr comp; 12701 xmlXPathObjectPtr arg1, arg2; 12702 xmlNodePtr bak; 12703 xmlDocPtr bakd; 12704 int pp; 12705 int cs; 12706 12707 CHECK_ERROR0; 12708 comp = ctxt->comp; 12709 switch (op->op) { 12710 case XPATH_OP_END: 12711 return (0); 12712 case XPATH_OP_UNION: 12713 bakd = ctxt->context->doc; 12714 bak = ctxt->context->node; 12715 pp = ctxt->context->proximityPosition; 12716 cs = ctxt->context->contextSize; 12717 total = 12718 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 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 /* 12725 * limit tree traversing to first node in the result 12726 */ 12727 if (ctxt->value->nodesetval->nodeNr > 1) 12728 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12729 *last = 12730 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12731 nodesetval->nodeNr - 12732 1]; 12733 } 12734 ctxt->context->doc = bakd; 12735 ctxt->context->node = bak; 12736 ctxt->context->proximityPosition = pp; 12737 ctxt->context->contextSize = cs; 12738 cur = 12739 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12740 CHECK_ERROR0; 12741 if ((ctxt->value != NULL) 12742 && (ctxt->value->type == XPATH_NODESET) 12743 && (ctxt->value->nodesetval != NULL) 12744 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12745 } 12746 CHECK_TYPE0(XPATH_NODESET); 12747 arg2 = valuePop(ctxt); 12748 12749 CHECK_TYPE0(XPATH_NODESET); 12750 arg1 = valuePop(ctxt); 12751 12752 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12753 arg2->nodesetval); 12754 valuePush(ctxt, arg1); 12755 xmlXPathReleaseObject(ctxt->context, arg2); 12756 /* optimizer */ 12757 if (total > cur) 12758 xmlXPathCompSwap(op); 12759 return (total + cur); 12760 case XPATH_OP_ROOT: 12761 xmlXPathRoot(ctxt); 12762 return (0); 12763 case XPATH_OP_NODE: 12764 if (op->ch1 != -1) 12765 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12766 CHECK_ERROR0; 12767 if (op->ch2 != -1) 12768 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12769 CHECK_ERROR0; 12770 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12771 ctxt->context->node)); 12772 return (total); 12773 case XPATH_OP_RESET: 12774 if (op->ch1 != -1) 12775 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12776 CHECK_ERROR0; 12777 if (op->ch2 != -1) 12778 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12779 CHECK_ERROR0; 12780 ctxt->context->node = NULL; 12781 return (total); 12782 case XPATH_OP_COLLECT:{ 12783 if (op->ch1 == -1) 12784 return (0); 12785 12786 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12787 CHECK_ERROR0; 12788 12789 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); 12790 return (total); 12791 } 12792 case XPATH_OP_VALUE: 12793 valuePush(ctxt, 12794 xmlXPathCacheObjectCopy(ctxt->context, 12795 (xmlXPathObjectPtr) op->value4)); 12796 return (0); 12797 case XPATH_OP_SORT: 12798 if (op->ch1 != -1) 12799 total += 12800 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12801 last); 12802 CHECK_ERROR0; 12803 if ((ctxt->value != NULL) 12804 && (ctxt->value->type == XPATH_NODESET) 12805 && (ctxt->value->nodesetval != NULL) 12806 && (ctxt->value->nodesetval->nodeNr > 1)) 12807 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12808 return (total); 12809 default: 12810 return (xmlXPathCompOpEval(ctxt, op)); 12811 } 12812} 12813 12814#ifdef XP_OPTIMIZED_FILTER_FIRST 12815static int 12816xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12817 xmlXPathStepOpPtr op, xmlNodePtr * first) 12818{ 12819 int total = 0; 12820 xmlXPathCompExprPtr comp; 12821 xmlXPathObjectPtr res; 12822 xmlXPathObjectPtr obj; 12823 xmlNodeSetPtr oldset; 12824 xmlNodePtr oldnode; 12825 xmlDocPtr oldDoc; 12826 int i; 12827 12828 CHECK_ERROR0; 12829 comp = ctxt->comp; 12830 /* 12831 * Optimization for ()[last()] selection i.e. the last elem 12832 */ 12833 if ((op->ch1 != -1) && (op->ch2 != -1) && 12834 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12835 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12836 int f = comp->steps[op->ch2].ch1; 12837 12838 if ((f != -1) && 12839 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12840 (comp->steps[f].value5 == NULL) && 12841 (comp->steps[f].value == 0) && 12842 (comp->steps[f].value4 != NULL) && 12843 (xmlStrEqual 12844 (comp->steps[f].value4, BAD_CAST "last"))) { 12845 xmlNodePtr last = NULL; 12846 12847 total += 12848 xmlXPathCompOpEvalLast(ctxt, 12849 &comp->steps[op->ch1], 12850 &last); 12851 CHECK_ERROR0; 12852 /* 12853 * The nodeset should be in document order, 12854 * Keep only the last value 12855 */ 12856 if ((ctxt->value != NULL) && 12857 (ctxt->value->type == XPATH_NODESET) && 12858 (ctxt->value->nodesetval != NULL) && 12859 (ctxt->value->nodesetval->nodeTab != NULL) && 12860 (ctxt->value->nodesetval->nodeNr > 1)) { 12861 ctxt->value->nodesetval->nodeTab[0] = 12862 ctxt->value->nodesetval->nodeTab[ctxt-> 12863 value-> 12864 nodesetval-> 12865 nodeNr - 12866 1]; 12867 ctxt->value->nodesetval->nodeNr = 1; 12868 *first = *(ctxt->value->nodesetval->nodeTab); 12869 } 12870 return (total); 12871 } 12872 } 12873 12874 if (op->ch1 != -1) 12875 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12876 CHECK_ERROR0; 12877 if (op->ch2 == -1) 12878 return (total); 12879 if (ctxt->value == NULL) 12880 return (total); 12881 12882#ifdef LIBXML_XPTR_ENABLED 12883 oldnode = ctxt->context->node; 12884 /* 12885 * Hum are we filtering the result of an XPointer expression 12886 */ 12887 if (ctxt->value->type == XPATH_LOCATIONSET) { 12888 xmlXPathObjectPtr tmp = NULL; 12889 xmlLocationSetPtr newlocset = NULL; 12890 xmlLocationSetPtr oldlocset; 12891 12892 /* 12893 * Extract the old locset, and then evaluate the result of the 12894 * expression for all the element in the locset. use it to grow 12895 * up a new locset. 12896 */ 12897 CHECK_TYPE0(XPATH_LOCATIONSET); 12898 obj = valuePop(ctxt); 12899 oldlocset = obj->user; 12900 ctxt->context->node = NULL; 12901 12902 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 12903 ctxt->context->contextSize = 0; 12904 ctxt->context->proximityPosition = 0; 12905 if (op->ch2 != -1) 12906 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12907 res = valuePop(ctxt); 12908 if (res != NULL) { 12909 xmlXPathReleaseObject(ctxt->context, res); 12910 } 12911 valuePush(ctxt, obj); 12912 CHECK_ERROR0; 12913 return (total); 12914 } 12915 newlocset = xmlXPtrLocationSetCreate(NULL); 12916 12917 for (i = 0; i < oldlocset->locNr; i++) { 12918 /* 12919 * Run the evaluation with a node list made of a 12920 * single item in the nodelocset. 12921 */ 12922 ctxt->context->node = oldlocset->locTab[i]->user; 12923 ctxt->context->contextSize = oldlocset->locNr; 12924 ctxt->context->proximityPosition = i + 1; 12925 if (tmp == NULL) { 12926 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 12927 ctxt->context->node); 12928 } else { 12929 xmlXPathNodeSetAddUnique(tmp->nodesetval, 12930 ctxt->context->node); 12931 } 12932 valuePush(ctxt, tmp); 12933 if (op->ch2 != -1) 12934 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12935 if (ctxt->error != XPATH_EXPRESSION_OK) { 12936 xmlXPathFreeObject(obj); 12937 return(0); 12938 } 12939 /* 12940 * The result of the evaluation need to be tested to 12941 * decided whether the filter succeeded or not 12942 */ 12943 res = valuePop(ctxt); 12944 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 12945 xmlXPtrLocationSetAdd(newlocset, 12946 xmlXPathCacheObjectCopy(ctxt->context, 12947 oldlocset->locTab[i])); 12948 } 12949 /* 12950 * Cleanup 12951 */ 12952 if (res != NULL) { 12953 xmlXPathReleaseObject(ctxt->context, res); 12954 } 12955 if (ctxt->value == tmp) { 12956 valuePop(ctxt); 12957 xmlXPathNodeSetClear(tmp->nodesetval, 1); 12958 /* 12959 * REVISIT TODO: Don't create a temporary nodeset 12960 * for everly iteration. 12961 */ 12962 /* OLD: xmlXPathFreeObject(res); */ 12963 } else 12964 tmp = NULL; 12965 ctxt->context->node = NULL; 12966 /* 12967 * Only put the first node in the result, then leave. 12968 */ 12969 if (newlocset->locNr > 0) { 12970 *first = (xmlNodePtr) oldlocset->locTab[i]->user; 12971 break; 12972 } 12973 } 12974 if (tmp != NULL) { 12975 xmlXPathReleaseObject(ctxt->context, tmp); 12976 } 12977 /* 12978 * The result is used as the new evaluation locset. 12979 */ 12980 xmlXPathReleaseObject(ctxt->context, obj); 12981 ctxt->context->node = NULL; 12982 ctxt->context->contextSize = -1; 12983 ctxt->context->proximityPosition = -1; 12984 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 12985 ctxt->context->node = oldnode; 12986 return (total); 12987 } 12988#endif /* LIBXML_XPTR_ENABLED */ 12989 12990 /* 12991 * Extract the old set, and then evaluate the result of the 12992 * expression for all the element in the set. use it to grow 12993 * up a new set. 12994 */ 12995 CHECK_TYPE0(XPATH_NODESET); 12996 obj = valuePop(ctxt); 12997 oldset = obj->nodesetval; 12998 12999 oldnode = ctxt->context->node; 13000 oldDoc = ctxt->context->doc; 13001 ctxt->context->node = NULL; 13002 13003 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13004 ctxt->context->contextSize = 0; 13005 ctxt->context->proximityPosition = 0; 13006 /* QUESTION TODO: Why was this code commented out? 13007 if (op->ch2 != -1) 13008 total += 13009 xmlXPathCompOpEval(ctxt, 13010 &comp->steps[op->ch2]); 13011 CHECK_ERROR0; 13012 res = valuePop(ctxt); 13013 if (res != NULL) 13014 xmlXPathFreeObject(res); 13015 */ 13016 valuePush(ctxt, obj); 13017 ctxt->context->node = oldnode; 13018 CHECK_ERROR0; 13019 } else { 13020 xmlNodeSetPtr newset; 13021 xmlXPathObjectPtr tmp = NULL; 13022 /* 13023 * Initialize the new set. 13024 * Also set the xpath document in case things like 13025 * key() evaluation are attempted on the predicate 13026 */ 13027 newset = xmlXPathNodeSetCreate(NULL); 13028 /* XXX what if xmlXPathNodeSetCreate returned NULL? */ 13029 13030 for (i = 0; i < oldset->nodeNr; i++) { 13031 /* 13032 * Run the evaluation with a node list made of 13033 * a single item in the nodeset. 13034 */ 13035 ctxt->context->node = oldset->nodeTab[i]; 13036 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13037 (oldset->nodeTab[i]->doc != NULL)) 13038 ctxt->context->doc = oldset->nodeTab[i]->doc; 13039 if (tmp == NULL) { 13040 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13041 ctxt->context->node); 13042 } else { 13043 xmlXPathNodeSetAddUnique(tmp->nodesetval, 13044 ctxt->context->node); 13045 } 13046 valuePush(ctxt, tmp); 13047 ctxt->context->contextSize = oldset->nodeNr; 13048 ctxt->context->proximityPosition = i + 1; 13049 if (op->ch2 != -1) 13050 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13051 if (ctxt->error != XPATH_EXPRESSION_OK) { 13052 xmlXPathFreeNodeSet(newset); 13053 xmlXPathFreeObject(obj); 13054 return(0); 13055 } 13056 /* 13057 * The result of the evaluation needs to be tested to 13058 * decide whether the filter succeeded or not 13059 */ 13060 res = valuePop(ctxt); 13061 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13062 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 13063 } 13064 /* 13065 * Cleanup 13066 */ 13067 if (res != NULL) { 13068 xmlXPathReleaseObject(ctxt->context, res); 13069 } 13070 if (ctxt->value == tmp) { 13071 valuePop(ctxt); 13072 /* 13073 * Don't free the temporary nodeset 13074 * in order to avoid massive recreation inside this 13075 * loop. 13076 */ 13077 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13078 } else 13079 tmp = NULL; 13080 ctxt->context->node = NULL; 13081 /* 13082 * Only put the first node in the result, then leave. 13083 */ 13084 if (newset->nodeNr > 0) { 13085 *first = *(newset->nodeTab); 13086 break; 13087 } 13088 } 13089 if (tmp != NULL) { 13090 xmlXPathReleaseObject(ctxt->context, tmp); 13091 } 13092 /* 13093 * The result is used as the new evaluation set. 13094 */ 13095 xmlXPathReleaseObject(ctxt->context, obj); 13096 ctxt->context->node = NULL; 13097 ctxt->context->contextSize = -1; 13098 ctxt->context->proximityPosition = -1; 13099 /* may want to move this past the '}' later */ 13100 ctxt->context->doc = oldDoc; 13101 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13102 } 13103 ctxt->context->node = oldnode; 13104 return(total); 13105} 13106#endif /* XP_OPTIMIZED_FILTER_FIRST */ 13107 13108/** 13109 * xmlXPathCompOpEval: 13110 * @ctxt: the XPath parser context with the compiled expression 13111 * @op: an XPath compiled operation 13112 * 13113 * Evaluate the Precompiled XPath operation 13114 * Returns the number of nodes traversed 13115 */ 13116static int 13117xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 13118{ 13119 int total = 0; 13120 int equal, ret; 13121 xmlXPathCompExprPtr comp; 13122 xmlXPathObjectPtr arg1, arg2; 13123 xmlNodePtr bak; 13124 xmlDocPtr bakd; 13125 int pp; 13126 int cs; 13127 13128 CHECK_ERROR0; 13129 comp = ctxt->comp; 13130 switch (op->op) { 13131 case XPATH_OP_END: 13132 return (0); 13133 case XPATH_OP_AND: 13134 bakd = ctxt->context->doc; 13135 bak = ctxt->context->node; 13136 pp = ctxt->context->proximityPosition; 13137 cs = ctxt->context->contextSize; 13138 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13139 CHECK_ERROR0; 13140 xmlXPathBooleanFunction(ctxt, 1); 13141 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 13142 return (total); 13143 arg2 = valuePop(ctxt); 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 if (ctxt->error) { 13150 xmlXPathFreeObject(arg2); 13151 return(0); 13152 } 13153 xmlXPathBooleanFunction(ctxt, 1); 13154 arg1 = valuePop(ctxt); 13155 arg1->boolval &= arg2->boolval; 13156 valuePush(ctxt, arg1); 13157 xmlXPathReleaseObject(ctxt->context, arg2); 13158 return (total); 13159 case XPATH_OP_OR: 13160 bakd = ctxt->context->doc; 13161 bak = ctxt->context->node; 13162 pp = ctxt->context->proximityPosition; 13163 cs = ctxt->context->contextSize; 13164 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13165 CHECK_ERROR0; 13166 xmlXPathBooleanFunction(ctxt, 1); 13167 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 13168 return (total); 13169 arg2 = valuePop(ctxt); 13170 ctxt->context->doc = bakd; 13171 ctxt->context->node = bak; 13172 ctxt->context->proximityPosition = pp; 13173 ctxt->context->contextSize = cs; 13174 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13175 if (ctxt->error) { 13176 xmlXPathFreeObject(arg2); 13177 return(0); 13178 } 13179 xmlXPathBooleanFunction(ctxt, 1); 13180 arg1 = valuePop(ctxt); 13181 arg1->boolval |= arg2->boolval; 13182 valuePush(ctxt, arg1); 13183 xmlXPathReleaseObject(ctxt->context, arg2); 13184 return (total); 13185 case XPATH_OP_EQUAL: 13186 bakd = ctxt->context->doc; 13187 bak = ctxt->context->node; 13188 pp = ctxt->context->proximityPosition; 13189 cs = ctxt->context->contextSize; 13190 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13191 CHECK_ERROR0; 13192 ctxt->context->doc = bakd; 13193 ctxt->context->node = bak; 13194 ctxt->context->proximityPosition = pp; 13195 ctxt->context->contextSize = cs; 13196 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13197 CHECK_ERROR0; 13198 if (op->value) 13199 equal = xmlXPathEqualValues(ctxt); 13200 else 13201 equal = xmlXPathNotEqualValues(ctxt); 13202 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 13203 return (total); 13204 case XPATH_OP_CMP: 13205 bakd = ctxt->context->doc; 13206 bak = ctxt->context->node; 13207 pp = ctxt->context->proximityPosition; 13208 cs = ctxt->context->contextSize; 13209 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13210 CHECK_ERROR0; 13211 ctxt->context->doc = bakd; 13212 ctxt->context->node = bak; 13213 ctxt->context->proximityPosition = pp; 13214 ctxt->context->contextSize = cs; 13215 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13216 CHECK_ERROR0; 13217 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 13218 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 13219 return (total); 13220 case XPATH_OP_PLUS: 13221 bakd = ctxt->context->doc; 13222 bak = ctxt->context->node; 13223 pp = ctxt->context->proximityPosition; 13224 cs = ctxt->context->contextSize; 13225 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13226 CHECK_ERROR0; 13227 if (op->ch2 != -1) { 13228 ctxt->context->doc = bakd; 13229 ctxt->context->node = bak; 13230 ctxt->context->proximityPosition = pp; 13231 ctxt->context->contextSize = cs; 13232 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13233 } 13234 CHECK_ERROR0; 13235 if (op->value == 0) 13236 xmlXPathSubValues(ctxt); 13237 else if (op->value == 1) 13238 xmlXPathAddValues(ctxt); 13239 else if (op->value == 2) 13240 xmlXPathValueFlipSign(ctxt); 13241 else if (op->value == 3) { 13242 CAST_TO_NUMBER; 13243 CHECK_TYPE0(XPATH_NUMBER); 13244 } 13245 return (total); 13246 case XPATH_OP_MULT: 13247 bakd = ctxt->context->doc; 13248 bak = ctxt->context->node; 13249 pp = ctxt->context->proximityPosition; 13250 cs = ctxt->context->contextSize; 13251 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13252 CHECK_ERROR0; 13253 ctxt->context->doc = bakd; 13254 ctxt->context->node = bak; 13255 ctxt->context->proximityPosition = pp; 13256 ctxt->context->contextSize = cs; 13257 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13258 CHECK_ERROR0; 13259 if (op->value == 0) 13260 xmlXPathMultValues(ctxt); 13261 else if (op->value == 1) 13262 xmlXPathDivValues(ctxt); 13263 else if (op->value == 2) 13264 xmlXPathModValues(ctxt); 13265 return (total); 13266 case XPATH_OP_UNION: 13267 bakd = ctxt->context->doc; 13268 bak = ctxt->context->node; 13269 pp = ctxt->context->proximityPosition; 13270 cs = ctxt->context->contextSize; 13271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13272 CHECK_ERROR0; 13273 ctxt->context->doc = bakd; 13274 ctxt->context->node = bak; 13275 ctxt->context->proximityPosition = pp; 13276 ctxt->context->contextSize = cs; 13277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13278 CHECK_ERROR0; 13279 CHECK_TYPE0(XPATH_NODESET); 13280 arg2 = valuePop(ctxt); 13281 13282 CHECK_TYPE0(XPATH_NODESET); 13283 arg1 = valuePop(ctxt); 13284 13285 if ((arg1->nodesetval == NULL) || 13286 ((arg2->nodesetval != NULL) && 13287 (arg2->nodesetval->nodeNr != 0))) 13288 { 13289 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 13290 arg2->nodesetval); 13291 } 13292 13293 valuePush(ctxt, arg1); 13294 xmlXPathReleaseObject(ctxt->context, arg2); 13295 return (total); 13296 case XPATH_OP_ROOT: 13297 xmlXPathRoot(ctxt); 13298 return (total); 13299 case XPATH_OP_NODE: 13300 if (op->ch1 != -1) 13301 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13302 CHECK_ERROR0; 13303 if (op->ch2 != -1) 13304 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13305 CHECK_ERROR0; 13306 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 13307 ctxt->context->node)); 13308 return (total); 13309 case XPATH_OP_RESET: 13310 if (op->ch1 != -1) 13311 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13312 CHECK_ERROR0; 13313 if (op->ch2 != -1) 13314 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13315 CHECK_ERROR0; 13316 ctxt->context->node = NULL; 13317 return (total); 13318 case XPATH_OP_COLLECT:{ 13319 if (op->ch1 == -1) 13320 return (total); 13321 13322 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13323 CHECK_ERROR0; 13324 13325 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); 13326 return (total); 13327 } 13328 case XPATH_OP_VALUE: 13329 valuePush(ctxt, 13330 xmlXPathCacheObjectCopy(ctxt->context, 13331 (xmlXPathObjectPtr) op->value4)); 13332 return (total); 13333 case XPATH_OP_VARIABLE:{ 13334 xmlXPathObjectPtr val; 13335 13336 if (op->ch1 != -1) 13337 total += 13338 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13339 if (op->value5 == NULL) { 13340 val = xmlXPathVariableLookup(ctxt->context, op->value4); 13341 if (val == NULL) { 13342 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13343 return(0); 13344 } 13345 valuePush(ctxt, val); 13346 } else { 13347 const xmlChar *URI; 13348 13349 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13350 if (URI == NULL) { 13351 xmlGenericError(xmlGenericErrorContext, 13352 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 13353 (char *) op->value4, (char *)op->value5); 13354 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13355 return (total); 13356 } 13357 val = xmlXPathVariableLookupNS(ctxt->context, 13358 op->value4, URI); 13359 if (val == NULL) { 13360 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 13361 return(0); 13362 } 13363 valuePush(ctxt, val); 13364 } 13365 return (total); 13366 } 13367 case XPATH_OP_FUNCTION:{ 13368 xmlXPathFunction func; 13369 const xmlChar *oldFunc, *oldFuncURI; 13370 int i; 13371 13372 if (op->ch1 != -1) 13373 total += 13374 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13375 if (ctxt->valueNr < op->value) { 13376 xmlGenericError(xmlGenericErrorContext, 13377 "xmlXPathCompOpEval: parameter error\n"); 13378 ctxt->error = XPATH_INVALID_OPERAND; 13379 return (total); 13380 } 13381 for (i = 0; i < op->value; i++) 13382 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13383 xmlGenericError(xmlGenericErrorContext, 13384 "xmlXPathCompOpEval: parameter error\n"); 13385 ctxt->error = XPATH_INVALID_OPERAND; 13386 return (total); 13387 } 13388 if (op->cache != NULL) 13389 XML_CAST_FPTR(func) = op->cache; 13390 else { 13391 const xmlChar *URI = NULL; 13392 13393 if (op->value5 == NULL) 13394 func = 13395 xmlXPathFunctionLookup(ctxt->context, 13396 op->value4); 13397 else { 13398 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13399 if (URI == NULL) { 13400 xmlGenericError(xmlGenericErrorContext, 13401 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13402 (char *)op->value4, (char *)op->value5); 13403 ctxt->error = XPATH_UNDEF_PREFIX_ERROR; 13404 return (total); 13405 } 13406 func = xmlXPathFunctionLookupNS(ctxt->context, 13407 op->value4, URI); 13408 } 13409 if (func == NULL) { 13410 xmlGenericError(xmlGenericErrorContext, 13411 "xmlXPathCompOpEval: function %s not found\n", 13412 (char *)op->value4); 13413 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13414 } 13415 op->cache = XML_CAST_FPTR(func); 13416 op->cacheURI = (void *) URI; 13417 } 13418 oldFunc = ctxt->context->function; 13419 oldFuncURI = ctxt->context->functionURI; 13420 ctxt->context->function = op->value4; 13421 ctxt->context->functionURI = op->cacheURI; 13422 func(ctxt, op->value); 13423 ctxt->context->function = oldFunc; 13424 ctxt->context->functionURI = oldFuncURI; 13425 return (total); 13426 } 13427 case XPATH_OP_ARG: 13428 bakd = ctxt->context->doc; 13429 bak = ctxt->context->node; 13430 pp = ctxt->context->proximityPosition; 13431 cs = ctxt->context->contextSize; 13432 if (op->ch1 != -1) 13433 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13434 ctxt->context->contextSize = cs; 13435 ctxt->context->proximityPosition = pp; 13436 ctxt->context->node = bak; 13437 ctxt->context->doc = bakd; 13438 CHECK_ERROR0; 13439 if (op->ch2 != -1) { 13440 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13441 ctxt->context->doc = bakd; 13442 ctxt->context->node = bak; 13443 CHECK_ERROR0; 13444 } 13445 return (total); 13446 case XPATH_OP_PREDICATE: 13447 case XPATH_OP_FILTER:{ 13448 xmlXPathObjectPtr res; 13449 xmlXPathObjectPtr obj, tmp; 13450 xmlNodeSetPtr newset = NULL; 13451 xmlNodeSetPtr oldset; 13452 xmlNodePtr oldnode; 13453 xmlDocPtr oldDoc; 13454 int i; 13455 13456 /* 13457 * Optimization for ()[1] selection i.e. the first elem 13458 */ 13459 if ((op->ch1 != -1) && (op->ch2 != -1) && 13460#ifdef XP_OPTIMIZED_FILTER_FIRST 13461 /* 13462 * FILTER TODO: Can we assume that the inner processing 13463 * will result in an ordered list if we have an 13464 * XPATH_OP_FILTER? 13465 * What about an additional field or flag on 13466 * xmlXPathObject like @sorted ? This way we wouln'd need 13467 * to assume anything, so it would be more robust and 13468 * easier to optimize. 13469 */ 13470 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13471 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13472#else 13473 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13474#endif 13475 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13476 xmlXPathObjectPtr val; 13477 13478 val = comp->steps[op->ch2].value4; 13479 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13480 (val->floatval == 1.0)) { 13481 xmlNodePtr first = NULL; 13482 13483 total += 13484 xmlXPathCompOpEvalFirst(ctxt, 13485 &comp->steps[op->ch1], 13486 &first); 13487 CHECK_ERROR0; 13488 /* 13489 * The nodeset should be in document order, 13490 * Keep only the first value 13491 */ 13492 if ((ctxt->value != NULL) && 13493 (ctxt->value->type == XPATH_NODESET) && 13494 (ctxt->value->nodesetval != NULL) && 13495 (ctxt->value->nodesetval->nodeNr > 1)) 13496 ctxt->value->nodesetval->nodeNr = 1; 13497 return (total); 13498 } 13499 } 13500 /* 13501 * Optimization for ()[last()] selection i.e. the last elem 13502 */ 13503 if ((op->ch1 != -1) && (op->ch2 != -1) && 13504 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13505 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13506 int f = comp->steps[op->ch2].ch1; 13507 13508 if ((f != -1) && 13509 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13510 (comp->steps[f].value5 == NULL) && 13511 (comp->steps[f].value == 0) && 13512 (comp->steps[f].value4 != NULL) && 13513 (xmlStrEqual 13514 (comp->steps[f].value4, BAD_CAST "last"))) { 13515 xmlNodePtr last = NULL; 13516 13517 total += 13518 xmlXPathCompOpEvalLast(ctxt, 13519 &comp->steps[op->ch1], 13520 &last); 13521 CHECK_ERROR0; 13522 /* 13523 * The nodeset should be in document order, 13524 * Keep only the last value 13525 */ 13526 if ((ctxt->value != NULL) && 13527 (ctxt->value->type == XPATH_NODESET) && 13528 (ctxt->value->nodesetval != NULL) && 13529 (ctxt->value->nodesetval->nodeTab != NULL) && 13530 (ctxt->value->nodesetval->nodeNr > 1)) { 13531 ctxt->value->nodesetval->nodeTab[0] = 13532 ctxt->value->nodesetval->nodeTab[ctxt-> 13533 value-> 13534 nodesetval-> 13535 nodeNr - 13536 1]; 13537 ctxt->value->nodesetval->nodeNr = 1; 13538 } 13539 return (total); 13540 } 13541 } 13542 /* 13543 * Process inner predicates first. 13544 * Example "index[parent::book][1]": 13545 * ... 13546 * PREDICATE <-- we are here "[1]" 13547 * PREDICATE <-- process "[parent::book]" first 13548 * SORT 13549 * COLLECT 'parent' 'name' 'node' book 13550 * NODE 13551 * ELEM Object is a number : 1 13552 */ 13553 if (op->ch1 != -1) 13554 total += 13555 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13556 CHECK_ERROR0; 13557 if (op->ch2 == -1) 13558 return (total); 13559 if (ctxt->value == NULL) 13560 return (total); 13561 13562 oldnode = ctxt->context->node; 13563 13564#ifdef LIBXML_XPTR_ENABLED 13565 /* 13566 * Hum are we filtering the result of an XPointer expression 13567 */ 13568 if (ctxt->value->type == XPATH_LOCATIONSET) { 13569 xmlLocationSetPtr newlocset = NULL; 13570 xmlLocationSetPtr oldlocset; 13571 13572 /* 13573 * Extract the old locset, and then evaluate the result of the 13574 * expression for all the element in the locset. use it to grow 13575 * up a new locset. 13576 */ 13577 CHECK_TYPE0(XPATH_LOCATIONSET); 13578 obj = valuePop(ctxt); 13579 oldlocset = obj->user; 13580 ctxt->context->node = NULL; 13581 13582 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13583 ctxt->context->contextSize = 0; 13584 ctxt->context->proximityPosition = 0; 13585 if (op->ch2 != -1) 13586 total += 13587 xmlXPathCompOpEval(ctxt, 13588 &comp->steps[op->ch2]); 13589 res = valuePop(ctxt); 13590 if (res != NULL) { 13591 xmlXPathReleaseObject(ctxt->context, res); 13592 } 13593 valuePush(ctxt, obj); 13594 CHECK_ERROR0; 13595 return (total); 13596 } 13597 newlocset = xmlXPtrLocationSetCreate(NULL); 13598 13599 for (i = 0; i < oldlocset->locNr; i++) { 13600 /* 13601 * Run the evaluation with a node list made of a 13602 * single item in the nodelocset. 13603 */ 13604 ctxt->context->node = oldlocset->locTab[i]->user; 13605 ctxt->context->contextSize = oldlocset->locNr; 13606 ctxt->context->proximityPosition = i + 1; 13607 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13608 ctxt->context->node); 13609 valuePush(ctxt, tmp); 13610 13611 if (op->ch2 != -1) 13612 total += 13613 xmlXPathCompOpEval(ctxt, 13614 &comp->steps[op->ch2]); 13615 if (ctxt->error != XPATH_EXPRESSION_OK) { 13616 xmlXPathFreeObject(obj); 13617 return(0); 13618 } 13619 13620 /* 13621 * The result of the evaluation need to be tested to 13622 * decided whether the filter succeeded or not 13623 */ 13624 res = valuePop(ctxt); 13625 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13626 xmlXPtrLocationSetAdd(newlocset, 13627 xmlXPathObjectCopy 13628 (oldlocset->locTab[i])); 13629 } 13630 13631 /* 13632 * Cleanup 13633 */ 13634 if (res != NULL) { 13635 xmlXPathReleaseObject(ctxt->context, res); 13636 } 13637 if (ctxt->value == tmp) { 13638 res = valuePop(ctxt); 13639 xmlXPathReleaseObject(ctxt->context, res); 13640 } 13641 13642 ctxt->context->node = NULL; 13643 } 13644 13645 /* 13646 * The result is used as the new evaluation locset. 13647 */ 13648 xmlXPathReleaseObject(ctxt->context, obj); 13649 ctxt->context->node = NULL; 13650 ctxt->context->contextSize = -1; 13651 ctxt->context->proximityPosition = -1; 13652 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13653 ctxt->context->node = oldnode; 13654 return (total); 13655 } 13656#endif /* LIBXML_XPTR_ENABLED */ 13657 13658 /* 13659 * Extract the old set, and then evaluate the result of the 13660 * expression for all the element in the set. use it to grow 13661 * up a new set. 13662 */ 13663 CHECK_TYPE0(XPATH_NODESET); 13664 obj = valuePop(ctxt); 13665 oldset = obj->nodesetval; 13666 13667 oldnode = ctxt->context->node; 13668 oldDoc = ctxt->context->doc; 13669 ctxt->context->node = NULL; 13670 13671 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13672 ctxt->context->contextSize = 0; 13673 ctxt->context->proximityPosition = 0; 13674/* 13675 if (op->ch2 != -1) 13676 total += 13677 xmlXPathCompOpEval(ctxt, 13678 &comp->steps[op->ch2]); 13679 CHECK_ERROR0; 13680 res = valuePop(ctxt); 13681 if (res != NULL) 13682 xmlXPathFreeObject(res); 13683*/ 13684 valuePush(ctxt, obj); 13685 ctxt->context->node = oldnode; 13686 CHECK_ERROR0; 13687 } else { 13688 tmp = NULL; 13689 /* 13690 * Initialize the new set. 13691 * Also set the xpath document in case things like 13692 * key() evaluation are attempted on the predicate 13693 */ 13694 newset = xmlXPathNodeSetCreate(NULL); 13695 /* 13696 * SPEC XPath 1.0: 13697 * "For each node in the node-set to be filtered, the 13698 * PredicateExpr is evaluated with that node as the 13699 * context node, with the number of nodes in the 13700 * node-set as the context size, and with the proximity 13701 * position of the node in the node-set with respect to 13702 * the axis as the context position;" 13703 * @oldset is the node-set" to be filtered. 13704 * 13705 * SPEC XPath 1.0: 13706 * "only predicates change the context position and 13707 * context size (see [2.4 Predicates])." 13708 * Example: 13709 * node-set context pos 13710 * nA 1 13711 * nB 2 13712 * nC 3 13713 * After applying predicate [position() > 1] : 13714 * node-set context pos 13715 * nB 1 13716 * nC 2 13717 * 13718 * removed the first node in the node-set, then 13719 * the context position of the 13720 */ 13721 for (i = 0; i < oldset->nodeNr; i++) { 13722 /* 13723 * Run the evaluation with a node list made of 13724 * a single item in the nodeset. 13725 */ 13726 ctxt->context->node = oldset->nodeTab[i]; 13727 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13728 (oldset->nodeTab[i]->doc != NULL)) 13729 ctxt->context->doc = oldset->nodeTab[i]->doc; 13730 if (tmp == NULL) { 13731 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13732 ctxt->context->node); 13733 } else { 13734 xmlXPathNodeSetAddUnique(tmp->nodesetval, 13735 ctxt->context->node); 13736 } 13737 valuePush(ctxt, tmp); 13738 ctxt->context->contextSize = oldset->nodeNr; 13739 ctxt->context->proximityPosition = i + 1; 13740 /* 13741 * Evaluate the predicate against the context node. 13742 * Can/should we optimize position() predicates 13743 * here (e.g. "[1]")? 13744 */ 13745 if (op->ch2 != -1) 13746 total += 13747 xmlXPathCompOpEval(ctxt, 13748 &comp->steps[op->ch2]); 13749 if (ctxt->error != XPATH_EXPRESSION_OK) { 13750 xmlXPathFreeNodeSet(newset); 13751 xmlXPathFreeObject(obj); 13752 return(0); 13753 } 13754 13755 /* 13756 * The result of the evaluation needs to be tested to 13757 * decide whether the filter succeeded or not 13758 */ 13759 /* 13760 * OPTIMIZE TODO: Can we use 13761 * xmlXPathNodeSetAdd*Unique()* instead? 13762 */ 13763 res = valuePop(ctxt); 13764 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13765 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 13766 } 13767 13768 /* 13769 * Cleanup 13770 */ 13771 if (res != NULL) { 13772 xmlXPathReleaseObject(ctxt->context, res); 13773 } 13774 if (ctxt->value == tmp) { 13775 valuePop(ctxt); 13776 xmlXPathNodeSetClear(tmp->nodesetval, 1); 13777 /* 13778 * Don't free the temporary nodeset 13779 * in order to avoid massive recreation inside this 13780 * loop. 13781 */ 13782 } else 13783 tmp = NULL; 13784 ctxt->context->node = NULL; 13785 } 13786 if (tmp != NULL) 13787 xmlXPathReleaseObject(ctxt->context, tmp); 13788 /* 13789 * The result is used as the new evaluation set. 13790 */ 13791 xmlXPathReleaseObject(ctxt->context, obj); 13792 ctxt->context->node = NULL; 13793 ctxt->context->contextSize = -1; 13794 ctxt->context->proximityPosition = -1; 13795 /* may want to move this past the '}' later */ 13796 ctxt->context->doc = oldDoc; 13797 valuePush(ctxt, 13798 xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13799 } 13800 ctxt->context->node = oldnode; 13801 return (total); 13802 } 13803 case XPATH_OP_SORT: 13804 if (op->ch1 != -1) 13805 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13806 CHECK_ERROR0; 13807 if ((ctxt->value != NULL) && 13808 (ctxt->value->type == XPATH_NODESET) && 13809 (ctxt->value->nodesetval != NULL) && 13810 (ctxt->value->nodesetval->nodeNr > 1)) 13811 { 13812 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13813 } 13814 return (total); 13815#ifdef LIBXML_XPTR_ENABLED 13816 case XPATH_OP_RANGETO:{ 13817 xmlXPathObjectPtr range; 13818 xmlXPathObjectPtr res, obj; 13819 xmlXPathObjectPtr tmp; 13820 xmlLocationSetPtr newlocset = NULL; 13821 xmlLocationSetPtr oldlocset; 13822 xmlNodeSetPtr oldset; 13823 int i, j; 13824 13825 if (op->ch1 != -1) 13826 total += 13827 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13828 if (op->ch2 == -1) 13829 return (total); 13830 13831 if (ctxt->value->type == XPATH_LOCATIONSET) { 13832 /* 13833 * Extract the old locset, and then evaluate the result of the 13834 * expression for all the element in the locset. use it to grow 13835 * up a new locset. 13836 */ 13837 CHECK_TYPE0(XPATH_LOCATIONSET); 13838 obj = valuePop(ctxt); 13839 oldlocset = obj->user; 13840 13841 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13842 ctxt->context->node = NULL; 13843 ctxt->context->contextSize = 0; 13844 ctxt->context->proximityPosition = 0; 13845 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); 13846 res = valuePop(ctxt); 13847 if (res != NULL) { 13848 xmlXPathReleaseObject(ctxt->context, res); 13849 } 13850 valuePush(ctxt, obj); 13851 CHECK_ERROR0; 13852 return (total); 13853 } 13854 newlocset = xmlXPtrLocationSetCreate(NULL); 13855 13856 for (i = 0; i < oldlocset->locNr; i++) { 13857 /* 13858 * Run the evaluation with a node list made of a 13859 * single item in the nodelocset. 13860 */ 13861 ctxt->context->node = oldlocset->locTab[i]->user; 13862 ctxt->context->contextSize = oldlocset->locNr; 13863 ctxt->context->proximityPosition = i + 1; 13864 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13865 ctxt->context->node); 13866 valuePush(ctxt, tmp); 13867 13868 if (op->ch2 != -1) 13869 total += 13870 xmlXPathCompOpEval(ctxt, 13871 &comp->steps[op->ch2]); 13872 if (ctxt->error != XPATH_EXPRESSION_OK) { 13873 xmlXPathFreeObject(obj); 13874 return(0); 13875 } 13876 13877 res = valuePop(ctxt); 13878 if (res->type == XPATH_LOCATIONSET) { 13879 xmlLocationSetPtr rloc = 13880 (xmlLocationSetPtr)res->user; 13881 for (j=0; j<rloc->locNr; j++) { 13882 range = xmlXPtrNewRange( 13883 oldlocset->locTab[i]->user, 13884 oldlocset->locTab[i]->index, 13885 rloc->locTab[j]->user2, 13886 rloc->locTab[j]->index2); 13887 if (range != NULL) { 13888 xmlXPtrLocationSetAdd(newlocset, range); 13889 } 13890 } 13891 } else { 13892 range = xmlXPtrNewRangeNodeObject( 13893 (xmlNodePtr)oldlocset->locTab[i]->user, res); 13894 if (range != NULL) { 13895 xmlXPtrLocationSetAdd(newlocset,range); 13896 } 13897 } 13898 13899 /* 13900 * Cleanup 13901 */ 13902 if (res != NULL) { 13903 xmlXPathReleaseObject(ctxt->context, res); 13904 } 13905 if (ctxt->value == tmp) { 13906 res = valuePop(ctxt); 13907 xmlXPathReleaseObject(ctxt->context, res); 13908 } 13909 13910 ctxt->context->node = NULL; 13911 } 13912 } else { /* Not a location set */ 13913 CHECK_TYPE0(XPATH_NODESET); 13914 obj = valuePop(ctxt); 13915 oldset = obj->nodesetval; 13916 ctxt->context->node = NULL; 13917 13918 newlocset = xmlXPtrLocationSetCreate(NULL); 13919 13920 if (oldset != NULL) { 13921 for (i = 0; i < oldset->nodeNr; i++) { 13922 /* 13923 * Run the evaluation with a node list made of a single item 13924 * in the nodeset. 13925 */ 13926 ctxt->context->node = oldset->nodeTab[i]; 13927 /* 13928 * OPTIMIZE TODO: Avoid recreation for every iteration. 13929 */ 13930 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13931 ctxt->context->node); 13932 valuePush(ctxt, tmp); 13933 13934 if (op->ch2 != -1) 13935 total += 13936 xmlXPathCompOpEval(ctxt, 13937 &comp->steps[op->ch2]); 13938 if (ctxt->error != XPATH_EXPRESSION_OK) { 13939 xmlXPathFreeObject(obj); 13940 return(0); 13941 } 13942 13943 res = valuePop(ctxt); 13944 range = 13945 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 13946 res); 13947 if (range != NULL) { 13948 xmlXPtrLocationSetAdd(newlocset, range); 13949 } 13950 13951 /* 13952 * Cleanup 13953 */ 13954 if (res != NULL) { 13955 xmlXPathReleaseObject(ctxt->context, res); 13956 } 13957 if (ctxt->value == tmp) { 13958 res = valuePop(ctxt); 13959 xmlXPathReleaseObject(ctxt->context, res); 13960 } 13961 13962 ctxt->context->node = NULL; 13963 } 13964 } 13965 } 13966 13967 /* 13968 * The result is used as the new evaluation set. 13969 */ 13970 xmlXPathReleaseObject(ctxt->context, obj); 13971 ctxt->context->node = NULL; 13972 ctxt->context->contextSize = -1; 13973 ctxt->context->proximityPosition = -1; 13974 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13975 return (total); 13976 } 13977#endif /* LIBXML_XPTR_ENABLED */ 13978 } 13979 xmlGenericError(xmlGenericErrorContext, 13980 "XPath: unknown precompiled operation %d\n", op->op); 13981 return (total); 13982} 13983 13984/** 13985 * xmlXPathCompOpEvalToBoolean: 13986 * @ctxt: the XPath parser context 13987 * 13988 * Evaluates if the expression evaluates to true. 13989 * 13990 * Returns 1 if true, 0 if false and -1 on API or internal errors. 13991 */ 13992static int 13993xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 13994 xmlXPathStepOpPtr op, 13995 int isPredicate) 13996{ 13997 xmlXPathObjectPtr resObj = NULL; 13998 13999start: 14000 /* comp = ctxt->comp; */ 14001 switch (op->op) { 14002 case XPATH_OP_END: 14003 return (0); 14004 case XPATH_OP_VALUE: 14005 resObj = (xmlXPathObjectPtr) op->value4; 14006 if (isPredicate) 14007 return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); 14008 return(xmlXPathCastToBoolean(resObj)); 14009 case XPATH_OP_SORT: 14010 /* 14011 * We don't need sorting for boolean results. Skip this one. 14012 */ 14013 if (op->ch1 != -1) { 14014 op = &ctxt->comp->steps[op->ch1]; 14015 goto start; 14016 } 14017 return(0); 14018 case XPATH_OP_COLLECT: 14019 if (op->ch1 == -1) 14020 return(0); 14021 14022 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); 14023 if (ctxt->error != XPATH_EXPRESSION_OK) 14024 return(-1); 14025 14026 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); 14027 if (ctxt->error != XPATH_EXPRESSION_OK) 14028 return(-1); 14029 14030 resObj = valuePop(ctxt); 14031 if (resObj == NULL) 14032 return(-1); 14033 break; 14034 default: 14035 /* 14036 * Fallback to call xmlXPathCompOpEval(). 14037 */ 14038 xmlXPathCompOpEval(ctxt, op); 14039 if (ctxt->error != XPATH_EXPRESSION_OK) 14040 return(-1); 14041 14042 resObj = valuePop(ctxt); 14043 if (resObj == NULL) 14044 return(-1); 14045 break; 14046 } 14047 14048 if (resObj) { 14049 int res; 14050 14051 if (resObj->type == XPATH_BOOLEAN) { 14052 res = resObj->boolval; 14053 } else if (isPredicate) { 14054 /* 14055 * For predicates a result of type "number" is handled 14056 * differently: 14057 * SPEC XPath 1.0: 14058 * "If the result is a number, the result will be converted 14059 * to true if the number is equal to the context position 14060 * and will be converted to false otherwise;" 14061 */ 14062 res = xmlXPathEvaluatePredicateResult(ctxt, resObj); 14063 } else { 14064 res = xmlXPathCastToBoolean(resObj); 14065 } 14066 xmlXPathReleaseObject(ctxt->context, resObj); 14067 return(res); 14068 } 14069 14070 return(0); 14071} 14072 14073#ifdef XPATH_STREAMING 14074/** 14075 * xmlXPathRunStreamEval: 14076 * @ctxt: the XPath parser context with the compiled expression 14077 * 14078 * Evaluate the Precompiled Streamable XPath expression in the given context. 14079 */ 14080static int 14081xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, 14082 xmlXPathObjectPtr *resultSeq, int toBool) 14083{ 14084 int max_depth, min_depth; 14085 int from_root; 14086 int ret, depth; 14087 int eval_all_nodes; 14088 xmlNodePtr cur = NULL, limit = NULL; 14089 xmlStreamCtxtPtr patstream = NULL; 14090 14091 int nb_nodes = 0; 14092 14093 if ((ctxt == NULL) || (comp == NULL)) 14094 return(-1); 14095 max_depth = xmlPatternMaxDepth(comp); 14096 if (max_depth == -1) 14097 return(-1); 14098 if (max_depth == -2) 14099 max_depth = 10000; 14100 min_depth = xmlPatternMinDepth(comp); 14101 if (min_depth == -1) 14102 return(-1); 14103 from_root = xmlPatternFromRoot(comp); 14104 if (from_root < 0) 14105 return(-1); 14106#if 0 14107 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 14108#endif 14109 14110 if (! toBool) { 14111 if (resultSeq == NULL) 14112 return(-1); 14113 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); 14114 if (*resultSeq == NULL) 14115 return(-1); 14116 } 14117 14118 /* 14119 * handle the special cases of "/" amd "." being matched 14120 */ 14121 if (min_depth == 0) { 14122 if (from_root) { 14123 /* Select "/" */ 14124 if (toBool) 14125 return(1); 14126 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, 14127 (xmlNodePtr) ctxt->doc); 14128 } else { 14129 /* Select "self::node()" */ 14130 if (toBool) 14131 return(1); 14132 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); 14133 } 14134 } 14135 if (max_depth == 0) { 14136 return(0); 14137 } 14138 14139 if (from_root) { 14140 cur = (xmlNodePtr)ctxt->doc; 14141 } else if (ctxt->node != NULL) { 14142 switch (ctxt->node->type) { 14143 case XML_ELEMENT_NODE: 14144 case XML_DOCUMENT_NODE: 14145 case XML_DOCUMENT_FRAG_NODE: 14146 case XML_HTML_DOCUMENT_NODE: 14147#ifdef LIBXML_DOCB_ENABLED 14148 case XML_DOCB_DOCUMENT_NODE: 14149#endif 14150 cur = ctxt->node; 14151 break; 14152 case XML_ATTRIBUTE_NODE: 14153 case XML_TEXT_NODE: 14154 case XML_CDATA_SECTION_NODE: 14155 case XML_ENTITY_REF_NODE: 14156 case XML_ENTITY_NODE: 14157 case XML_PI_NODE: 14158 case XML_COMMENT_NODE: 14159 case XML_NOTATION_NODE: 14160 case XML_DTD_NODE: 14161 case XML_DOCUMENT_TYPE_NODE: 14162 case XML_ELEMENT_DECL: 14163 case XML_ATTRIBUTE_DECL: 14164 case XML_ENTITY_DECL: 14165 case XML_NAMESPACE_DECL: 14166 case XML_XINCLUDE_START: 14167 case XML_XINCLUDE_END: 14168 break; 14169 } 14170 limit = cur; 14171 } 14172 if (cur == NULL) { 14173 return(0); 14174 } 14175 14176 patstream = xmlPatternGetStreamCtxt(comp); 14177 if (patstream == NULL) { 14178 /* 14179 * QUESTION TODO: Is this an error? 14180 */ 14181 return(0); 14182 } 14183 14184 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 14185 14186 if (from_root) { 14187 ret = xmlStreamPush(patstream, NULL, NULL); 14188 if (ret < 0) { 14189 } else if (ret == 1) { 14190 if (toBool) 14191 goto return_1; 14192 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14193 } 14194 } 14195 depth = 0; 14196 goto scan_children; 14197next_node: 14198 do { 14199 nb_nodes++; 14200 14201 switch (cur->type) { 14202 case XML_ELEMENT_NODE: 14203 case XML_TEXT_NODE: 14204 case XML_CDATA_SECTION_NODE: 14205 case XML_COMMENT_NODE: 14206 case XML_PI_NODE: 14207 if (cur->type == XML_ELEMENT_NODE) { 14208 ret = xmlStreamPush(patstream, cur->name, 14209 (cur->ns ? cur->ns->href : NULL)); 14210 } else if (eval_all_nodes) 14211 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 14212 else 14213 break; 14214 14215 if (ret < 0) { 14216 /* NOP. */ 14217 } else if (ret == 1) { 14218 if (toBool) 14219 goto return_1; 14220 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); 14221 } 14222 if ((cur->children == NULL) || (depth >= max_depth)) { 14223 ret = xmlStreamPop(patstream); 14224 while (cur->next != NULL) { 14225 cur = cur->next; 14226 if ((cur->type != XML_ENTITY_DECL) && 14227 (cur->type != XML_DTD_NODE)) 14228 goto next_node; 14229 } 14230 } 14231 default: 14232 break; 14233 } 14234 14235scan_children: 14236 if ((cur->children != NULL) && (depth < max_depth)) { 14237 /* 14238 * Do not descend on entities declarations 14239 */ 14240 if (cur->children->type != XML_ENTITY_DECL) { 14241 cur = cur->children; 14242 depth++; 14243 /* 14244 * Skip DTDs 14245 */ 14246 if (cur->type != XML_DTD_NODE) 14247 continue; 14248 } 14249 } 14250 14251 if (cur == limit) 14252 break; 14253 14254 while (cur->next != NULL) { 14255 cur = cur->next; 14256 if ((cur->type != XML_ENTITY_DECL) && 14257 (cur->type != XML_DTD_NODE)) 14258 goto next_node; 14259 } 14260 14261 do { 14262 cur = cur->parent; 14263 depth--; 14264 if ((cur == NULL) || (cur == limit)) 14265 goto done; 14266 if (cur->type == XML_ELEMENT_NODE) { 14267 ret = xmlStreamPop(patstream); 14268 } else if ((eval_all_nodes) && 14269 ((cur->type == XML_TEXT_NODE) || 14270 (cur->type == XML_CDATA_SECTION_NODE) || 14271 (cur->type == XML_COMMENT_NODE) || 14272 (cur->type == XML_PI_NODE))) 14273 { 14274 ret = xmlStreamPop(patstream); 14275 } 14276 if (cur->next != NULL) { 14277 cur = cur->next; 14278 break; 14279 } 14280 } while (cur != NULL); 14281 14282 } while ((cur != NULL) && (depth >= 0)); 14283 14284done: 14285 14286#if 0 14287 printf("stream eval: checked %d nodes selected %d\n", 14288 nb_nodes, retObj->nodesetval->nodeNr); 14289#endif 14290 14291 if (patstream) 14292 xmlFreeStreamCtxt(patstream); 14293 return(0); 14294 14295return_1: 14296 if (patstream) 14297 xmlFreeStreamCtxt(patstream); 14298 return(1); 14299} 14300#endif /* XPATH_STREAMING */ 14301 14302/** 14303 * xmlXPathRunEval: 14304 * @ctxt: the XPath parser context with the compiled expression 14305 * @toBool: evaluate to a boolean result 14306 * 14307 * Evaluate the Precompiled XPath expression in the given context. 14308 */ 14309static int 14310xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) 14311{ 14312 xmlXPathCompExprPtr comp; 14313 14314 if ((ctxt == NULL) || (ctxt->comp == NULL)) 14315 return(-1); 14316 14317 if (ctxt->valueTab == NULL) { 14318 /* Allocate the value stack */ 14319 ctxt->valueTab = (xmlXPathObjectPtr *) 14320 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 14321 if (ctxt->valueTab == NULL) { 14322 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 14323 xmlFree(ctxt); 14324 } 14325 ctxt->valueNr = 0; 14326 ctxt->valueMax = 10; 14327 ctxt->value = NULL; 14328 } 14329#ifdef XPATH_STREAMING 14330 if (ctxt->comp->stream) { 14331 int res; 14332 14333 if (toBool) { 14334 /* 14335 * Evaluation to boolean result. 14336 */ 14337 res = xmlXPathRunStreamEval(ctxt->context, 14338 ctxt->comp->stream, NULL, 1); 14339 if (res != -1) 14340 return(res); 14341 } else { 14342 xmlXPathObjectPtr resObj = NULL; 14343 14344 /* 14345 * Evaluation to a sequence. 14346 */ 14347 res = xmlXPathRunStreamEval(ctxt->context, 14348 ctxt->comp->stream, &resObj, 0); 14349 14350 if ((res != -1) && (resObj != NULL)) { 14351 valuePush(ctxt, resObj); 14352 return(0); 14353 } 14354 if (resObj != NULL) 14355 xmlXPathReleaseObject(ctxt->context, resObj); 14356 } 14357 /* 14358 * QUESTION TODO: This falls back to normal XPath evaluation 14359 * if res == -1. Is this intended? 14360 */ 14361 } 14362#endif 14363 comp = ctxt->comp; 14364 if (comp->last < 0) { 14365 xmlGenericError(xmlGenericErrorContext, 14366 "xmlXPathRunEval: last is less than zero\n"); 14367 return(-1); 14368 } 14369 if (toBool) 14370 return(xmlXPathCompOpEvalToBoolean(ctxt, 14371 &comp->steps[comp->last], 0)); 14372 else 14373 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 14374 14375 return(0); 14376} 14377 14378/************************************************************************ 14379 * * 14380 * Public interfaces * 14381 * * 14382 ************************************************************************/ 14383 14384/** 14385 * xmlXPathEvalPredicate: 14386 * @ctxt: the XPath context 14387 * @res: the Predicate Expression evaluation result 14388 * 14389 * Evaluate a predicate result for the current node. 14390 * A PredicateExpr is evaluated by evaluating the Expr and converting 14391 * the result to a boolean. If the result is a number, the result will 14392 * be converted to true if the number is equal to the position of the 14393 * context node in the context node list (as returned by the position 14394 * function) and will be converted to false otherwise; if the result 14395 * is not a number, then the result will be converted as if by a call 14396 * to the boolean function. 14397 * 14398 * Returns 1 if predicate is true, 0 otherwise 14399 */ 14400int 14401xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 14402 if ((ctxt == NULL) || (res == NULL)) return(0); 14403 switch (res->type) { 14404 case XPATH_BOOLEAN: 14405 return(res->boolval); 14406 case XPATH_NUMBER: 14407 return(res->floatval == ctxt->proximityPosition); 14408 case XPATH_NODESET: 14409 case XPATH_XSLT_TREE: 14410 if (res->nodesetval == NULL) 14411 return(0); 14412 return(res->nodesetval->nodeNr != 0); 14413 case XPATH_STRING: 14414 return((res->stringval != NULL) && 14415 (xmlStrlen(res->stringval) != 0)); 14416 default: 14417 STRANGE 14418 } 14419 return(0); 14420} 14421 14422/** 14423 * xmlXPathEvaluatePredicateResult: 14424 * @ctxt: the XPath Parser context 14425 * @res: the Predicate Expression evaluation result 14426 * 14427 * Evaluate a predicate result for the current node. 14428 * A PredicateExpr is evaluated by evaluating the Expr and converting 14429 * the result to a boolean. If the result is a number, the result will 14430 * be converted to true if the number is equal to the position of the 14431 * context node in the context node list (as returned by the position 14432 * function) and will be converted to false otherwise; if the result 14433 * is not a number, then the result will be converted as if by a call 14434 * to the boolean function. 14435 * 14436 * Returns 1 if predicate is true, 0 otherwise 14437 */ 14438int 14439xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 14440 xmlXPathObjectPtr res) { 14441 if ((ctxt == NULL) || (res == NULL)) return(0); 14442 switch (res->type) { 14443 case XPATH_BOOLEAN: 14444 return(res->boolval); 14445 case XPATH_NUMBER: 14446#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 14447 return((res->floatval == ctxt->context->proximityPosition) && 14448 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 14449#else 14450 return(res->floatval == ctxt->context->proximityPosition); 14451#endif 14452 case XPATH_NODESET: 14453 case XPATH_XSLT_TREE: 14454 if (res->nodesetval == NULL) 14455 return(0); 14456 return(res->nodesetval->nodeNr != 0); 14457 case XPATH_STRING: 14458 return((res->stringval != NULL) && (res->stringval[0] != 0)); 14459#ifdef LIBXML_XPTR_ENABLED 14460 case XPATH_LOCATIONSET:{ 14461 xmlLocationSetPtr ptr = res->user; 14462 if (ptr == NULL) 14463 return(0); 14464 return (ptr->locNr != 0); 14465 } 14466#endif 14467 default: 14468 STRANGE 14469 } 14470 return(0); 14471} 14472 14473#ifdef XPATH_STREAMING 14474/** 14475 * xmlXPathTryStreamCompile: 14476 * @ctxt: an XPath context 14477 * @str: the XPath expression 14478 * 14479 * Try to compile the XPath expression as a streamable subset. 14480 * 14481 * Returns the compiled expression or NULL if failed to compile. 14482 */ 14483static xmlXPathCompExprPtr 14484xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14485 /* 14486 * Optimization: use streaming patterns when the XPath expression can 14487 * be compiled to a stream lookup 14488 */ 14489 xmlPatternPtr stream; 14490 xmlXPathCompExprPtr comp; 14491 xmlDictPtr dict = NULL; 14492 const xmlChar **namespaces = NULL; 14493 xmlNsPtr ns; 14494 int i, j; 14495 14496 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 14497 (!xmlStrchr(str, '@'))) { 14498 const xmlChar *tmp; 14499 14500 /* 14501 * We don't try to handle expressions using the verbose axis 14502 * specifiers ("::"), just the simplied form at this point. 14503 * Additionally, if there is no list of namespaces available and 14504 * there's a ":" in the expression, indicating a prefixed QName, 14505 * then we won't try to compile either. xmlPatterncompile() needs 14506 * to have a list of namespaces at compilation time in order to 14507 * compile prefixed name tests. 14508 */ 14509 tmp = xmlStrchr(str, ':'); 14510 if ((tmp != NULL) && 14511 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 14512 return(NULL); 14513 14514 if (ctxt != NULL) { 14515 dict = ctxt->dict; 14516 if (ctxt->nsNr > 0) { 14517 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 14518 if (namespaces == NULL) { 14519 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14520 return(NULL); 14521 } 14522 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14523 ns = ctxt->namespaces[j]; 14524 namespaces[i++] = ns->href; 14525 namespaces[i++] = ns->prefix; 14526 } 14527 namespaces[i++] = NULL; 14528 namespaces[i] = NULL; 14529 } 14530 } 14531 14532 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14533 &namespaces[0]); 14534 if (namespaces != NULL) { 14535 xmlFree((xmlChar **)namespaces); 14536 } 14537 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14538 comp = xmlXPathNewCompExpr(); 14539 if (comp == NULL) { 14540 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14541 return(NULL); 14542 } 14543 comp->stream = stream; 14544 comp->dict = dict; 14545 if (comp->dict) 14546 xmlDictReference(comp->dict); 14547 return(comp); 14548 } 14549 xmlFreePattern(stream); 14550 } 14551 return(NULL); 14552} 14553#endif /* XPATH_STREAMING */ 14554 14555static int 14556xmlXPathCanRewriteDosExpression(xmlChar *expr) 14557{ 14558 if (expr == NULL) 14559 return(0); 14560 do { 14561 if ((*expr == '/') && (*(++expr) == '/')) 14562 return(1); 14563 } while (*expr++); 14564 return(0); 14565} 14566static void 14567xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) 14568{ 14569 /* 14570 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14571 * internal representation. 14572 */ 14573 if (op->ch1 != -1) { 14574 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14575 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) && 14576 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) && 14577 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */)) 14578 { 14579 /* 14580 * This is a "child::foo" 14581 */ 14582 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14583 14584 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14585 (prevop->ch1 != -1) && 14586 ((xmlXPathAxisVal) prevop->value == 14587 AXIS_DESCENDANT_OR_SELF) && 14588 (prevop->ch2 == -1) && 14589 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14590 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) && 14591 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT)) 14592 { 14593 /* 14594 * This is a "/descendant-or-self::node()" without predicates. 14595 * Eliminate it. 14596 */ 14597 op->ch1 = prevop->ch1; 14598 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM; 14599 } 14600 } 14601 if (op->ch1 != -1) 14602 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]); 14603 } 14604 if (op->ch2 != -1) 14605 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]); 14606} 14607 14608/** 14609 * xmlXPathCtxtCompile: 14610 * @ctxt: an XPath context 14611 * @str: the XPath expression 14612 * 14613 * Compile an XPath expression 14614 * 14615 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14616 * the caller has to free the object. 14617 */ 14618xmlXPathCompExprPtr 14619xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14620 xmlXPathParserContextPtr pctxt; 14621 xmlXPathCompExprPtr comp; 14622 14623#ifdef XPATH_STREAMING 14624 comp = xmlXPathTryStreamCompile(ctxt, str); 14625 if (comp != NULL) 14626 return(comp); 14627#endif 14628 14629 xmlXPathInit(); 14630 14631 pctxt = xmlXPathNewParserContext(str, ctxt); 14632 if (pctxt == NULL) 14633 return NULL; 14634 xmlXPathCompileExpr(pctxt, 1); 14635 14636 if( pctxt->error != XPATH_EXPRESSION_OK ) 14637 { 14638 xmlXPathFreeParserContext(pctxt); 14639 return(NULL); 14640 } 14641 14642 if (*pctxt->cur != 0) { 14643 /* 14644 * aleksey: in some cases this line prints *second* error message 14645 * (see bug #78858) and probably this should be fixed. 14646 * However, we are not sure that all error messages are printed 14647 * out in other places. It's not critical so we leave it as-is for now 14648 */ 14649 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14650 comp = NULL; 14651 } else { 14652 comp = pctxt->comp; 14653 pctxt->comp = NULL; 14654 } 14655 xmlXPathFreeParserContext(pctxt); 14656 14657 if (comp != NULL) { 14658 comp->expr = xmlStrdup(str); 14659#ifdef DEBUG_EVAL_COUNTS 14660 comp->string = xmlStrdup(str); 14661 comp->nb = 0; 14662#endif 14663 if ((comp->expr != NULL) && 14664 (comp->nbStep > 2) && 14665 (comp->last >= 0) && 14666 (xmlXPathCanRewriteDosExpression(comp->expr) == 1)) 14667 { 14668 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]); 14669 } 14670 } 14671 return(comp); 14672} 14673 14674/** 14675 * xmlXPathCompile: 14676 * @str: the XPath expression 14677 * 14678 * Compile an XPath expression 14679 * 14680 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14681 * the caller has to free the object. 14682 */ 14683xmlXPathCompExprPtr 14684xmlXPathCompile(const xmlChar *str) { 14685 return(xmlXPathCtxtCompile(NULL, str)); 14686} 14687 14688/** 14689 * xmlXPathCompiledEvalInternal: 14690 * @comp: the compiled XPath expression 14691 * @ctxt: the XPath context 14692 * @resObj: the resulting XPath object or NULL 14693 * @toBool: 1 if only a boolean result is requested 14694 * 14695 * Evaluate the Precompiled XPath expression in the given context. 14696 * The caller has to free @resObj. 14697 * 14698 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14699 * the caller has to free the object. 14700 */ 14701static int 14702xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, 14703 xmlXPathContextPtr ctxt, 14704 xmlXPathObjectPtr *resObj, 14705 int toBool) 14706{ 14707 xmlXPathParserContextPtr pctxt; 14708#ifndef LIBXML_THREAD_ENABLED 14709 static int reentance = 0; 14710#endif 14711 int res; 14712 14713 CHECK_CTXT_NEG(ctxt) 14714 14715 if (comp == NULL) 14716 return(-1); 14717 xmlXPathInit(); 14718 14719#ifndef LIBXML_THREAD_ENABLED 14720 reentance++; 14721 if (reentance > 1) 14722 xmlXPathDisableOptimizer = 1; 14723#endif 14724 14725#ifdef DEBUG_EVAL_COUNTS 14726 comp->nb++; 14727 if ((comp->string != NULL) && (comp->nb > 100)) { 14728 fprintf(stderr, "100 x %s\n", comp->string); 14729 comp->nb = 0; 14730 } 14731#endif 14732 pctxt = xmlXPathCompParserContext(comp, ctxt); 14733 res = xmlXPathRunEval(pctxt, toBool); 14734 14735 if (resObj) { 14736 if (pctxt->value == NULL) { 14737 xmlGenericError(xmlGenericErrorContext, 14738 "xmlXPathCompiledEval: evaluation failed\n"); 14739 *resObj = NULL; 14740 } else { 14741 *resObj = valuePop(pctxt); 14742 } 14743 } 14744 14745 /* 14746 * Pop all remaining objects from the stack. 14747 */ 14748 if (pctxt->valueNr > 0) { 14749 xmlXPathObjectPtr tmp; 14750 int stack = 0; 14751 14752 do { 14753 tmp = valuePop(pctxt); 14754 if (tmp != NULL) { 14755 stack++; 14756 xmlXPathReleaseObject(ctxt, tmp); 14757 } 14758 } while (tmp != NULL); 14759 if ((stack != 0) && 14760 ((toBool) || ((resObj) && (*resObj)))) 14761 { 14762 xmlGenericError(xmlGenericErrorContext, 14763 "xmlXPathCompiledEval: %d objects left on the stack.\n", 14764 stack); 14765 } 14766 } 14767 14768 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) { 14769 xmlXPathFreeObject(*resObj); 14770 *resObj = NULL; 14771 } 14772 pctxt->comp = NULL; 14773 xmlXPathFreeParserContext(pctxt); 14774#ifndef LIBXML_THREAD_ENABLED 14775 reentance--; 14776#endif 14777 14778 return(res); 14779} 14780 14781/** 14782 * xmlXPathCompiledEval: 14783 * @comp: the compiled XPath expression 14784 * @ctx: the XPath context 14785 * 14786 * Evaluate the Precompiled XPath expression in the given context. 14787 * 14788 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14789 * the caller has to free the object. 14790 */ 14791xmlXPathObjectPtr 14792xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) 14793{ 14794 xmlXPathObjectPtr res = NULL; 14795 14796 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); 14797 return(res); 14798} 14799 14800/** 14801 * xmlXPathCompiledEvalToBoolean: 14802 * @comp: the compiled XPath expression 14803 * @ctxt: the XPath context 14804 * 14805 * Applies the XPath boolean() function on the result of the given 14806 * compiled expression. 14807 * 14808 * Returns 1 if the expression evaluated to true, 0 if to false and 14809 * -1 in API and internal errors. 14810 */ 14811int 14812xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, 14813 xmlXPathContextPtr ctxt) 14814{ 14815 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); 14816} 14817 14818/** 14819 * xmlXPathEvalExpr: 14820 * @ctxt: the XPath Parser context 14821 * 14822 * Parse and evaluate an XPath expression in the given context, 14823 * then push the result on the context stack 14824 */ 14825void 14826xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14827#ifdef XPATH_STREAMING 14828 xmlXPathCompExprPtr comp; 14829#endif 14830 14831 if (ctxt == NULL) return; 14832 14833#ifdef XPATH_STREAMING 14834 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14835 if (comp != NULL) { 14836 if (ctxt->comp != NULL) 14837 xmlXPathFreeCompExpr(ctxt->comp); 14838 ctxt->comp = comp; 14839 if (ctxt->cur != NULL) 14840 while (*ctxt->cur != 0) ctxt->cur++; 14841 } else 14842#endif 14843 { 14844 xmlXPathCompileExpr(ctxt, 1); 14845 /* 14846 * In this scenario the expression string will sit in ctxt->base. 14847 */ 14848 if ((ctxt->error == XPATH_EXPRESSION_OK) && 14849 (ctxt->comp != NULL) && 14850 (ctxt->base != NULL) && 14851 (ctxt->comp->nbStep > 2) && 14852 (ctxt->comp->last >= 0) && 14853 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1)) 14854 { 14855 xmlXPathRewriteDOSExpression(ctxt->comp, 14856 &ctxt->comp->steps[ctxt->comp->last]); 14857 } 14858 } 14859 CHECK_ERROR; 14860 xmlXPathRunEval(ctxt, 0); 14861} 14862 14863/** 14864 * xmlXPathEval: 14865 * @str: the XPath expression 14866 * @ctx: the XPath context 14867 * 14868 * Evaluate the XPath Location Path in the given context. 14869 * 14870 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14871 * the caller has to free the object. 14872 */ 14873xmlXPathObjectPtr 14874xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 14875 xmlXPathParserContextPtr ctxt; 14876 xmlXPathObjectPtr res, tmp, init = NULL; 14877 int stack = 0; 14878 14879 CHECK_CTXT(ctx) 14880 14881 xmlXPathInit(); 14882 14883 ctxt = xmlXPathNewParserContext(str, ctx); 14884 if (ctxt == NULL) 14885 return NULL; 14886 xmlXPathEvalExpr(ctxt); 14887 14888 if (ctxt->value == NULL) { 14889 xmlGenericError(xmlGenericErrorContext, 14890 "xmlXPathEval: evaluation failed\n"); 14891 res = NULL; 14892 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL) 14893#ifdef XPATH_STREAMING 14894 && (ctxt->comp->stream == NULL) 14895#endif 14896 ) { 14897 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14898 res = NULL; 14899 } else { 14900 res = valuePop(ctxt); 14901 } 14902 14903 do { 14904 tmp = valuePop(ctxt); 14905 if (tmp != NULL) { 14906 if (tmp != init) 14907 stack++; 14908 xmlXPathReleaseObject(ctx, tmp); 14909 } 14910 } while (tmp != NULL); 14911 if ((stack != 0) && (res != NULL)) { 14912 xmlGenericError(xmlGenericErrorContext, 14913 "xmlXPathEval: %d object left on the stack\n", 14914 stack); 14915 } 14916 if (ctxt->error != XPATH_EXPRESSION_OK) { 14917 xmlXPathFreeObject(res); 14918 res = NULL; 14919 } 14920 14921 xmlXPathFreeParserContext(ctxt); 14922 return(res); 14923} 14924 14925/** 14926 * xmlXPathEvalExpression: 14927 * @str: the XPath expression 14928 * @ctxt: the XPath context 14929 * 14930 * Evaluate the XPath expression in the given context. 14931 * 14932 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14933 * the caller has to free the object. 14934 */ 14935xmlXPathObjectPtr 14936xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 14937 xmlXPathParserContextPtr pctxt; 14938 xmlXPathObjectPtr res, tmp; 14939 int stack = 0; 14940 14941 CHECK_CTXT(ctxt) 14942 14943 xmlXPathInit(); 14944 14945 pctxt = xmlXPathNewParserContext(str, ctxt); 14946 if (pctxt == NULL) 14947 return NULL; 14948 xmlXPathEvalExpr(pctxt); 14949 14950 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) { 14951 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14952 res = NULL; 14953 } else { 14954 res = valuePop(pctxt); 14955 } 14956 do { 14957 tmp = valuePop(pctxt); 14958 if (tmp != NULL) { 14959 xmlXPathReleaseObject(ctxt, tmp); 14960 stack++; 14961 } 14962 } while (tmp != NULL); 14963 if ((stack != 0) && (res != NULL)) { 14964 xmlGenericError(xmlGenericErrorContext, 14965 "xmlXPathEvalExpression: %d object left on the stack\n", 14966 stack); 14967 } 14968 xmlXPathFreeParserContext(pctxt); 14969 return(res); 14970} 14971 14972/************************************************************************ 14973 * * 14974 * Extra functions not pertaining to the XPath spec * 14975 * * 14976 ************************************************************************/ 14977/** 14978 * xmlXPathEscapeUriFunction: 14979 * @ctxt: the XPath Parser context 14980 * @nargs: the number of arguments 14981 * 14982 * Implement the escape-uri() XPath function 14983 * string escape-uri(string $str, bool $escape-reserved) 14984 * 14985 * This function applies the URI escaping rules defined in section 2 of [RFC 14986 * 2396] to the string supplied as $uri-part, which typically represents all 14987 * or part of a URI. The effect of the function is to replace any special 14988 * character in the string by an escape sequence of the form %xx%yy..., 14989 * where xxyy... is the hexadecimal representation of the octets used to 14990 * represent the character in UTF-8. 14991 * 14992 * The set of characters that are escaped depends on the setting of the 14993 * boolean argument $escape-reserved. 14994 * 14995 * If $escape-reserved is true, all characters are escaped other than lower 14996 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 14997 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 14998 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 14999 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 15000 * A-F). 15001 * 15002 * If $escape-reserved is false, the behavior differs in that characters 15003 * referred to in [RFC 2396] as reserved characters are not escaped. These 15004 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 15005 * 15006 * [RFC 2396] does not define whether escaped URIs should use lower case or 15007 * upper case for hexadecimal digits. To ensure that escaped URIs can be 15008 * compared using string comparison functions, this function must always use 15009 * the upper-case letters A-F. 15010 * 15011 * Generally, $escape-reserved should be set to true when escaping a string 15012 * that is to form a single part of a URI, and to false when escaping an 15013 * entire URI or URI reference. 15014 * 15015 * In the case of non-ascii characters, the string is encoded according to 15016 * utf-8 and then converted according to RFC 2396. 15017 * 15018 * Examples 15019 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 15020 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 15021 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 15022 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 15023 * 15024 */ 15025static void 15026xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 15027 xmlXPathObjectPtr str; 15028 int escape_reserved; 15029 xmlBufferPtr target; 15030 xmlChar *cptr; 15031 xmlChar escape[4]; 15032 15033 CHECK_ARITY(2); 15034 15035 escape_reserved = xmlXPathPopBoolean(ctxt); 15036 15037 CAST_TO_STRING; 15038 str = valuePop(ctxt); 15039 15040 target = xmlBufferCreate(); 15041 15042 escape[0] = '%'; 15043 escape[3] = 0; 15044 15045 if (target) { 15046 for (cptr = str->stringval; *cptr; cptr++) { 15047 if ((*cptr >= 'A' && *cptr <= 'Z') || 15048 (*cptr >= 'a' && *cptr <= 'z') || 15049 (*cptr >= '0' && *cptr <= '9') || 15050 *cptr == '-' || *cptr == '_' || *cptr == '.' || 15051 *cptr == '!' || *cptr == '~' || *cptr == '*' || 15052 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 15053 (*cptr == '%' && 15054 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 15055 (cptr[1] >= 'a' && cptr[1] <= 'f') || 15056 (cptr[1] >= '0' && cptr[1] <= '9')) && 15057 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 15058 (cptr[2] >= 'a' && cptr[2] <= 'f') || 15059 (cptr[2] >= '0' && cptr[2] <= '9'))) || 15060 (!escape_reserved && 15061 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 15062 *cptr == ':' || *cptr == '@' || *cptr == '&' || 15063 *cptr == '=' || *cptr == '+' || *cptr == '$' || 15064 *cptr == ','))) { 15065 xmlBufferAdd(target, cptr, 1); 15066 } else { 15067 if ((*cptr >> 4) < 10) 15068 escape[1] = '0' + (*cptr >> 4); 15069 else 15070 escape[1] = 'A' - 10 + (*cptr >> 4); 15071 if ((*cptr & 0xF) < 10) 15072 escape[2] = '0' + (*cptr & 0xF); 15073 else 15074 escape[2] = 'A' - 10 + (*cptr & 0xF); 15075 15076 xmlBufferAdd(target, &escape[0], 3); 15077 } 15078 } 15079 } 15080 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 15081 xmlBufferContent(target))); 15082 xmlBufferFree(target); 15083 xmlXPathReleaseObject(ctxt->context, str); 15084} 15085 15086/** 15087 * xmlXPathRegisterAllFunctions: 15088 * @ctxt: the XPath context 15089 * 15090 * Registers all default XPath functions in this context 15091 */ 15092void 15093xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 15094{ 15095 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 15096 xmlXPathBooleanFunction); 15097 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 15098 xmlXPathCeilingFunction); 15099 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 15100 xmlXPathCountFunction); 15101 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 15102 xmlXPathConcatFunction); 15103 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 15104 xmlXPathContainsFunction); 15105 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 15106 xmlXPathIdFunction); 15107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 15108 xmlXPathFalseFunction); 15109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 15110 xmlXPathFloorFunction); 15111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 15112 xmlXPathLastFunction); 15113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 15114 xmlXPathLangFunction); 15115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 15116 xmlXPathLocalNameFunction); 15117 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 15118 xmlXPathNotFunction); 15119 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 15120 xmlXPathNameFunction); 15121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 15122 xmlXPathNamespaceURIFunction); 15123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 15124 xmlXPathNormalizeFunction); 15125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 15126 xmlXPathNumberFunction); 15127 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 15128 xmlXPathPositionFunction); 15129 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 15130 xmlXPathRoundFunction); 15131 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 15132 xmlXPathStringFunction); 15133 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 15134 xmlXPathStringLengthFunction); 15135 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 15136 xmlXPathStartsWithFunction); 15137 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 15138 xmlXPathSubstringFunction); 15139 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 15140 xmlXPathSubstringBeforeFunction); 15141 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 15142 xmlXPathSubstringAfterFunction); 15143 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 15144 xmlXPathSumFunction); 15145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 15146 xmlXPathTrueFunction); 15147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 15148 xmlXPathTranslateFunction); 15149 15150 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 15151 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 15152 xmlXPathEscapeUriFunction); 15153} 15154 15155#endif /* LIBXML_XPATH_ENABLED */ 15156#define bottom_xpath 15157#include "elfgcchack.h" 15158