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_PATTERN_TO_ANY_NODE_ENABLED: when an XPath expression can be 69* evaluated using the streaming mode (pattern.c) then this is used to 70* enable resolution to nodes of type text-node, cdata-section-node, 71* comment-node and pi-node. The only known scenario where this is 72* needed is an expression like "foo//.", "//.", etc.; i.e. an expression 73* where the final node to be selected can be of any type. 74* Disabling this #define will result in an incorrect evaluation to 75* only element-nodes and the document node. 76*/ 77#define XP_PATTERN_TO_ANY_NODE_ENABLED 78 79/* 80* XP_OPTIMIZED_NON_ELEM_COMPARISON: 81* If defined, this will use xmlXPathCmpNodesExt() instead of 82* xmlXPathCmpNodes(). The new function is optimized comparison of 83* non-element nodes; actually it will speed up comparison only if 84* xmlXPathOrderDocElems() was called in order to index the elements of 85* a tree in document order; Libxslt does such an indexing, thus it will 86* benefit from this optimization. 87*/ 88#define XP_OPTIMIZED_NON_ELEM_COMPARISON 89 90/* 91* XP_OPTIMIZED_FILTER_FIRST: 92* If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 93* in a way, that it stop evaluation at the first node. 94*/ 95#define XP_OPTIMIZED_FILTER_FIRST 96 97/* 98* XP_DEBUG_OBJ_USAGE: 99* Internal flag to enable tracking of how much XPath objects have been 100* created. 101*/ 102/* #define XP_DEBUG_OBJ_USAGE */ 103 104/* 105 * TODO: 106 * There are a few spots where some tests are done which depend upon ascii 107 * data. These should be enhanced for full UTF8 support (see particularly 108 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 109 */ 110 111#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 112/************************************************************************ 113 * * 114 * Forward declarations * 115 * * 116 ************************************************************************/ 117static void 118xmlXPathFreeValueTree(xmlNodeSetPtr obj); 119static void 120xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 121 122/************************************************************************ 123 * * 124 * Floating point stuff * 125 * * 126 ************************************************************************/ 127 128#ifndef TRIO_REPLACE_STDIO 129#define TRIO_PUBLIC static 130#endif 131#include "trionan.c" 132 133/* 134 * The lack of portability of this section of the libc is annoying ! 135 */ 136double xmlXPathNAN = 0; 137double xmlXPathPINF = 1; 138double xmlXPathNINF = -1; 139static double xmlXPathNZERO = 0; /* not exported from headers */ 140static int xmlXPathInitialized = 0; 141 142/** 143 * xmlXPathInit: 144 * 145 * Initialize the XPath environment 146 */ 147void 148xmlXPathInit(void) { 149 if (xmlXPathInitialized) return; 150 151 xmlXPathPINF = trio_pinf(); 152 xmlXPathNINF = trio_ninf(); 153 xmlXPathNAN = trio_nan(); 154 xmlXPathNZERO = trio_nzero(); 155 156 xmlXPathInitialized = 1; 157} 158 159/** 160 * xmlXPathIsNaN: 161 * @val: a double value 162 * 163 * Provides a portable isnan() function to detect whether a double 164 * is a NotaNumber. Based on trio code 165 * http://sourceforge.net/projects/ctrio/ 166 * 167 * Returns 1 if the value is a NaN, 0 otherwise 168 */ 169int 170xmlXPathIsNaN(double val) { 171 return(trio_isnan(val)); 172} 173 174/** 175 * xmlXPathIsInf: 176 * @val: a double value 177 * 178 * Provides a portable isinf() function to detect whether a double 179 * is a +Infinite or -Infinite. Based on trio code 180 * http://sourceforge.net/projects/ctrio/ 181 * 182 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise 183 */ 184int 185xmlXPathIsInf(double val) { 186 return(trio_isinf(val)); 187} 188 189#endif /* SCHEMAS or XPATH */ 190#ifdef LIBXML_XPATH_ENABLED 191/** 192 * xmlXPathGetSign: 193 * @val: a double value 194 * 195 * Provides a portable function to detect the sign of a double 196 * Modified from trio code 197 * http://sourceforge.net/projects/ctrio/ 198 * 199 * Returns 1 if the value is Negative, 0 if positive 200 */ 201static int 202xmlXPathGetSign(double val) { 203 return(trio_signbit(val)); 204} 205 206 207/* 208 * TODO: when compatibility allows remove all "fake node libxslt" strings 209 * the test should just be name[0] = ' ' 210 */ 211/* #define DEBUG */ 212/* #define DEBUG_STEP */ 213/* #define DEBUG_STEP_NTH */ 214/* #define DEBUG_EXPR */ 215/* #define DEBUG_EVAL_COUNTS */ 216 217static xmlNs xmlXPathXMLNamespaceStruct = { 218 NULL, 219 XML_NAMESPACE_DECL, 220 XML_XML_NAMESPACE, 221 BAD_CAST "xml", 222 NULL 223}; 224static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 225#ifndef LIBXML_THREAD_ENABLED 226/* 227 * Optimizer is disabled only when threaded apps are detected while 228 * the library ain't compiled for thread safety. 229 */ 230static int xmlXPathDisableOptimizer = 0; 231#endif 232 233/************************************************************************ 234 * * 235 * Error handling routines * 236 * * 237 ************************************************************************/ 238 239/** 240 * XP_ERRORNULL: 241 * @X: the error code 242 * 243 * Macro to raise an XPath error and return NULL. 244 */ 245#define XP_ERRORNULL(X) \ 246 { xmlXPathErr(ctxt, X); return(NULL); } 247 248/* 249 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 250 */ 251static const char *xmlXPathErrorMessages[] = { 252 "Ok\n", 253 "Number encoding\n", 254 "Unfinished literal\n", 255 "Start of literal\n", 256 "Expected $ for variable reference\n", 257 "Undefined variable\n", 258 "Invalid predicate\n", 259 "Invalid expression\n", 260 "Missing closing curly brace\n", 261 "Unregistered function\n", 262 "Invalid operand\n", 263 "Invalid type\n", 264 "Invalid number of arguments\n", 265 "Invalid context size\n", 266 "Invalid context position\n", 267 "Memory allocation error\n", 268 "Syntax error\n", 269 "Resource error\n", 270 "Sub resource error\n", 271 "Undefined namespace prefix\n", 272 "Encoding error\n", 273 "Char out of XML range\n", 274 "Invalid or incomplete context\n", 275 "?? Unknown error ??\n" /* Must be last in the list! */ 276}; 277#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 278 sizeof(xmlXPathErrorMessages[0])) - 1) 279/** 280 * xmlXPathErrMemory: 281 * @ctxt: an XPath context 282 * @extra: extra informations 283 * 284 * Handle a redefinition of attribute error 285 */ 286static void 287xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 288{ 289 if (ctxt != NULL) { 290 if (extra) { 291 xmlChar buf[200]; 292 293 xmlStrPrintf(buf, 200, 294 BAD_CAST "Memory allocation failed : %s\n", 295 extra); 296 ctxt->lastError.message = (char *) xmlStrdup(buf); 297 } else { 298 ctxt->lastError.message = (char *) 299 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 300 } 301 ctxt->lastError.domain = XML_FROM_XPATH; 302 ctxt->lastError.code = XML_ERR_NO_MEMORY; 303 if (ctxt->error != NULL) 304 ctxt->error(ctxt->userData, &ctxt->lastError); 305 } else { 306 if (extra) 307 __xmlRaiseError(NULL, NULL, NULL, 308 NULL, NULL, XML_FROM_XPATH, 309 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 310 extra, NULL, NULL, 0, 0, 311 "Memory allocation failed : %s\n", extra); 312 else 313 __xmlRaiseError(NULL, NULL, NULL, 314 NULL, NULL, XML_FROM_XPATH, 315 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 316 NULL, NULL, NULL, 0, 0, 317 "Memory allocation failed\n"); 318 } 319} 320 321/** 322 * xmlXPathPErrMemory: 323 * @ctxt: an XPath parser context 324 * @extra: extra informations 325 * 326 * Handle a redefinition of attribute error 327 */ 328static void 329xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 330{ 331 if (ctxt == NULL) 332 xmlXPathErrMemory(NULL, extra); 333 else { 334 ctxt->error = XPATH_MEMORY_ERROR; 335 xmlXPathErrMemory(ctxt->context, extra); 336 } 337} 338 339/** 340 * xmlXPathErr: 341 * @ctxt: a XPath parser context 342 * @error: the error code 343 * 344 * Handle an XPath error 345 */ 346void 347xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 348{ 349 if ((error < 0) || (error > MAXERRNO)) 350 error = MAXERRNO; 351 if (ctxt == NULL) { 352 __xmlRaiseError(NULL, NULL, NULL, 353 NULL, NULL, XML_FROM_XPATH, 354 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 355 XML_ERR_ERROR, NULL, 0, 356 NULL, NULL, NULL, 0, 0, 357 xmlXPathErrorMessages[error]); 358 return; 359 } 360 ctxt->error = error; 361 if (ctxt->context == NULL) { 362 __xmlRaiseError(NULL, NULL, NULL, 363 NULL, NULL, XML_FROM_XPATH, 364 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 365 XML_ERR_ERROR, NULL, 0, 366 (const char *) ctxt->base, NULL, NULL, 367 ctxt->cur - ctxt->base, 0, 368 xmlXPathErrorMessages[error]); 369 return; 370 } 371 372 /* cleanup current last error */ 373 xmlResetError(&ctxt->context->lastError); 374 375 ctxt->context->lastError.domain = XML_FROM_XPATH; 376 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 377 XPATH_EXPRESSION_OK; 378 ctxt->context->lastError.level = XML_ERR_ERROR; 379 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 380 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 381 ctxt->context->lastError.node = ctxt->context->debugNode; 382 if (ctxt->context->error != NULL) { 383 ctxt->context->error(ctxt->context->userData, 384 &ctxt->context->lastError); 385 } else { 386 __xmlRaiseError(NULL, NULL, NULL, 387 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 388 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 389 XML_ERR_ERROR, NULL, 0, 390 (const char *) ctxt->base, NULL, NULL, 391 ctxt->cur - ctxt->base, 0, 392 xmlXPathErrorMessages[error]); 393 } 394 395} 396 397/** 398 * xmlXPatherror: 399 * @ctxt: the XPath Parser context 400 * @file: the file name 401 * @line: the line number 402 * @no: the error number 403 * 404 * Formats an error message. 405 */ 406void 407xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 408 int line ATTRIBUTE_UNUSED, int no) { 409 xmlXPathErr(ctxt, no); 410} 411 412/************************************************************************ 413 * * 414 * Utilities * 415 * * 416 ************************************************************************/ 417 418/** 419 * xsltPointerList: 420 * 421 * Pointer-list for various purposes. 422 */ 423typedef struct _xmlPointerList xmlPointerList; 424typedef xmlPointerList *xmlPointerListPtr; 425struct _xmlPointerList { 426 void **items; 427 int number; 428 int size; 429}; 430/* 431* TODO: Since such a list-handling is used in xmlschemas.c and libxslt 432* and here, we should make the functions public. 433*/ 434static int 435xmlPointerListAddSize(xmlPointerListPtr list, 436 void *item, 437 int initialSize) 438{ 439 if (list->items == NULL) { 440 if (initialSize <= 0) 441 initialSize = 1; 442 list->items = (void **) xmlMalloc( 443 initialSize * sizeof(void *)); 444 if (list->items == NULL) { 445 xmlXPathErrMemory(NULL, 446 "xmlPointerListCreate: allocating item\n"); 447 return(-1); 448 } 449 list->number = 0; 450 list->size = initialSize; 451 } else if (list->size <= list->number) { 452 list->size *= 2; 453 list->items = (void **) xmlRealloc(list->items, 454 list->size * sizeof(void *)); 455 if (list->items == NULL) { 456 xmlXPathErrMemory(NULL, 457 "xmlPointerListCreate: re-allocating item\n"); 458 list->size = 0; 459 return(-1); 460 } 461 } 462 list->items[list->number++] = item; 463 return(0); 464} 465 466/** 467 * xsltPointerListCreate: 468 * 469 * Creates an xsltPointerList structure. 470 * 471 * Returns a xsltPointerList structure or NULL in case of an error. 472 */ 473static xmlPointerListPtr 474xmlPointerListCreate(int initialSize) 475{ 476 xmlPointerListPtr ret; 477 478 ret = xmlMalloc(sizeof(xmlPointerList)); 479 if (ret == NULL) { 480 xmlXPathErrMemory(NULL, 481 "xmlPointerListCreate: allocating item\n"); 482 return (NULL); 483 } 484 memset(ret, 0, sizeof(xmlPointerList)); 485 if (initialSize > 0) { 486 xmlPointerListAddSize(ret, NULL, initialSize); 487 ret->number = 0; 488 } 489 return (ret); 490} 491 492/** 493 * xsltPointerListFree: 494 * 495 * Frees the xsltPointerList structure. This does not free 496 * the content of the list. 497 */ 498static void 499xmlPointerListFree(xmlPointerListPtr list) 500{ 501 if (list == NULL) 502 return; 503 if (list->items != NULL) 504 xmlFree(list->items); 505 xmlFree(list); 506} 507 508/************************************************************************ 509 * * 510 * Parser Types * 511 * * 512 ************************************************************************/ 513 514/* 515 * Types are private: 516 */ 517 518typedef enum { 519 XPATH_OP_END=0, 520 XPATH_OP_AND, 521 XPATH_OP_OR, 522 XPATH_OP_EQUAL, 523 XPATH_OP_CMP, 524 XPATH_OP_PLUS, 525 XPATH_OP_MULT, 526 XPATH_OP_UNION, 527 XPATH_OP_ROOT, 528 XPATH_OP_NODE, 529 XPATH_OP_RESET, /* 10 */ 530 XPATH_OP_COLLECT, 531 XPATH_OP_VALUE, /* 12 */ 532 XPATH_OP_VARIABLE, 533 XPATH_OP_FUNCTION, 534 XPATH_OP_ARG, 535 XPATH_OP_PREDICATE, 536 XPATH_OP_FILTER, /* 17 */ 537 XPATH_OP_SORT /* 18 */ 538#ifdef LIBXML_XPTR_ENABLED 539 ,XPATH_OP_RANGETO 540#endif 541} xmlXPathOp; 542 543typedef enum { 544 AXIS_ANCESTOR = 1, 545 AXIS_ANCESTOR_OR_SELF, 546 AXIS_ATTRIBUTE, 547 AXIS_CHILD, 548 AXIS_DESCENDANT, 549 AXIS_DESCENDANT_OR_SELF, 550 AXIS_FOLLOWING, 551 AXIS_FOLLOWING_SIBLING, 552 AXIS_NAMESPACE, 553 AXIS_PARENT, 554 AXIS_PRECEDING, 555 AXIS_PRECEDING_SIBLING, 556 AXIS_SELF 557} xmlXPathAxisVal; 558 559typedef enum { 560 NODE_TEST_NONE = 0, 561 NODE_TEST_TYPE = 1, 562 NODE_TEST_PI = 2, 563 NODE_TEST_ALL = 3, 564 NODE_TEST_NS = 4, 565 NODE_TEST_NAME = 5 566} xmlXPathTestVal; 567 568typedef enum { 569 NODE_TYPE_NODE = 0, 570 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 571 NODE_TYPE_TEXT = XML_TEXT_NODE, 572 NODE_TYPE_PI = XML_PI_NODE 573} xmlXPathTypeVal; 574 575#define XP_REWRITE_DOS_CHILD_ELEM 1 576 577typedef struct _xmlXPathStepOp xmlXPathStepOp; 578typedef xmlXPathStepOp *xmlXPathStepOpPtr; 579struct _xmlXPathStepOp { 580 xmlXPathOp op; /* The identifier of the operation */ 581 int ch1; /* First child */ 582 int ch2; /* Second child */ 583 int value; 584 int value2; 585 int value3; 586 void *value4; 587 void *value5; 588 void *cache; 589 void *cacheURI; 590 int rewriteType; 591}; 592 593struct _xmlXPathCompExpr { 594 int nbStep; /* Number of steps in this expression */ 595 int maxStep; /* Maximum number of steps allocated */ 596 xmlXPathStepOp *steps; /* ops for computation of this expression */ 597 int last; /* index of last step in expression */ 598 xmlChar *expr; /* the expression being computed */ 599 xmlDictPtr dict; /* the dictionnary to use if any */ 600#ifdef DEBUG_EVAL_COUNTS 601 int nb; 602 xmlChar *string; 603#endif 604#ifdef XPATH_STREAMING 605 xmlPatternPtr stream; 606#endif 607}; 608 609/************************************************************************ 610 * * 611 * Parser Type functions * 612 * * 613 ************************************************************************/ 614 615/** 616 * xmlXPathNewCompExpr: 617 * 618 * Create a new Xpath component 619 * 620 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 621 */ 622static xmlXPathCompExprPtr 623xmlXPathNewCompExpr(void) { 624 xmlXPathCompExprPtr cur; 625 626 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 627 if (cur == NULL) { 628 xmlXPathErrMemory(NULL, "allocating component\n"); 629 return(NULL); 630 } 631 memset(cur, 0, sizeof(xmlXPathCompExpr)); 632 cur->maxStep = 10; 633 cur->nbStep = 0; 634 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 635 sizeof(xmlXPathStepOp)); 636 if (cur->steps == NULL) { 637 xmlXPathErrMemory(NULL, "allocating steps\n"); 638 xmlFree(cur); 639 return(NULL); 640 } 641 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 642 cur->last = -1; 643#ifdef DEBUG_EVAL_COUNTS 644 cur->nb = 0; 645#endif 646 return(cur); 647} 648 649/** 650 * xmlXPathFreeCompExpr: 651 * @comp: an XPATH comp 652 * 653 * Free up the memory allocated by @comp 654 */ 655void 656xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 657{ 658 xmlXPathStepOpPtr op; 659 int i; 660 661 if (comp == NULL) 662 return; 663 if (comp->dict == NULL) { 664 for (i = 0; i < comp->nbStep; i++) { 665 op = &comp->steps[i]; 666 if (op->value4 != NULL) { 667 if (op->op == XPATH_OP_VALUE) 668 xmlXPathFreeObject(op->value4); 669 else 670 xmlFree(op->value4); 671 } 672 if (op->value5 != NULL) 673 xmlFree(op->value5); 674 } 675 } else { 676 for (i = 0; i < comp->nbStep; i++) { 677 op = &comp->steps[i]; 678 if (op->value4 != NULL) { 679 if (op->op == XPATH_OP_VALUE) 680 xmlXPathFreeObject(op->value4); 681 } 682 } 683 xmlDictFree(comp->dict); 684 } 685 if (comp->steps != NULL) { 686 xmlFree(comp->steps); 687 } 688#ifdef DEBUG_EVAL_COUNTS 689 if (comp->string != NULL) { 690 xmlFree(comp->string); 691 } 692#endif 693#ifdef XPATH_STREAMING 694 if (comp->stream != NULL) { 695 xmlFreePatternList(comp->stream); 696 } 697#endif 698 if (comp->expr != NULL) { 699 xmlFree(comp->expr); 700 } 701 702 xmlFree(comp); 703} 704 705/** 706 * xmlXPathCompExprAdd: 707 * @comp: the compiled expression 708 * @ch1: first child index 709 * @ch2: second child index 710 * @op: an op 711 * @value: the first int value 712 * @value2: the second int value 713 * @value3: the third int value 714 * @value4: the first string value 715 * @value5: the second string value 716 * 717 * Add a step to an XPath Compiled Expression 718 * 719 * Returns -1 in case of failure, the index otherwise 720 */ 721static int 722xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 723 xmlXPathOp op, int value, 724 int value2, int value3, void *value4, void *value5) { 725 if (comp->nbStep >= comp->maxStep) { 726 xmlXPathStepOp *real; 727 728 comp->maxStep *= 2; 729 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 730 comp->maxStep * sizeof(xmlXPathStepOp)); 731 if (real == NULL) { 732 comp->maxStep /= 2; 733 xmlXPathErrMemory(NULL, "adding step\n"); 734 return(-1); 735 } 736 comp->steps = real; 737 } 738 comp->last = comp->nbStep; 739 comp->steps[comp->nbStep].ch1 = ch1; 740 comp->steps[comp->nbStep].ch2 = ch2; 741 comp->steps[comp->nbStep].op = op; 742 comp->steps[comp->nbStep].value = value; 743 comp->steps[comp->nbStep].value2 = value2; 744 comp->steps[comp->nbStep].value3 = value3; 745 if ((comp->dict != NULL) && 746 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 747 (op == XPATH_OP_COLLECT))) { 748 if (value4 != NULL) { 749 comp->steps[comp->nbStep].value4 = (xmlChar *) 750 (void *)xmlDictLookup(comp->dict, value4, -1); 751 xmlFree(value4); 752 } else 753 comp->steps[comp->nbStep].value4 = NULL; 754 if (value5 != NULL) { 755 comp->steps[comp->nbStep].value5 = (xmlChar *) 756 (void *)xmlDictLookup(comp->dict, value5, -1); 757 xmlFree(value5); 758 } else 759 comp->steps[comp->nbStep].value5 = NULL; 760 } else { 761 comp->steps[comp->nbStep].value4 = value4; 762 comp->steps[comp->nbStep].value5 = value5; 763 } 764 comp->steps[comp->nbStep].cache = NULL; 765 return(comp->nbStep++); 766} 767 768/** 769 * xmlXPathCompSwap: 770 * @comp: the compiled expression 771 * @op: operation index 772 * 773 * Swaps 2 operations in the compiled expression 774 */ 775static void 776xmlXPathCompSwap(xmlXPathStepOpPtr op) { 777 int tmp; 778 779#ifndef LIBXML_THREAD_ENABLED 780 /* 781 * Since this manipulates possibly shared variables, this is 782 * disabled if one detects that the library is used in a multithreaded 783 * application 784 */ 785 if (xmlXPathDisableOptimizer) 786 return; 787#endif 788 789 tmp = op->ch1; 790 op->ch1 = op->ch2; 791 op->ch2 = tmp; 792} 793 794#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 795 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 796 (op), (val), (val2), (val3), (val4), (val5)) 797#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 798 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 799 (op), (val), (val2), (val3), (val4), (val5)) 800 801#define PUSH_LEAVE_EXPR(op, val, val2) \ 802xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 803 804#define PUSH_UNARY_EXPR(op, ch, val, val2) \ 805xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 806 807#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 808xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 809 (val), (val2), 0 ,NULL ,NULL) 810 811/************************************************************************ 812 * * 813 * XPath object cache structures * 814 * * 815 ************************************************************************/ 816 817/* #define XP_DEFAULT_CACHE_ON */ 818 819#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 820 821typedef struct _xmlXPathContextCache xmlXPathContextCache; 822typedef xmlXPathContextCache *xmlXPathContextCachePtr; 823struct _xmlXPathContextCache { 824 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 825 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 826 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 827 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 828 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 829 int maxNodeset; 830 int maxString; 831 int maxBoolean; 832 int maxNumber; 833 int maxMisc; 834#ifdef XP_DEBUG_OBJ_USAGE 835 int dbgCachedAll; 836 int dbgCachedNodeset; 837 int dbgCachedString; 838 int dbgCachedBool; 839 int dbgCachedNumber; 840 int dbgCachedPoint; 841 int dbgCachedRange; 842 int dbgCachedLocset; 843 int dbgCachedUsers; 844 int dbgCachedXSLTTree; 845 int dbgCachedUndefined; 846 847 848 int dbgReusedAll; 849 int dbgReusedNodeset; 850 int dbgReusedString; 851 int dbgReusedBool; 852 int dbgReusedNumber; 853 int dbgReusedPoint; 854 int dbgReusedRange; 855 int dbgReusedLocset; 856 int dbgReusedUsers; 857 int dbgReusedXSLTTree; 858 int dbgReusedUndefined; 859 860#endif 861}; 862 863/************************************************************************ 864 * * 865 * Debugging related functions * 866 * * 867 ************************************************************************/ 868 869#define STRANGE \ 870 xmlGenericError(xmlGenericErrorContext, \ 871 "Internal error at %s:%d\n", \ 872 __FILE__, __LINE__); 873 874#ifdef LIBXML_DEBUG_ENABLED 875static void 876xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 877 int i; 878 char shift[100]; 879 880 for (i = 0;((i < depth) && (i < 25));i++) 881 shift[2 * i] = shift[2 * i + 1] = ' '; 882 shift[2 * i] = shift[2 * i + 1] = 0; 883 if (cur == NULL) { 884 fprintf(output, shift); 885 fprintf(output, "Node is NULL !\n"); 886 return; 887 888 } 889 890 if ((cur->type == XML_DOCUMENT_NODE) || 891 (cur->type == XML_HTML_DOCUMENT_NODE)) { 892 fprintf(output, shift); 893 fprintf(output, " /\n"); 894 } else if (cur->type == XML_ATTRIBUTE_NODE) 895 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 896 else 897 xmlDebugDumpOneNode(output, cur, depth); 898} 899static void 900xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 901 xmlNodePtr tmp; 902 int i; 903 char shift[100]; 904 905 for (i = 0;((i < depth) && (i < 25));i++) 906 shift[2 * i] = shift[2 * i + 1] = ' '; 907 shift[2 * i] = shift[2 * i + 1] = 0; 908 if (cur == NULL) { 909 fprintf(output, shift); 910 fprintf(output, "Node is NULL !\n"); 911 return; 912 913 } 914 915 while (cur != NULL) { 916 tmp = cur; 917 cur = cur->next; 918 xmlDebugDumpOneNode(output, tmp, depth); 919 } 920} 921 922static void 923xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 924 int i; 925 char shift[100]; 926 927 for (i = 0;((i < depth) && (i < 25));i++) 928 shift[2 * i] = shift[2 * i + 1] = ' '; 929 shift[2 * i] = shift[2 * i + 1] = 0; 930 931 if (cur == NULL) { 932 fprintf(output, shift); 933 fprintf(output, "NodeSet is NULL !\n"); 934 return; 935 936 } 937 938 if (cur != NULL) { 939 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 940 for (i = 0;i < cur->nodeNr;i++) { 941 fprintf(output, shift); 942 fprintf(output, "%d", i + 1); 943 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 944 } 945 } 946} 947 948static void 949xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 950 int i; 951 char shift[100]; 952 953 for (i = 0;((i < depth) && (i < 25));i++) 954 shift[2 * i] = shift[2 * i + 1] = ' '; 955 shift[2 * i] = shift[2 * i + 1] = 0; 956 957 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 958 fprintf(output, shift); 959 fprintf(output, "Value Tree is NULL !\n"); 960 return; 961 962 } 963 964 fprintf(output, shift); 965 fprintf(output, "%d", i + 1); 966 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 967} 968#if defined(LIBXML_XPTR_ENABLED) 969static void 970xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 971 int i; 972 char shift[100]; 973 974 for (i = 0;((i < depth) && (i < 25));i++) 975 shift[2 * i] = shift[2 * i + 1] = ' '; 976 shift[2 * i] = shift[2 * i + 1] = 0; 977 978 if (cur == NULL) { 979 fprintf(output, shift); 980 fprintf(output, "LocationSet is NULL !\n"); 981 return; 982 983 } 984 985 for (i = 0;i < cur->locNr;i++) { 986 fprintf(output, shift); 987 fprintf(output, "%d : ", i + 1); 988 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 989 } 990} 991#endif /* LIBXML_XPTR_ENABLED */ 992 993/** 994 * xmlXPathDebugDumpObject: 995 * @output: the FILE * to dump the output 996 * @cur: the object to inspect 997 * @depth: indentation level 998 * 999 * Dump the content of the object for debugging purposes 1000 */ 1001void 1002xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1003 int i; 1004 char shift[100]; 1005 1006 if (output == NULL) return; 1007 1008 for (i = 0;((i < depth) && (i < 25));i++) 1009 shift[2 * i] = shift[2 * i + 1] = ' '; 1010 shift[2 * i] = shift[2 * i + 1] = 0; 1011 1012 1013 fprintf(output, shift); 1014 1015 if (cur == NULL) { 1016 fprintf(output, "Object is empty (NULL)\n"); 1017 return; 1018 } 1019 switch(cur->type) { 1020 case XPATH_UNDEFINED: 1021 fprintf(output, "Object is uninitialized\n"); 1022 break; 1023 case XPATH_NODESET: 1024 fprintf(output, "Object is a Node Set :\n"); 1025 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1026 break; 1027 case XPATH_XSLT_TREE: 1028 fprintf(output, "Object is an XSLT value tree :\n"); 1029 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1030 break; 1031 case XPATH_BOOLEAN: 1032 fprintf(output, "Object is a Boolean : "); 1033 if (cur->boolval) fprintf(output, "true\n"); 1034 else fprintf(output, "false\n"); 1035 break; 1036 case XPATH_NUMBER: 1037 switch (xmlXPathIsInf(cur->floatval)) { 1038 case 1: 1039 fprintf(output, "Object is a number : Infinity\n"); 1040 break; 1041 case -1: 1042 fprintf(output, "Object is a number : -Infinity\n"); 1043 break; 1044 default: 1045 if (xmlXPathIsNaN(cur->floatval)) { 1046 fprintf(output, "Object is a number : NaN\n"); 1047 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 1048 fprintf(output, "Object is a number : 0\n"); 1049 } else { 1050 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1051 } 1052 } 1053 break; 1054 case XPATH_STRING: 1055 fprintf(output, "Object is a string : "); 1056 xmlDebugDumpString(output, cur->stringval); 1057 fprintf(output, "\n"); 1058 break; 1059 case XPATH_POINT: 1060 fprintf(output, "Object is a point : index %d in node", cur->index); 1061 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1062 fprintf(output, "\n"); 1063 break; 1064 case XPATH_RANGE: 1065 if ((cur->user2 == NULL) || 1066 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1067 fprintf(output, "Object is a collapsed range :\n"); 1068 fprintf(output, shift); 1069 if (cur->index >= 0) 1070 fprintf(output, "index %d in ", cur->index); 1071 fprintf(output, "node\n"); 1072 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1073 depth + 1); 1074 } else { 1075 fprintf(output, "Object is a range :\n"); 1076 fprintf(output, shift); 1077 fprintf(output, "From "); 1078 if (cur->index >= 0) 1079 fprintf(output, "index %d in ", cur->index); 1080 fprintf(output, "node\n"); 1081 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1082 depth + 1); 1083 fprintf(output, shift); 1084 fprintf(output, "To "); 1085 if (cur->index2 >= 0) 1086 fprintf(output, "index %d in ", cur->index2); 1087 fprintf(output, "node\n"); 1088 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1089 depth + 1); 1090 fprintf(output, "\n"); 1091 } 1092 break; 1093 case XPATH_LOCATIONSET: 1094#if defined(LIBXML_XPTR_ENABLED) 1095 fprintf(output, "Object is a Location Set:\n"); 1096 xmlXPathDebugDumpLocationSet(output, 1097 (xmlLocationSetPtr) cur->user, depth); 1098#endif 1099 break; 1100 case XPATH_USERS: 1101 fprintf(output, "Object is user defined\n"); 1102 break; 1103 } 1104} 1105 1106static void 1107xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1108 xmlXPathStepOpPtr op, int depth) { 1109 int i; 1110 char shift[100]; 1111 1112 for (i = 0;((i < depth) && (i < 25));i++) 1113 shift[2 * i] = shift[2 * i + 1] = ' '; 1114 shift[2 * i] = shift[2 * i + 1] = 0; 1115 1116 fprintf(output, shift); 1117 if (op == NULL) { 1118 fprintf(output, "Step is NULL\n"); 1119 return; 1120 } 1121 switch (op->op) { 1122 case XPATH_OP_END: 1123 fprintf(output, "END"); break; 1124 case XPATH_OP_AND: 1125 fprintf(output, "AND"); break; 1126 case XPATH_OP_OR: 1127 fprintf(output, "OR"); break; 1128 case XPATH_OP_EQUAL: 1129 if (op->value) 1130 fprintf(output, "EQUAL ="); 1131 else 1132 fprintf(output, "EQUAL !="); 1133 break; 1134 case XPATH_OP_CMP: 1135 if (op->value) 1136 fprintf(output, "CMP <"); 1137 else 1138 fprintf(output, "CMP >"); 1139 if (!op->value2) 1140 fprintf(output, "="); 1141 break; 1142 case XPATH_OP_PLUS: 1143 if (op->value == 0) 1144 fprintf(output, "PLUS -"); 1145 else if (op->value == 1) 1146 fprintf(output, "PLUS +"); 1147 else if (op->value == 2) 1148 fprintf(output, "PLUS unary -"); 1149 else if (op->value == 3) 1150 fprintf(output, "PLUS unary - -"); 1151 break; 1152 case XPATH_OP_MULT: 1153 if (op->value == 0) 1154 fprintf(output, "MULT *"); 1155 else if (op->value == 1) 1156 fprintf(output, "MULT div"); 1157 else 1158 fprintf(output, "MULT mod"); 1159 break; 1160 case XPATH_OP_UNION: 1161 fprintf(output, "UNION"); break; 1162 case XPATH_OP_ROOT: 1163 fprintf(output, "ROOT"); break; 1164 case XPATH_OP_NODE: 1165 fprintf(output, "NODE"); break; 1166 case XPATH_OP_RESET: 1167 fprintf(output, "RESET"); break; 1168 case XPATH_OP_SORT: 1169 fprintf(output, "SORT"); break; 1170 case XPATH_OP_COLLECT: { 1171 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1172 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1173 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1174 const xmlChar *prefix = op->value4; 1175 const xmlChar *name = op->value5; 1176 1177 fprintf(output, "COLLECT "); 1178 switch (axis) { 1179 case AXIS_ANCESTOR: 1180 fprintf(output, " 'ancestors' "); break; 1181 case AXIS_ANCESTOR_OR_SELF: 1182 fprintf(output, " 'ancestors-or-self' "); break; 1183 case AXIS_ATTRIBUTE: 1184 fprintf(output, " 'attributes' "); break; 1185 case AXIS_CHILD: 1186 fprintf(output, " 'child' "); break; 1187 case AXIS_DESCENDANT: 1188 fprintf(output, " 'descendant' "); break; 1189 case AXIS_DESCENDANT_OR_SELF: 1190 fprintf(output, " 'descendant-or-self' "); break; 1191 case AXIS_FOLLOWING: 1192 fprintf(output, " 'following' "); break; 1193 case AXIS_FOLLOWING_SIBLING: 1194 fprintf(output, " 'following-siblings' "); break; 1195 case AXIS_NAMESPACE: 1196 fprintf(output, " 'namespace' "); break; 1197 case AXIS_PARENT: 1198 fprintf(output, " 'parent' "); break; 1199 case AXIS_PRECEDING: 1200 fprintf(output, " 'preceding' "); break; 1201 case AXIS_PRECEDING_SIBLING: 1202 fprintf(output, " 'preceding-sibling' "); break; 1203 case AXIS_SELF: 1204 fprintf(output, " 'self' "); break; 1205 } 1206 switch (test) { 1207 case NODE_TEST_NONE: 1208 fprintf(output, "'none' "); break; 1209 case NODE_TEST_TYPE: 1210 fprintf(output, "'type' "); break; 1211 case NODE_TEST_PI: 1212 fprintf(output, "'PI' "); break; 1213 case NODE_TEST_ALL: 1214 fprintf(output, "'all' "); break; 1215 case NODE_TEST_NS: 1216 fprintf(output, "'namespace' "); break; 1217 case NODE_TEST_NAME: 1218 fprintf(output, "'name' "); break; 1219 } 1220 switch (type) { 1221 case NODE_TYPE_NODE: 1222 fprintf(output, "'node' "); break; 1223 case NODE_TYPE_COMMENT: 1224 fprintf(output, "'comment' "); break; 1225 case NODE_TYPE_TEXT: 1226 fprintf(output, "'text' "); break; 1227 case NODE_TYPE_PI: 1228 fprintf(output, "'PI' "); break; 1229 } 1230 if (prefix != NULL) 1231 fprintf(output, "%s:", prefix); 1232 if (name != NULL) 1233 fprintf(output, "%s", (const char *) name); 1234 break; 1235 1236 } 1237 case XPATH_OP_VALUE: { 1238 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1239 1240 fprintf(output, "ELEM "); 1241 xmlXPathDebugDumpObject(output, object, 0); 1242 goto finish; 1243 } 1244 case XPATH_OP_VARIABLE: { 1245 const xmlChar *prefix = op->value5; 1246 const xmlChar *name = op->value4; 1247 1248 if (prefix != NULL) 1249 fprintf(output, "VARIABLE %s:%s", prefix, name); 1250 else 1251 fprintf(output, "VARIABLE %s", name); 1252 break; 1253 } 1254 case XPATH_OP_FUNCTION: { 1255 int nbargs = op->value; 1256 const xmlChar *prefix = op->value5; 1257 const xmlChar *name = op->value4; 1258 1259 if (prefix != NULL) 1260 fprintf(output, "FUNCTION %s:%s(%d args)", 1261 prefix, name, nbargs); 1262 else 1263 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1264 break; 1265 } 1266 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1267 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1268 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1269#ifdef LIBXML_XPTR_ENABLED 1270 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1271#endif 1272 default: 1273 fprintf(output, "UNKNOWN %d\n", op->op); return; 1274 } 1275 fprintf(output, "\n"); 1276finish: 1277 if (op->ch1 >= 0) 1278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1279 if (op->ch2 >= 0) 1280 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1281} 1282 1283/** 1284 * xmlXPathDebugDumpCompExpr: 1285 * @output: the FILE * for the output 1286 * @comp: the precompiled XPath expression 1287 * @depth: the indentation level. 1288 * 1289 * Dumps the tree of the compiled XPath expression. 1290 */ 1291void 1292xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1293 int depth) { 1294 int i; 1295 char shift[100]; 1296 1297 if ((output == NULL) || (comp == NULL)) return; 1298 1299 for (i = 0;((i < depth) && (i < 25));i++) 1300 shift[2 * i] = shift[2 * i + 1] = ' '; 1301 shift[2 * i] = shift[2 * i + 1] = 0; 1302 1303 fprintf(output, shift); 1304 1305 fprintf(output, "Compiled Expression : %d elements\n", 1306 comp->nbStep); 1307 i = comp->last; 1308 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1309} 1310 1311#ifdef XP_DEBUG_OBJ_USAGE 1312 1313/* 1314* XPath object usage related debugging variables. 1315*/ 1316static int xmlXPathDebugObjCounterUndefined = 0; 1317static int xmlXPathDebugObjCounterNodeset = 0; 1318static int xmlXPathDebugObjCounterBool = 0; 1319static int xmlXPathDebugObjCounterNumber = 0; 1320static int xmlXPathDebugObjCounterString = 0; 1321static int xmlXPathDebugObjCounterPoint = 0; 1322static int xmlXPathDebugObjCounterRange = 0; 1323static int xmlXPathDebugObjCounterLocset = 0; 1324static int xmlXPathDebugObjCounterUsers = 0; 1325static int xmlXPathDebugObjCounterXSLTTree = 0; 1326static int xmlXPathDebugObjCounterAll = 0; 1327 1328static int xmlXPathDebugObjTotalUndefined = 0; 1329static int xmlXPathDebugObjTotalNodeset = 0; 1330static int xmlXPathDebugObjTotalBool = 0; 1331static int xmlXPathDebugObjTotalNumber = 0; 1332static int xmlXPathDebugObjTotalString = 0; 1333static int xmlXPathDebugObjTotalPoint = 0; 1334static int xmlXPathDebugObjTotalRange = 0; 1335static int xmlXPathDebugObjTotalLocset = 0; 1336static int xmlXPathDebugObjTotalUsers = 0; 1337static int xmlXPathDebugObjTotalXSLTTree = 0; 1338static int xmlXPathDebugObjTotalAll = 0; 1339 1340static int xmlXPathDebugObjMaxUndefined = 0; 1341static int xmlXPathDebugObjMaxNodeset = 0; 1342static int xmlXPathDebugObjMaxBool = 0; 1343static int xmlXPathDebugObjMaxNumber = 0; 1344static int xmlXPathDebugObjMaxString = 0; 1345static int xmlXPathDebugObjMaxPoint = 0; 1346static int xmlXPathDebugObjMaxRange = 0; 1347static int xmlXPathDebugObjMaxLocset = 0; 1348static int xmlXPathDebugObjMaxUsers = 0; 1349static int xmlXPathDebugObjMaxXSLTTree = 0; 1350static int xmlXPathDebugObjMaxAll = 0; 1351 1352/* REVISIT TODO: Make this static when committing */ 1353static void 1354xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1355{ 1356 if (ctxt != NULL) { 1357 if (ctxt->cache != NULL) { 1358 xmlXPathContextCachePtr cache = 1359 (xmlXPathContextCachePtr) ctxt->cache; 1360 1361 cache->dbgCachedAll = 0; 1362 cache->dbgCachedNodeset = 0; 1363 cache->dbgCachedString = 0; 1364 cache->dbgCachedBool = 0; 1365 cache->dbgCachedNumber = 0; 1366 cache->dbgCachedPoint = 0; 1367 cache->dbgCachedRange = 0; 1368 cache->dbgCachedLocset = 0; 1369 cache->dbgCachedUsers = 0; 1370 cache->dbgCachedXSLTTree = 0; 1371 cache->dbgCachedUndefined = 0; 1372 1373 cache->dbgReusedAll = 0; 1374 cache->dbgReusedNodeset = 0; 1375 cache->dbgReusedString = 0; 1376 cache->dbgReusedBool = 0; 1377 cache->dbgReusedNumber = 0; 1378 cache->dbgReusedPoint = 0; 1379 cache->dbgReusedRange = 0; 1380 cache->dbgReusedLocset = 0; 1381 cache->dbgReusedUsers = 0; 1382 cache->dbgReusedXSLTTree = 0; 1383 cache->dbgReusedUndefined = 0; 1384 } 1385 } 1386 1387 xmlXPathDebugObjCounterUndefined = 0; 1388 xmlXPathDebugObjCounterNodeset = 0; 1389 xmlXPathDebugObjCounterBool = 0; 1390 xmlXPathDebugObjCounterNumber = 0; 1391 xmlXPathDebugObjCounterString = 0; 1392 xmlXPathDebugObjCounterPoint = 0; 1393 xmlXPathDebugObjCounterRange = 0; 1394 xmlXPathDebugObjCounterLocset = 0; 1395 xmlXPathDebugObjCounterUsers = 0; 1396 xmlXPathDebugObjCounterXSLTTree = 0; 1397 xmlXPathDebugObjCounterAll = 0; 1398 1399 xmlXPathDebugObjTotalUndefined = 0; 1400 xmlXPathDebugObjTotalNodeset = 0; 1401 xmlXPathDebugObjTotalBool = 0; 1402 xmlXPathDebugObjTotalNumber = 0; 1403 xmlXPathDebugObjTotalString = 0; 1404 xmlXPathDebugObjTotalPoint = 0; 1405 xmlXPathDebugObjTotalRange = 0; 1406 xmlXPathDebugObjTotalLocset = 0; 1407 xmlXPathDebugObjTotalUsers = 0; 1408 xmlXPathDebugObjTotalXSLTTree = 0; 1409 xmlXPathDebugObjTotalAll = 0; 1410 1411 xmlXPathDebugObjMaxUndefined = 0; 1412 xmlXPathDebugObjMaxNodeset = 0; 1413 xmlXPathDebugObjMaxBool = 0; 1414 xmlXPathDebugObjMaxNumber = 0; 1415 xmlXPathDebugObjMaxString = 0; 1416 xmlXPathDebugObjMaxPoint = 0; 1417 xmlXPathDebugObjMaxRange = 0; 1418 xmlXPathDebugObjMaxLocset = 0; 1419 xmlXPathDebugObjMaxUsers = 0; 1420 xmlXPathDebugObjMaxXSLTTree = 0; 1421 xmlXPathDebugObjMaxAll = 0; 1422 1423} 1424 1425static void 1426xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1427 xmlXPathObjectType objType) 1428{ 1429 int isCached = 0; 1430 1431 if (ctxt != NULL) { 1432 if (ctxt->cache != NULL) { 1433 xmlXPathContextCachePtr cache = 1434 (xmlXPathContextCachePtr) ctxt->cache; 1435 1436 isCached = 1; 1437 1438 cache->dbgReusedAll++; 1439 switch (objType) { 1440 case XPATH_UNDEFINED: 1441 cache->dbgReusedUndefined++; 1442 break; 1443 case XPATH_NODESET: 1444 cache->dbgReusedNodeset++; 1445 break; 1446 case XPATH_BOOLEAN: 1447 cache->dbgReusedBool++; 1448 break; 1449 case XPATH_NUMBER: 1450 cache->dbgReusedNumber++; 1451 break; 1452 case XPATH_STRING: 1453 cache->dbgReusedString++; 1454 break; 1455 case XPATH_POINT: 1456 cache->dbgReusedPoint++; 1457 break; 1458 case XPATH_RANGE: 1459 cache->dbgReusedRange++; 1460 break; 1461 case XPATH_LOCATIONSET: 1462 cache->dbgReusedLocset++; 1463 break; 1464 case XPATH_USERS: 1465 cache->dbgReusedUsers++; 1466 break; 1467 case XPATH_XSLT_TREE: 1468 cache->dbgReusedXSLTTree++; 1469 break; 1470 default: 1471 break; 1472 } 1473 } 1474 } 1475 1476 switch (objType) { 1477 case XPATH_UNDEFINED: 1478 if (! isCached) 1479 xmlXPathDebugObjTotalUndefined++; 1480 xmlXPathDebugObjCounterUndefined++; 1481 if (xmlXPathDebugObjCounterUndefined > 1482 xmlXPathDebugObjMaxUndefined) 1483 xmlXPathDebugObjMaxUndefined = 1484 xmlXPathDebugObjCounterUndefined; 1485 break; 1486 case XPATH_NODESET: 1487 if (! isCached) 1488 xmlXPathDebugObjTotalNodeset++; 1489 xmlXPathDebugObjCounterNodeset++; 1490 if (xmlXPathDebugObjCounterNodeset > 1491 xmlXPathDebugObjMaxNodeset) 1492 xmlXPathDebugObjMaxNodeset = 1493 xmlXPathDebugObjCounterNodeset; 1494 break; 1495 case XPATH_BOOLEAN: 1496 if (! isCached) 1497 xmlXPathDebugObjTotalBool++; 1498 xmlXPathDebugObjCounterBool++; 1499 if (xmlXPathDebugObjCounterBool > 1500 xmlXPathDebugObjMaxBool) 1501 xmlXPathDebugObjMaxBool = 1502 xmlXPathDebugObjCounterBool; 1503 break; 1504 case XPATH_NUMBER: 1505 if (! isCached) 1506 xmlXPathDebugObjTotalNumber++; 1507 xmlXPathDebugObjCounterNumber++; 1508 if (xmlXPathDebugObjCounterNumber > 1509 xmlXPathDebugObjMaxNumber) 1510 xmlXPathDebugObjMaxNumber = 1511 xmlXPathDebugObjCounterNumber; 1512 break; 1513 case XPATH_STRING: 1514 if (! isCached) 1515 xmlXPathDebugObjTotalString++; 1516 xmlXPathDebugObjCounterString++; 1517 if (xmlXPathDebugObjCounterString > 1518 xmlXPathDebugObjMaxString) 1519 xmlXPathDebugObjMaxString = 1520 xmlXPathDebugObjCounterString; 1521 break; 1522 case XPATH_POINT: 1523 if (! isCached) 1524 xmlXPathDebugObjTotalPoint++; 1525 xmlXPathDebugObjCounterPoint++; 1526 if (xmlXPathDebugObjCounterPoint > 1527 xmlXPathDebugObjMaxPoint) 1528 xmlXPathDebugObjMaxPoint = 1529 xmlXPathDebugObjCounterPoint; 1530 break; 1531 case XPATH_RANGE: 1532 if (! isCached) 1533 xmlXPathDebugObjTotalRange++; 1534 xmlXPathDebugObjCounterRange++; 1535 if (xmlXPathDebugObjCounterRange > 1536 xmlXPathDebugObjMaxRange) 1537 xmlXPathDebugObjMaxRange = 1538 xmlXPathDebugObjCounterRange; 1539 break; 1540 case XPATH_LOCATIONSET: 1541 if (! isCached) 1542 xmlXPathDebugObjTotalLocset++; 1543 xmlXPathDebugObjCounterLocset++; 1544 if (xmlXPathDebugObjCounterLocset > 1545 xmlXPathDebugObjMaxLocset) 1546 xmlXPathDebugObjMaxLocset = 1547 xmlXPathDebugObjCounterLocset; 1548 break; 1549 case XPATH_USERS: 1550 if (! isCached) 1551 xmlXPathDebugObjTotalUsers++; 1552 xmlXPathDebugObjCounterUsers++; 1553 if (xmlXPathDebugObjCounterUsers > 1554 xmlXPathDebugObjMaxUsers) 1555 xmlXPathDebugObjMaxUsers = 1556 xmlXPathDebugObjCounterUsers; 1557 break; 1558 case XPATH_XSLT_TREE: 1559 if (! isCached) 1560 xmlXPathDebugObjTotalXSLTTree++; 1561 xmlXPathDebugObjCounterXSLTTree++; 1562 if (xmlXPathDebugObjCounterXSLTTree > 1563 xmlXPathDebugObjMaxXSLTTree) 1564 xmlXPathDebugObjMaxXSLTTree = 1565 xmlXPathDebugObjCounterXSLTTree; 1566 break; 1567 default: 1568 break; 1569 } 1570 if (! isCached) 1571 xmlXPathDebugObjTotalAll++; 1572 xmlXPathDebugObjCounterAll++; 1573 if (xmlXPathDebugObjCounterAll > 1574 xmlXPathDebugObjMaxAll) 1575 xmlXPathDebugObjMaxAll = 1576 xmlXPathDebugObjCounterAll; 1577} 1578 1579static void 1580xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1581 xmlXPathObjectType objType) 1582{ 1583 int isCached = 0; 1584 1585 if (ctxt != NULL) { 1586 if (ctxt->cache != NULL) { 1587 xmlXPathContextCachePtr cache = 1588 (xmlXPathContextCachePtr) ctxt->cache; 1589 1590 isCached = 1; 1591 1592 cache->dbgCachedAll++; 1593 switch (objType) { 1594 case XPATH_UNDEFINED: 1595 cache->dbgCachedUndefined++; 1596 break; 1597 case XPATH_NODESET: 1598 cache->dbgCachedNodeset++; 1599 break; 1600 case XPATH_BOOLEAN: 1601 cache->dbgCachedBool++; 1602 break; 1603 case XPATH_NUMBER: 1604 cache->dbgCachedNumber++; 1605 break; 1606 case XPATH_STRING: 1607 cache->dbgCachedString++; 1608 break; 1609 case XPATH_POINT: 1610 cache->dbgCachedPoint++; 1611 break; 1612 case XPATH_RANGE: 1613 cache->dbgCachedRange++; 1614 break; 1615 case XPATH_LOCATIONSET: 1616 cache->dbgCachedLocset++; 1617 break; 1618 case XPATH_USERS: 1619 cache->dbgCachedUsers++; 1620 break; 1621 case XPATH_XSLT_TREE: 1622 cache->dbgCachedXSLTTree++; 1623 break; 1624 default: 1625 break; 1626 } 1627 1628 } 1629 } 1630 switch (objType) { 1631 case XPATH_UNDEFINED: 1632 xmlXPathDebugObjCounterUndefined--; 1633 break; 1634 case XPATH_NODESET: 1635 xmlXPathDebugObjCounterNodeset--; 1636 break; 1637 case XPATH_BOOLEAN: 1638 xmlXPathDebugObjCounterBool--; 1639 break; 1640 case XPATH_NUMBER: 1641 xmlXPathDebugObjCounterNumber--; 1642 break; 1643 case XPATH_STRING: 1644 xmlXPathDebugObjCounterString--; 1645 break; 1646 case XPATH_POINT: 1647 xmlXPathDebugObjCounterPoint--; 1648 break; 1649 case XPATH_RANGE: 1650 xmlXPathDebugObjCounterRange--; 1651 break; 1652 case XPATH_LOCATIONSET: 1653 xmlXPathDebugObjCounterLocset--; 1654 break; 1655 case XPATH_USERS: 1656 xmlXPathDebugObjCounterUsers--; 1657 break; 1658 case XPATH_XSLT_TREE: 1659 xmlXPathDebugObjCounterXSLTTree--; 1660 break; 1661 default: 1662 break; 1663 } 1664 xmlXPathDebugObjCounterAll--; 1665} 1666 1667/* REVISIT TODO: Make this static when committing */ 1668static void 1669xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 1670{ 1671 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 1672 reqXSLTTree, reqUndefined; 1673 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 1674 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 1675 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 1676 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 1677 int leftObjs = xmlXPathDebugObjCounterAll; 1678 1679 reqAll = xmlXPathDebugObjTotalAll; 1680 reqNodeset = xmlXPathDebugObjTotalNodeset; 1681 reqString = xmlXPathDebugObjTotalString; 1682 reqBool = xmlXPathDebugObjTotalBool; 1683 reqNumber = xmlXPathDebugObjTotalNumber; 1684 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 1685 reqUndefined = xmlXPathDebugObjTotalUndefined; 1686 1687 printf("# XPath object usage:\n"); 1688 1689 if (ctxt != NULL) { 1690 if (ctxt->cache != NULL) { 1691 xmlXPathContextCachePtr cache = 1692 (xmlXPathContextCachePtr) ctxt->cache; 1693 1694 reAll = cache->dbgReusedAll; 1695 reqAll += reAll; 1696 reNodeset = cache->dbgReusedNodeset; 1697 reqNodeset += reNodeset; 1698 reString = cache->dbgReusedString; 1699 reqString += reString; 1700 reBool = cache->dbgReusedBool; 1701 reqBool += reBool; 1702 reNumber = cache->dbgReusedNumber; 1703 reqNumber += reNumber; 1704 reXSLTTree = cache->dbgReusedXSLTTree; 1705 reqXSLTTree += reXSLTTree; 1706 reUndefined = cache->dbgReusedUndefined; 1707 reqUndefined += reUndefined; 1708 1709 caAll = cache->dbgCachedAll; 1710 caBool = cache->dbgCachedBool; 1711 caNodeset = cache->dbgCachedNodeset; 1712 caString = cache->dbgCachedString; 1713 caNumber = cache->dbgCachedNumber; 1714 caXSLTTree = cache->dbgCachedXSLTTree; 1715 caUndefined = cache->dbgCachedUndefined; 1716 1717 if (cache->nodesetObjs) 1718 leftObjs -= cache->nodesetObjs->number; 1719 if (cache->stringObjs) 1720 leftObjs -= cache->stringObjs->number; 1721 if (cache->booleanObjs) 1722 leftObjs -= cache->booleanObjs->number; 1723 if (cache->numberObjs) 1724 leftObjs -= cache->numberObjs->number; 1725 if (cache->miscObjs) 1726 leftObjs -= cache->miscObjs->number; 1727 } 1728 } 1729 1730 printf("# all\n"); 1731 printf("# total : %d\n", reqAll); 1732 printf("# left : %d\n", leftObjs); 1733 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 1734 printf("# reused : %d\n", reAll); 1735 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 1736 1737 printf("# node-sets\n"); 1738 printf("# total : %d\n", reqNodeset); 1739 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 1740 printf("# reused : %d\n", reNodeset); 1741 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 1742 1743 printf("# strings\n"); 1744 printf("# total : %d\n", reqString); 1745 printf("# created: %d\n", xmlXPathDebugObjTotalString); 1746 printf("# reused : %d\n", reString); 1747 printf("# max : %d\n", xmlXPathDebugObjMaxString); 1748 1749 printf("# booleans\n"); 1750 printf("# total : %d\n", reqBool); 1751 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 1752 printf("# reused : %d\n", reBool); 1753 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 1754 1755 printf("# numbers\n"); 1756 printf("# total : %d\n", reqNumber); 1757 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 1758 printf("# reused : %d\n", reNumber); 1759 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 1760 1761 printf("# XSLT result tree fragments\n"); 1762 printf("# total : %d\n", reqXSLTTree); 1763 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 1764 printf("# reused : %d\n", reXSLTTree); 1765 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 1766 1767 printf("# undefined\n"); 1768 printf("# total : %d\n", reqUndefined); 1769 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 1770 printf("# reused : %d\n", reUndefined); 1771 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 1772 1773} 1774 1775#endif /* XP_DEBUG_OBJ_USAGE */ 1776 1777#endif /* LIBXML_DEBUG_ENABLED */ 1778 1779/************************************************************************ 1780 * * 1781 * XPath object caching * 1782 * * 1783 ************************************************************************/ 1784 1785/** 1786 * xmlXPathNewCache: 1787 * 1788 * Create a new object cache 1789 * 1790 * Returns the xmlXPathCache just allocated. 1791 */ 1792static xmlXPathContextCachePtr 1793xmlXPathNewCache(void) 1794{ 1795 xmlXPathContextCachePtr ret; 1796 1797 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 1798 if (ret == NULL) { 1799 xmlXPathErrMemory(NULL, "creating object cache\n"); 1800 return(NULL); 1801 } 1802 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 1803 ret->maxNodeset = 100; 1804 ret->maxString = 100; 1805 ret->maxBoolean = 100; 1806 ret->maxNumber = 100; 1807 ret->maxMisc = 100; 1808 return(ret); 1809} 1810 1811static void 1812xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 1813{ 1814 int i; 1815 xmlXPathObjectPtr obj; 1816 1817 if (list == NULL) 1818 return; 1819 1820 for (i = 0; i < list->number; i++) { 1821 obj = list->items[i]; 1822 /* 1823 * Note that it is already assured that we don't need to 1824 * look out for namespace nodes in the node-set. 1825 */ 1826 if (obj->nodesetval != NULL) { 1827 if (obj->nodesetval->nodeTab != NULL) 1828 xmlFree(obj->nodesetval->nodeTab); 1829 xmlFree(obj->nodesetval); 1830 } 1831 xmlFree(obj); 1832#ifdef XP_DEBUG_OBJ_USAGE 1833 xmlXPathDebugObjCounterAll--; 1834#endif 1835 } 1836 xmlPointerListFree(list); 1837} 1838 1839static void 1840xmlXPathFreeCache(xmlXPathContextCachePtr cache) 1841{ 1842 if (cache == NULL) 1843 return; 1844 if (cache->nodesetObjs) 1845 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 1846 if (cache->stringObjs) 1847 xmlXPathCacheFreeObjectList(cache->stringObjs); 1848 if (cache->booleanObjs) 1849 xmlXPathCacheFreeObjectList(cache->booleanObjs); 1850 if (cache->numberObjs) 1851 xmlXPathCacheFreeObjectList(cache->numberObjs); 1852 if (cache->miscObjs) 1853 xmlXPathCacheFreeObjectList(cache->miscObjs); 1854 xmlFree(cache); 1855} 1856 1857/** 1858 * xmlXPathContextSetCache: 1859 * 1860 * @ctxt: the XPath context 1861 * @active: enables/disables (creates/frees) the cache 1862 * @value: a value with semantics dependant on @options 1863 * @options: options (currently only the value 0 is used) 1864 * 1865 * Creates/frees an object cache on the XPath context. 1866 * If activates XPath objects (xmlXPathObject) will be cached internally 1867 * to be reused. 1868 * @options: 1869 * 0: This will set the XPath object caching: 1870 * @value: 1871 * This will set the maximum number of XPath objects 1872 * to be cached per slot 1873 * There are 5 slots for: node-set, string, number, boolean, and 1874 * misc objects. Use <0 for the default number (100). 1875 * Other values for @options have currently no effect. 1876 * 1877 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 1878 */ 1879int 1880xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 1881 int active, 1882 int value, 1883 int options) 1884{ 1885 if (ctxt == NULL) 1886 return(-1); 1887 if (active) { 1888 xmlXPathContextCachePtr cache; 1889 1890 if (ctxt->cache == NULL) { 1891 ctxt->cache = xmlXPathNewCache(); 1892 if (ctxt->cache == NULL) 1893 return(-1); 1894 } 1895 cache = (xmlXPathContextCachePtr) ctxt->cache; 1896 if (options == 0) { 1897 if (value < 0) 1898 value = 100; 1899 cache->maxNodeset = value; 1900 cache->maxString = value; 1901 cache->maxNumber = value; 1902 cache->maxBoolean = value; 1903 cache->maxMisc = value; 1904 } 1905 } else if (ctxt->cache != NULL) { 1906 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 1907 ctxt->cache = NULL; 1908 } 1909 return(0); 1910} 1911 1912/** 1913 * xmlXPathCacheWrapNodeSet: 1914 * @ctxt: the XPath context 1915 * @val: the NodePtr value 1916 * 1917 * This is the cached version of xmlXPathWrapNodeSet(). 1918 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 1919 * 1920 * Returns the created or reused object. 1921 */ 1922static xmlXPathObjectPtr 1923xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 1924{ 1925 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1926 xmlXPathContextCachePtr cache = 1927 (xmlXPathContextCachePtr) ctxt->cache; 1928 1929 if ((cache->miscObjs != NULL) && 1930 (cache->miscObjs->number != 0)) 1931 { 1932 xmlXPathObjectPtr ret; 1933 1934 ret = (xmlXPathObjectPtr) 1935 cache->miscObjs->items[--cache->miscObjs->number]; 1936 ret->type = XPATH_NODESET; 1937 ret->nodesetval = val; 1938#ifdef XP_DEBUG_OBJ_USAGE 1939 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 1940#endif 1941 return(ret); 1942 } 1943 } 1944 1945 return(xmlXPathWrapNodeSet(val)); 1946 1947} 1948 1949/** 1950 * xmlXPathCacheWrapString: 1951 * @ctxt: the XPath context 1952 * @val: the xmlChar * value 1953 * 1954 * This is the cached version of xmlXPathWrapString(). 1955 * Wraps the @val string into an XPath object. 1956 * 1957 * Returns the created or reused object. 1958 */ 1959static xmlXPathObjectPtr 1960xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 1961{ 1962 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1963 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 1964 1965 if ((cache->stringObjs != NULL) && 1966 (cache->stringObjs->number != 0)) 1967 { 1968 1969 xmlXPathObjectPtr ret; 1970 1971 ret = (xmlXPathObjectPtr) 1972 cache->stringObjs->items[--cache->stringObjs->number]; 1973 ret->type = XPATH_STRING; 1974 ret->stringval = val; 1975#ifdef XP_DEBUG_OBJ_USAGE 1976 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1977#endif 1978 return(ret); 1979 } else if ((cache->miscObjs != NULL) && 1980 (cache->miscObjs->number != 0)) 1981 { 1982 xmlXPathObjectPtr ret; 1983 /* 1984 * Fallback to misc-cache. 1985 */ 1986 ret = (xmlXPathObjectPtr) 1987 cache->miscObjs->items[--cache->miscObjs->number]; 1988 1989 ret->type = XPATH_STRING; 1990 ret->stringval = val; 1991#ifdef XP_DEBUG_OBJ_USAGE 1992 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1993#endif 1994 return(ret); 1995 } 1996 } 1997 return(xmlXPathWrapString(val)); 1998} 1999 2000/** 2001 * xmlXPathCacheNewNodeSet: 2002 * @ctxt: the XPath context 2003 * @val: the NodePtr value 2004 * 2005 * This is the cached version of xmlXPathNewNodeSet(). 2006 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2007 * it with the single Node @val 2008 * 2009 * Returns the created or reused object. 2010 */ 2011static xmlXPathObjectPtr 2012xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2013{ 2014 if ((ctxt != NULL) && (ctxt->cache)) { 2015 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2016 2017 if ((cache->nodesetObjs != NULL) && 2018 (cache->nodesetObjs->number != 0)) 2019 { 2020 xmlXPathObjectPtr ret; 2021 /* 2022 * Use the nodset-cache. 2023 */ 2024 ret = (xmlXPathObjectPtr) 2025 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2026 ret->type = XPATH_NODESET; 2027 ret->boolval = 0; 2028 if (val) { 2029 if ((ret->nodesetval->nodeMax == 0) || 2030 (val->type == XML_NAMESPACE_DECL)) 2031 { 2032 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2033 } else { 2034 ret->nodesetval->nodeTab[0] = val; 2035 ret->nodesetval->nodeNr = 1; 2036 } 2037 } 2038#ifdef XP_DEBUG_OBJ_USAGE 2039 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2040#endif 2041 return(ret); 2042 } else if ((cache->miscObjs != NULL) && 2043 (cache->miscObjs->number != 0)) 2044 { 2045 xmlXPathObjectPtr ret; 2046 /* 2047 * Fallback to misc-cache. 2048 */ 2049 2050 ret = (xmlXPathObjectPtr) 2051 cache->miscObjs->items[--cache->miscObjs->number]; 2052 2053 ret->type = XPATH_NODESET; 2054 ret->boolval = 0; 2055 ret->nodesetval = xmlXPathNodeSetCreate(val); 2056#ifdef XP_DEBUG_OBJ_USAGE 2057 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2058#endif 2059 return(ret); 2060 } 2061 } 2062 return(xmlXPathNewNodeSet(val)); 2063} 2064 2065/** 2066 * xmlXPathCacheNewCString: 2067 * @ctxt: the XPath context 2068 * @val: the char * value 2069 * 2070 * This is the cached version of xmlXPathNewCString(). 2071 * Acquire an xmlXPathObjectPtr of type string and of value @val 2072 * 2073 * Returns the created or reused object. 2074 */ 2075static xmlXPathObjectPtr 2076xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2077{ 2078 if ((ctxt != NULL) && (ctxt->cache)) { 2079 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2080 2081 if ((cache->stringObjs != NULL) && 2082 (cache->stringObjs->number != 0)) 2083 { 2084 xmlXPathObjectPtr ret; 2085 2086 ret = (xmlXPathObjectPtr) 2087 cache->stringObjs->items[--cache->stringObjs->number]; 2088 2089 ret->type = XPATH_STRING; 2090 ret->stringval = xmlStrdup(BAD_CAST val); 2091#ifdef XP_DEBUG_OBJ_USAGE 2092 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2093#endif 2094 return(ret); 2095 } else if ((cache->miscObjs != NULL) && 2096 (cache->miscObjs->number != 0)) 2097 { 2098 xmlXPathObjectPtr ret; 2099 2100 ret = (xmlXPathObjectPtr) 2101 cache->miscObjs->items[--cache->miscObjs->number]; 2102 2103 ret->type = XPATH_STRING; 2104 ret->stringval = xmlStrdup(BAD_CAST val); 2105#ifdef XP_DEBUG_OBJ_USAGE 2106 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2107#endif 2108 return(ret); 2109 } 2110 } 2111 return(xmlXPathNewCString(val)); 2112} 2113 2114/** 2115 * xmlXPathCacheNewString: 2116 * @ctxt: the XPath context 2117 * @val: the xmlChar * value 2118 * 2119 * This is the cached version of xmlXPathNewString(). 2120 * Acquire an xmlXPathObjectPtr of type string and of value @val 2121 * 2122 * Returns the created or reused object. 2123 */ 2124static xmlXPathObjectPtr 2125xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2126{ 2127 if ((ctxt != NULL) && (ctxt->cache)) { 2128 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2129 2130 if ((cache->stringObjs != NULL) && 2131 (cache->stringObjs->number != 0)) 2132 { 2133 xmlXPathObjectPtr ret; 2134 2135 ret = (xmlXPathObjectPtr) 2136 cache->stringObjs->items[--cache->stringObjs->number]; 2137 ret->type = XPATH_STRING; 2138 if (val != NULL) 2139 ret->stringval = xmlStrdup(val); 2140 else 2141 ret->stringval = xmlStrdup((const xmlChar *)""); 2142#ifdef XP_DEBUG_OBJ_USAGE 2143 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2144#endif 2145 return(ret); 2146 } else if ((cache->miscObjs != NULL) && 2147 (cache->miscObjs->number != 0)) 2148 { 2149 xmlXPathObjectPtr ret; 2150 2151 ret = (xmlXPathObjectPtr) 2152 cache->miscObjs->items[--cache->miscObjs->number]; 2153 2154 ret->type = XPATH_STRING; 2155 if (val != NULL) 2156 ret->stringval = xmlStrdup(val); 2157 else 2158 ret->stringval = xmlStrdup((const xmlChar *)""); 2159#ifdef XP_DEBUG_OBJ_USAGE 2160 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2161#endif 2162 return(ret); 2163 } 2164 } 2165 return(xmlXPathNewString(val)); 2166} 2167 2168/** 2169 * xmlXPathCacheNewBoolean: 2170 * @ctxt: the XPath context 2171 * @val: the boolean value 2172 * 2173 * This is the cached version of xmlXPathNewBoolean(). 2174 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2175 * 2176 * Returns the created or reused object. 2177 */ 2178static xmlXPathObjectPtr 2179xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2180{ 2181 if ((ctxt != NULL) && (ctxt->cache)) { 2182 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2183 2184 if ((cache->booleanObjs != NULL) && 2185 (cache->booleanObjs->number != 0)) 2186 { 2187 xmlXPathObjectPtr ret; 2188 2189 ret = (xmlXPathObjectPtr) 2190 cache->booleanObjs->items[--cache->booleanObjs->number]; 2191 ret->type = XPATH_BOOLEAN; 2192 ret->boolval = (val != 0); 2193#ifdef XP_DEBUG_OBJ_USAGE 2194 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2195#endif 2196 return(ret); 2197 } else if ((cache->miscObjs != NULL) && 2198 (cache->miscObjs->number != 0)) 2199 { 2200 xmlXPathObjectPtr ret; 2201 2202 ret = (xmlXPathObjectPtr) 2203 cache->miscObjs->items[--cache->miscObjs->number]; 2204 2205 ret->type = XPATH_BOOLEAN; 2206 ret->boolval = (val != 0); 2207#ifdef XP_DEBUG_OBJ_USAGE 2208 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2209#endif 2210 return(ret); 2211 } 2212 } 2213 return(xmlXPathNewBoolean(val)); 2214} 2215 2216/** 2217 * xmlXPathCacheNewFloat: 2218 * @ctxt: the XPath context 2219 * @val: the double value 2220 * 2221 * This is the cached version of xmlXPathNewFloat(). 2222 * Acquires an xmlXPathObjectPtr of type double and of value @val 2223 * 2224 * Returns the created or reused object. 2225 */ 2226static xmlXPathObjectPtr 2227xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2228{ 2229 if ((ctxt != NULL) && (ctxt->cache)) { 2230 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2231 2232 if ((cache->numberObjs != NULL) && 2233 (cache->numberObjs->number != 0)) 2234 { 2235 xmlXPathObjectPtr ret; 2236 2237 ret = (xmlXPathObjectPtr) 2238 cache->numberObjs->items[--cache->numberObjs->number]; 2239 ret->type = XPATH_NUMBER; 2240 ret->floatval = val; 2241#ifdef XP_DEBUG_OBJ_USAGE 2242 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2243#endif 2244 return(ret); 2245 } else if ((cache->miscObjs != NULL) && 2246 (cache->miscObjs->number != 0)) 2247 { 2248 xmlXPathObjectPtr ret; 2249 2250 ret = (xmlXPathObjectPtr) 2251 cache->miscObjs->items[--cache->miscObjs->number]; 2252 2253 ret->type = XPATH_NUMBER; 2254 ret->floatval = val; 2255#ifdef XP_DEBUG_OBJ_USAGE 2256 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2257#endif 2258 return(ret); 2259 } 2260 } 2261 return(xmlXPathNewFloat(val)); 2262} 2263 2264/** 2265 * xmlXPathCacheConvertString: 2266 * @ctxt: the XPath context 2267 * @val: an XPath object 2268 * 2269 * This is the cached version of xmlXPathConvertString(). 2270 * Converts an existing object to its string() equivalent 2271 * 2272 * Returns a created or reused object, the old one is freed (cached) 2273 * (or the operation is done directly on @val) 2274 */ 2275 2276static xmlXPathObjectPtr 2277xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2278 xmlChar *res = NULL; 2279 2280 if (val == NULL) 2281 return(xmlXPathCacheNewCString(ctxt, "")); 2282 2283 switch (val->type) { 2284 case XPATH_UNDEFINED: 2285#ifdef DEBUG_EXPR 2286 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2287#endif 2288 break; 2289 case XPATH_NODESET: 2290 case XPATH_XSLT_TREE: 2291 res = xmlXPathCastNodeSetToString(val->nodesetval); 2292 break; 2293 case XPATH_STRING: 2294 return(val); 2295 case XPATH_BOOLEAN: 2296 res = xmlXPathCastBooleanToString(val->boolval); 2297 break; 2298 case XPATH_NUMBER: 2299 res = xmlXPathCastNumberToString(val->floatval); 2300 break; 2301 case XPATH_USERS: 2302 case XPATH_POINT: 2303 case XPATH_RANGE: 2304 case XPATH_LOCATIONSET: 2305 TODO; 2306 break; 2307 } 2308 xmlXPathReleaseObject(ctxt, val); 2309 if (res == NULL) 2310 return(xmlXPathCacheNewCString(ctxt, "")); 2311 return(xmlXPathCacheWrapString(ctxt, res)); 2312} 2313 2314/** 2315 * xmlXPathCacheObjectCopy: 2316 * @ctxt: the XPath context 2317 * @val: the original object 2318 * 2319 * This is the cached version of xmlXPathObjectCopy(). 2320 * Acquire a copy of a given object 2321 * 2322 * Returns a created or reused created object. 2323 */ 2324static xmlXPathObjectPtr 2325xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2326{ 2327 if (val == NULL) 2328 return(NULL); 2329 2330 switch (val->type) { 2331 case XPATH_NODESET: 2332 if (XP_HAS_CACHE(ctxt)) 2333 return(xmlXPathCacheWrapNodeSet(ctxt, 2334 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2335 case XPATH_STRING: 2336 if (XP_HAS_CACHE(ctxt)) 2337 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2338 case XPATH_BOOLEAN: 2339 if (XP_HAS_CACHE(ctxt)) 2340 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2341 case XPATH_NUMBER: 2342 if (XP_HAS_CACHE(ctxt)) 2343 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2344 default: 2345 break; 2346 } 2347 return(xmlXPathObjectCopy(val)); 2348} 2349 2350/** 2351 * xmlXPathCacheConvertBoolean: 2352 * @ctxt: the XPath context 2353 * @val: an XPath object 2354 * 2355 * This is the cached version of xmlXPathConvertBoolean(). 2356 * Converts an existing object to its boolean() equivalent 2357 * 2358 * Returns a created or reused object, the old one is freed (or the operation 2359 * is done directly on @val) 2360 */ 2361static xmlXPathObjectPtr 2362xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2363 xmlXPathObjectPtr ret; 2364 2365 if (val == NULL) 2366 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2367 if (val->type == XPATH_BOOLEAN) 2368 return(val); 2369 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2370 xmlXPathReleaseObject(ctxt, val); 2371 return(ret); 2372} 2373 2374/** 2375 * xmlXPathCacheConvertNumber: 2376 * @ctxt: the XPath context 2377 * @val: an XPath object 2378 * 2379 * This is the cached version of xmlXPathConvertNumber(). 2380 * Converts an existing object to its number() equivalent 2381 * 2382 * Returns a created or reused object, the old one is freed (or the operation 2383 * is done directly on @val) 2384 */ 2385static xmlXPathObjectPtr 2386xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2387 xmlXPathObjectPtr ret; 2388 2389 if (val == NULL) 2390 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2391 if (val->type == XPATH_NUMBER) 2392 return(val); 2393 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2394 xmlXPathReleaseObject(ctxt, val); 2395 return(ret); 2396} 2397 2398/************************************************************************ 2399 * * 2400 * Parser stacks related functions and macros * 2401 * * 2402 ************************************************************************/ 2403 2404/** 2405 * valuePop: 2406 * @ctxt: an XPath evaluation context 2407 * 2408 * Pops the top XPath object from the value stack 2409 * 2410 * Returns the XPath object just removed 2411 */ 2412xmlXPathObjectPtr 2413valuePop(xmlXPathParserContextPtr ctxt) 2414{ 2415 xmlXPathObjectPtr ret; 2416 2417 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2418 return (NULL); 2419 ctxt->valueNr--; 2420 if (ctxt->valueNr > 0) 2421 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2422 else 2423 ctxt->value = NULL; 2424 ret = ctxt->valueTab[ctxt->valueNr]; 2425 ctxt->valueTab[ctxt->valueNr] = NULL; 2426 return (ret); 2427} 2428/** 2429 * valuePush: 2430 * @ctxt: an XPath evaluation context 2431 * @value: the XPath object 2432 * 2433 * Pushes a new XPath object on top of the value stack 2434 * 2435 * returns the number of items on the value stack 2436 */ 2437int 2438valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2439{ 2440 if ((ctxt == NULL) || (value == NULL)) return(-1); 2441 if (ctxt->valueNr >= ctxt->valueMax) { 2442 xmlXPathObjectPtr *tmp; 2443 2444 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2445 2 * ctxt->valueMax * 2446 sizeof(ctxt->valueTab[0])); 2447 if (tmp == NULL) { 2448 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 2449 return (0); 2450 } 2451 ctxt->valueMax *= 2; 2452 ctxt->valueTab = tmp; 2453 } 2454 ctxt->valueTab[ctxt->valueNr] = value; 2455 ctxt->value = value; 2456 return (ctxt->valueNr++); 2457} 2458 2459/** 2460 * xmlXPathPopBoolean: 2461 * @ctxt: an XPath parser context 2462 * 2463 * Pops a boolean from the stack, handling conversion if needed. 2464 * Check error with #xmlXPathCheckError. 2465 * 2466 * Returns the boolean 2467 */ 2468int 2469xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2470 xmlXPathObjectPtr obj; 2471 int ret; 2472 2473 obj = valuePop(ctxt); 2474 if (obj == NULL) { 2475 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2476 return(0); 2477 } 2478 if (obj->type != XPATH_BOOLEAN) 2479 ret = xmlXPathCastToBoolean(obj); 2480 else 2481 ret = obj->boolval; 2482 xmlXPathReleaseObject(ctxt->context, obj); 2483 return(ret); 2484} 2485 2486/** 2487 * xmlXPathPopNumber: 2488 * @ctxt: an XPath parser context 2489 * 2490 * Pops a number from the stack, handling conversion if needed. 2491 * Check error with #xmlXPathCheckError. 2492 * 2493 * Returns the number 2494 */ 2495double 2496xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2497 xmlXPathObjectPtr obj; 2498 double ret; 2499 2500 obj = valuePop(ctxt); 2501 if (obj == NULL) { 2502 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2503 return(0); 2504 } 2505 if (obj->type != XPATH_NUMBER) 2506 ret = xmlXPathCastToNumber(obj); 2507 else 2508 ret = obj->floatval; 2509 xmlXPathReleaseObject(ctxt->context, obj); 2510 return(ret); 2511} 2512 2513/** 2514 * xmlXPathPopString: 2515 * @ctxt: an XPath parser context 2516 * 2517 * Pops a string from the stack, handling conversion if needed. 2518 * Check error with #xmlXPathCheckError. 2519 * 2520 * Returns the string 2521 */ 2522xmlChar * 2523xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2524 xmlXPathObjectPtr obj; 2525 xmlChar * ret; 2526 2527 obj = valuePop(ctxt); 2528 if (obj == NULL) { 2529 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2530 return(NULL); 2531 } 2532 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2533 /* TODO: needs refactoring somewhere else */ 2534 if (obj->stringval == ret) 2535 obj->stringval = NULL; 2536 xmlXPathReleaseObject(ctxt->context, obj); 2537 return(ret); 2538} 2539 2540/** 2541 * xmlXPathPopNodeSet: 2542 * @ctxt: an XPath parser context 2543 * 2544 * Pops a node-set from the stack, handling conversion if needed. 2545 * Check error with #xmlXPathCheckError. 2546 * 2547 * Returns the node-set 2548 */ 2549xmlNodeSetPtr 2550xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 2551 xmlXPathObjectPtr obj; 2552 xmlNodeSetPtr ret; 2553 2554 if (ctxt == NULL) return(NULL); 2555 if (ctxt->value == NULL) { 2556 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2557 return(NULL); 2558 } 2559 if (!xmlXPathStackIsNodeSet(ctxt)) { 2560 xmlXPathSetTypeError(ctxt); 2561 return(NULL); 2562 } 2563 obj = valuePop(ctxt); 2564 ret = obj->nodesetval; 2565#if 0 2566 /* to fix memory leak of not clearing obj->user */ 2567 if (obj->boolval && obj->user != NULL) 2568 xmlFreeNodeList((xmlNodePtr) obj->user); 2569#endif 2570 obj->nodesetval = NULL; 2571 xmlXPathReleaseObject(ctxt->context, obj); 2572 return(ret); 2573} 2574 2575/** 2576 * xmlXPathPopExternal: 2577 * @ctxt: an XPath parser context 2578 * 2579 * Pops an external object from the stack, handling conversion if needed. 2580 * Check error with #xmlXPathCheckError. 2581 * 2582 * Returns the object 2583 */ 2584void * 2585xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 2586 xmlXPathObjectPtr obj; 2587 void * ret; 2588 2589 if ((ctxt == NULL) || (ctxt->value == NULL)) { 2590 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2591 return(NULL); 2592 } 2593 if (ctxt->value->type != XPATH_USERS) { 2594 xmlXPathSetTypeError(ctxt); 2595 return(NULL); 2596 } 2597 obj = valuePop(ctxt); 2598 ret = obj->user; 2599 obj->user = NULL; 2600 xmlXPathReleaseObject(ctxt->context, obj); 2601 return(ret); 2602} 2603 2604/* 2605 * Macros for accessing the content. Those should be used only by the parser, 2606 * and not exported. 2607 * 2608 * Dirty macros, i.e. one need to make assumption on the context to use them 2609 * 2610 * CUR_PTR return the current pointer to the xmlChar to be parsed. 2611 * CUR returns the current xmlChar value, i.e. a 8 bit value 2612 * in ISO-Latin or UTF-8. 2613 * This should be used internally by the parser 2614 * only to compare to ASCII values otherwise it would break when 2615 * running with UTF-8 encoding. 2616 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 2617 * to compare on ASCII based substring. 2618 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 2619 * strings within the parser. 2620 * CURRENT Returns the current char value, with the full decoding of 2621 * UTF-8 if we are using this mode. It returns an int. 2622 * NEXT Skip to the next character, this does the proper decoding 2623 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 2624 * It returns the pointer to the current xmlChar. 2625 */ 2626 2627#define CUR (*ctxt->cur) 2628#define SKIP(val) ctxt->cur += (val) 2629#define NXT(val) ctxt->cur[(val)] 2630#define CUR_PTR ctxt->cur 2631#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 2632 2633#define COPY_BUF(l,b,i,v) \ 2634 if (l == 1) b[i++] = (xmlChar) v; \ 2635 else i += xmlCopyChar(l,&b[i],v) 2636 2637#define NEXTL(l) ctxt->cur += l 2638 2639#define SKIP_BLANKS \ 2640 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 2641 2642#define CURRENT (*ctxt->cur) 2643#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 2644 2645 2646#ifndef DBL_DIG 2647#define DBL_DIG 16 2648#endif 2649#ifndef DBL_EPSILON 2650#define DBL_EPSILON 1E-9 2651#endif 2652 2653#define UPPER_DOUBLE 1E9 2654#define LOWER_DOUBLE 1E-5 2655 2656#define INTEGER_DIGITS DBL_DIG 2657#define FRACTION_DIGITS (DBL_DIG + 1) 2658#define EXPONENT_DIGITS (3 + 2) 2659 2660/** 2661 * xmlXPathFormatNumber: 2662 * @number: number to format 2663 * @buffer: output buffer 2664 * @buffersize: size of output buffer 2665 * 2666 * Convert the number into a string representation. 2667 */ 2668static void 2669xmlXPathFormatNumber(double number, char buffer[], int buffersize) 2670{ 2671 switch (xmlXPathIsInf(number)) { 2672 case 1: 2673 if (buffersize > (int)sizeof("Infinity")) 2674 snprintf(buffer, buffersize, "Infinity"); 2675 break; 2676 case -1: 2677 if (buffersize > (int)sizeof("-Infinity")) 2678 snprintf(buffer, buffersize, "-Infinity"); 2679 break; 2680 default: 2681 if (xmlXPathIsNaN(number)) { 2682 if (buffersize > (int)sizeof("NaN")) 2683 snprintf(buffer, buffersize, "NaN"); 2684 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 2685 snprintf(buffer, buffersize, "0"); 2686 } else if (number == ((int) number)) { 2687 char work[30]; 2688 char *ptr, *cur; 2689 int value = (int) number; 2690 2691 ptr = &buffer[0]; 2692 if (value == 0) { 2693 *ptr++ = '0'; 2694 } else { 2695 snprintf(work, 29, "%d", value); 2696 cur = &work[0]; 2697 while ((*cur) && (ptr - buffer < buffersize)) { 2698 *ptr++ = *cur++; 2699 } 2700 } 2701 if (ptr - buffer < buffersize) { 2702 *ptr = 0; 2703 } else if (buffersize > 0) { 2704 ptr--; 2705 *ptr = 0; 2706 } 2707 } else { 2708 /* 3 is sign, decimal point, and terminating zero */ 2709 char work[DBL_DIG + EXPONENT_DIGITS + 3]; 2710 int integer_place, fraction_place; 2711 char *ptr; 2712 char *after_fraction; 2713 double absolute_value; 2714 int size; 2715 2716 absolute_value = fabs(number); 2717 2718 /* 2719 * First choose format - scientific or regular floating point. 2720 * In either case, result is in work, and after_fraction points 2721 * just past the fractional part. 2722 */ 2723 if ( ((absolute_value > UPPER_DOUBLE) || 2724 (absolute_value < LOWER_DOUBLE)) && 2725 (absolute_value != 0.0) ) { 2726 /* Use scientific notation */ 2727 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 2728 fraction_place = DBL_DIG - 1; 2729 size = snprintf(work, sizeof(work),"%*.*e", 2730 integer_place, fraction_place, number); 2731 while ((size > 0) && (work[size] != 'e')) size--; 2732 after_fraction = work + size; 2733 2734 } 2735 else { 2736 /* Use regular notation */ 2737 if (absolute_value > 0.0) 2738 integer_place = 1 + (int)log10(absolute_value); 2739 else 2740 integer_place = 0; 2741 fraction_place = (integer_place > 0) 2742 ? DBL_DIG - integer_place 2743 : DBL_DIG; 2744 size = snprintf(work, sizeof(work), "%0.*f", 2745 fraction_place, number); 2746 after_fraction = work + size; 2747 } 2748 2749 /* Remove fractional trailing zeroes */ 2750 ptr = after_fraction; 2751 while (*(--ptr) == '0') 2752 ; 2753 if (*ptr != '.') 2754 ptr++; 2755 while ((*ptr++ = *after_fraction++) != 0); 2756 2757 /* Finally copy result back to caller */ 2758 size = strlen(work) + 1; 2759 if (size > buffersize) { 2760 work[buffersize - 1] = 0; 2761 size = buffersize; 2762 } 2763 memmove(buffer, work, size); 2764 } 2765 break; 2766 } 2767} 2768 2769 2770/************************************************************************ 2771 * * 2772 * Routines to handle NodeSets * 2773 * * 2774 ************************************************************************/ 2775 2776/** 2777 * xmlXPathOrderDocElems: 2778 * @doc: an input document 2779 * 2780 * Call this routine to speed up XPath computation on static documents. 2781 * This stamps all the element nodes with the document order 2782 * Like for line information, the order is kept in the element->content 2783 * field, the value stored is actually - the node number (starting at -1) 2784 * to be able to differentiate from line numbers. 2785 * 2786 * Returns the number of elements found in the document or -1 in case 2787 * of error. 2788 */ 2789long 2790xmlXPathOrderDocElems(xmlDocPtr doc) { 2791 long count = 0; 2792 xmlNodePtr cur; 2793 2794 if (doc == NULL) 2795 return(-1); 2796 cur = doc->children; 2797 while (cur != NULL) { 2798 if (cur->type == XML_ELEMENT_NODE) { 2799 cur->content = (void *) (-(++count)); 2800 if (cur->children != NULL) { 2801 cur = cur->children; 2802 continue; 2803 } 2804 } 2805 if (cur->next != NULL) { 2806 cur = cur->next; 2807 continue; 2808 } 2809 do { 2810 cur = cur->parent; 2811 if (cur == NULL) 2812 break; 2813 if (cur == (xmlNodePtr) doc) { 2814 cur = NULL; 2815 break; 2816 } 2817 if (cur->next != NULL) { 2818 cur = cur->next; 2819 break; 2820 } 2821 } while (cur != NULL); 2822 } 2823 return(count); 2824} 2825 2826/** 2827 * xmlXPathCmpNodes: 2828 * @node1: the first node 2829 * @node2: the second node 2830 * 2831 * Compare two nodes w.r.t document order 2832 * 2833 * Returns -2 in case of error 1 if first point < second point, 0 if 2834 * it's the same node, -1 otherwise 2835 */ 2836int 2837xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 2838 int depth1, depth2; 2839 int attr1 = 0, attr2 = 0; 2840 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 2841 xmlNodePtr cur, root; 2842 2843 if ((node1 == NULL) || (node2 == NULL)) 2844 return(-2); 2845 /* 2846 * a couple of optimizations which will avoid computations in most cases 2847 */ 2848 if (node1->type == XML_ATTRIBUTE_NODE) { 2849 attr1 = 1; 2850 attrNode1 = node1; 2851 node1 = node1->parent; 2852 } 2853 if (node2->type == XML_ATTRIBUTE_NODE) { 2854 attr2 = 1; 2855 attrNode2 = node2; 2856 node2 = node2->parent; 2857 } 2858 if (node1 == node2) { 2859 if (attr1 == attr2) { 2860 /* not required, but we keep attributes in order */ 2861 if (attr1 != 0) { 2862 cur = attrNode2->prev; 2863 while (cur != NULL) { 2864 if (cur == attrNode1) 2865 return (1); 2866 cur = cur->prev; 2867 } 2868 return (-1); 2869 } 2870 return(0); 2871 } 2872 if (attr2 == 1) 2873 return(1); 2874 return(-1); 2875 } 2876 if ((node1->type == XML_NAMESPACE_DECL) || 2877 (node2->type == XML_NAMESPACE_DECL)) 2878 return(1); 2879 if (node1 == node2->prev) 2880 return(1); 2881 if (node1 == node2->next) 2882 return(-1); 2883 2884 /* 2885 * Speedup using document order if availble. 2886 */ 2887 if ((node1->type == XML_ELEMENT_NODE) && 2888 (node2->type == XML_ELEMENT_NODE) && 2889 (0 > (long) node1->content) && 2890 (0 > (long) node2->content) && 2891 (node1->doc == node2->doc)) { 2892 long l1, l2; 2893 2894 l1 = -((long) node1->content); 2895 l2 = -((long) node2->content); 2896 if (l1 < l2) 2897 return(1); 2898 if (l1 > l2) 2899 return(-1); 2900 } 2901 2902 /* 2903 * compute depth to root 2904 */ 2905 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 2906 if (cur == node1) 2907 return(1); 2908 depth2++; 2909 } 2910 root = cur; 2911 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 2912 if (cur == node2) 2913 return(-1); 2914 depth1++; 2915 } 2916 /* 2917 * Distinct document (or distinct entities :-( ) case. 2918 */ 2919 if (root != cur) { 2920 return(-2); 2921 } 2922 /* 2923 * get the nearest common ancestor. 2924 */ 2925 while (depth1 > depth2) { 2926 depth1--; 2927 node1 = node1->parent; 2928 } 2929 while (depth2 > depth1) { 2930 depth2--; 2931 node2 = node2->parent; 2932 } 2933 while (node1->parent != node2->parent) { 2934 node1 = node1->parent; 2935 node2 = node2->parent; 2936 /* should not happen but just in case ... */ 2937 if ((node1 == NULL) || (node2 == NULL)) 2938 return(-2); 2939 } 2940 /* 2941 * Find who's first. 2942 */ 2943 if (node1 == node2->prev) 2944 return(1); 2945 if (node1 == node2->next) 2946 return(-1); 2947 /* 2948 * Speedup using document order if availble. 2949 */ 2950 if ((node1->type == XML_ELEMENT_NODE) && 2951 (node2->type == XML_ELEMENT_NODE) && 2952 (0 > (long) node1->content) && 2953 (0 > (long) node2->content) && 2954 (node1->doc == node2->doc)) { 2955 long l1, l2; 2956 2957 l1 = -((long) node1->content); 2958 l2 = -((long) node2->content); 2959 if (l1 < l2) 2960 return(1); 2961 if (l1 > l2) 2962 return(-1); 2963 } 2964 2965 for (cur = node1->next;cur != NULL;cur = cur->next) 2966 if (cur == node2) 2967 return(1); 2968 return(-1); /* assume there is no sibling list corruption */ 2969} 2970 2971#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 2972/** 2973 * xmlXPathCmpNodesExt: 2974 * @node1: the first node 2975 * @node2: the second node 2976 * 2977 * Compare two nodes w.r.t document order. 2978 * This one is optimized for handling of non-element nodes. 2979 * 2980 * Returns -2 in case of error 1 if first point < second point, 0 if 2981 * it's the same node, -1 otherwise 2982 */ 2983static int 2984xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 2985 int depth1, depth2; 2986 int misc = 0, precedence1 = 0, precedence2 = 0; 2987 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 2988 xmlNodePtr cur, root; 2989 long l1, l2; 2990 2991 if ((node1 == NULL) || (node2 == NULL)) 2992 return(-2); 2993 2994 if (node1 == node2) 2995 return(0); 2996 2997 /* 2998 * a couple of optimizations which will avoid computations in most cases 2999 */ 3000 switch (node1->type) { 3001 case XML_ELEMENT_NODE: 3002 if (node2->type == XML_ELEMENT_NODE) { 3003 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */ 3004 (0 > (long) node2->content) && 3005 (node1->doc == node2->doc)) 3006 { 3007 l1 = -((long) node1->content); 3008 l2 = -((long) node2->content); 3009 if (l1 < l2) 3010 return(1); 3011 if (l1 > l2) 3012 return(-1); 3013 } else 3014 goto turtle_comparison; 3015 } 3016 break; 3017 case XML_ATTRIBUTE_NODE: 3018 precedence1 = 1; /* element is owner */ 3019 miscNode1 = node1; 3020 node1 = node1->parent; 3021 misc = 1; 3022 break; 3023 case XML_TEXT_NODE: 3024 case XML_CDATA_SECTION_NODE: 3025 case XML_COMMENT_NODE: 3026 case XML_PI_NODE: { 3027 miscNode1 = node1; 3028 /* 3029 * Find nearest element node. 3030 */ 3031 if (node1->prev != NULL) { 3032 do { 3033 node1 = node1->prev; 3034 if (node1->type == XML_ELEMENT_NODE) { 3035 precedence1 = 3; /* element in prev-sibl axis */ 3036 break; 3037 } 3038 if (node1->prev == NULL) { 3039 precedence1 = 2; /* element is parent */ 3040 /* 3041 * URGENT TODO: Are there any cases, where the 3042 * parent of such a node is not an element node? 3043 */ 3044 node1 = node1->parent; 3045 break; 3046 } 3047 } while (1); 3048 } else { 3049 precedence1 = 2; /* element is parent */ 3050 node1 = node1->parent; 3051 } 3052 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) { 3053 /* 3054 * Fallback for whatever case. 3055 */ 3056 node1 = miscNode1; 3057 precedence1 = 0; 3058 } else 3059 misc = 1; 3060 } 3061 break; 3062 case XML_NAMESPACE_DECL: 3063 /* 3064 * TODO: why do we return 1 for namespace nodes? 3065 */ 3066 return(1); 3067 default: 3068 break; 3069 } 3070 switch (node2->type) { 3071 case XML_ELEMENT_NODE: 3072 break; 3073 case XML_ATTRIBUTE_NODE: 3074 precedence2 = 1; /* element is owner */ 3075 miscNode2 = node2; 3076 node2 = node2->parent; 3077 misc = 1; 3078 break; 3079 case XML_TEXT_NODE: 3080 case XML_CDATA_SECTION_NODE: 3081 case XML_COMMENT_NODE: 3082 case XML_PI_NODE: { 3083 miscNode2 = node2; 3084 if (node2->prev != NULL) { 3085 do { 3086 node2 = node2->prev; 3087 if (node2->type == XML_ELEMENT_NODE) { 3088 precedence2 = 3; /* element in prev-sibl axis */ 3089 break; 3090 } 3091 if (node2->prev == NULL) { 3092 precedence2 = 2; /* element is parent */ 3093 node2 = node2->parent; 3094 break; 3095 } 3096 } while (1); 3097 } else { 3098 precedence2 = 2; /* element is parent */ 3099 node2 = node2->parent; 3100 } 3101 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 3102 (0 <= (long) node1->content)) 3103 { 3104 node2 = miscNode2; 3105 precedence2 = 0; 3106 } else 3107 misc = 1; 3108 } 3109 break; 3110 case XML_NAMESPACE_DECL: 3111 return(1); 3112 default: 3113 break; 3114 } 3115 if (misc) { 3116 if (node1 == node2) { 3117 if (precedence1 == precedence2) { 3118 /* 3119 * The ugly case; but normally there aren't many 3120 * adjacent non-element nodes around. 3121 */ 3122 cur = miscNode2->prev; 3123 while (cur != NULL) { 3124 if (cur == miscNode1) 3125 return(1); 3126 if (cur->type == XML_ELEMENT_NODE) 3127 return(-1); 3128 cur = cur->prev; 3129 } 3130 return (-1); 3131 } else { 3132 /* 3133 * Evaluate based on higher precedence wrt to the element. 3134 * TODO: This assumes attributes are sorted before content. 3135 * Is this 100% correct? 3136 */ 3137 if (precedence1 < precedence2) 3138 return(1); 3139 else 3140 return(-1); 3141 } 3142 } 3143 /* 3144 * Special case: One of the helper-elements is contained by the other. 3145 * <foo> 3146 * <node2> 3147 * <node1>Text-1(precedence1 == 2)</node1> 3148 * </node2> 3149 * Text-6(precedence2 == 3) 3150 * </foo> 3151 */ 3152 if ((precedence2 == 3) && (precedence1 > 1)) { 3153 cur = node1->parent; 3154 while (cur) { 3155 if (cur == node2) 3156 return(1); 3157 cur = cur->parent; 3158 } 3159 } 3160 if ((precedence1 == 3) && (precedence2 > 1)) { 3161 cur = node2->parent; 3162 while (cur) { 3163 if (cur == node1) 3164 return(-1); 3165 cur = cur->parent; 3166 } 3167 } 3168 } 3169 3170 /* 3171 * Speedup using document order if availble. 3172 */ 3173 if ((node1->type == XML_ELEMENT_NODE) && 3174 (node2->type == XML_ELEMENT_NODE) && 3175 (0 > (long) node1->content) && 3176 (0 > (long) node2->content) && 3177 (node1->doc == node2->doc)) { 3178 3179 l1 = -((long) node1->content); 3180 l2 = -((long) node2->content); 3181 if (l1 < l2) 3182 return(1); 3183 if (l1 > l2) 3184 return(-1); 3185 } 3186 3187turtle_comparison: 3188 3189 if (node1 == node2->prev) 3190 return(1); 3191 if (node1 == node2->next) 3192 return(-1); 3193 /* 3194 * compute depth to root 3195 */ 3196 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3197 if (cur == node1) 3198 return(1); 3199 depth2++; 3200 } 3201 root = cur; 3202 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3203 if (cur == node2) 3204 return(-1); 3205 depth1++; 3206 } 3207 /* 3208 * Distinct document (or distinct entities :-( ) case. 3209 */ 3210 if (root != cur) { 3211 return(-2); 3212 } 3213 /* 3214 * get the nearest common ancestor. 3215 */ 3216 while (depth1 > depth2) { 3217 depth1--; 3218 node1 = node1->parent; 3219 } 3220 while (depth2 > depth1) { 3221 depth2--; 3222 node2 = node2->parent; 3223 } 3224 while (node1->parent != node2->parent) { 3225 node1 = node1->parent; 3226 node2 = node2->parent; 3227 /* should not happen but just in case ... */ 3228 if ((node1 == NULL) || (node2 == NULL)) 3229 return(-2); 3230 } 3231 /* 3232 * Find who's first. 3233 */ 3234 if (node1 == node2->prev) 3235 return(1); 3236 if (node1 == node2->next) 3237 return(-1); 3238 /* 3239 * Speedup using document order if availble. 3240 */ 3241 if ((node1->type == XML_ELEMENT_NODE) && 3242 (node2->type == XML_ELEMENT_NODE) && 3243 (0 > (long) node1->content) && 3244 (0 > (long) node2->content) && 3245 (node1->doc == node2->doc)) { 3246 3247 l1 = -((long) node1->content); 3248 l2 = -((long) node2->content); 3249 if (l1 < l2) 3250 return(1); 3251 if (l1 > l2) 3252 return(-1); 3253 } 3254 3255 for (cur = node1->next;cur != NULL;cur = cur->next) 3256 if (cur == node2) 3257 return(1); 3258 return(-1); /* assume there is no sibling list corruption */ 3259} 3260#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 3261 3262/** 3263 * xmlXPathNodeSetSort: 3264 * @set: the node set 3265 * 3266 * Sort the node set in document order 3267 */ 3268void 3269xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3270 int i, j, incr, len; 3271 xmlNodePtr tmp; 3272 3273 if (set == NULL) 3274 return; 3275 3276 /* Use Shell's sort to sort the node-set */ 3277 len = set->nodeNr; 3278 for (incr = len / 2; incr > 0; incr /= 2) { 3279 for (i = incr; i < len; i++) { 3280 j = i - incr; 3281 while (j >= 0) { 3282#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3283 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3284 set->nodeTab[j + incr]) == -1) 3285#else 3286 if (xmlXPathCmpNodes(set->nodeTab[j], 3287 set->nodeTab[j + incr]) == -1) 3288#endif 3289 { 3290 tmp = set->nodeTab[j]; 3291 set->nodeTab[j] = set->nodeTab[j + incr]; 3292 set->nodeTab[j + incr] = tmp; 3293 j -= incr; 3294 } else 3295 break; 3296 } 3297 } 3298 } 3299} 3300 3301#define XML_NODESET_DEFAULT 10 3302/** 3303 * xmlXPathNodeSetDupNs: 3304 * @node: the parent node of the namespace XPath node 3305 * @ns: the libxml namespace declaration node. 3306 * 3307 * Namespace node in libxml don't match the XPath semantic. In a node set 3308 * the namespace nodes are duplicated and the next pointer is set to the 3309 * parent node in the XPath semantic. 3310 * 3311 * Returns the newly created object. 3312 */ 3313static xmlNodePtr 3314xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3315 xmlNsPtr cur; 3316 3317 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3318 return(NULL); 3319 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3320 return((xmlNodePtr) ns); 3321 3322 /* 3323 * Allocate a new Namespace and fill the fields. 3324 */ 3325 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3326 if (cur == NULL) { 3327 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3328 return(NULL); 3329 } 3330 memset(cur, 0, sizeof(xmlNs)); 3331 cur->type = XML_NAMESPACE_DECL; 3332 if (ns->href != NULL) 3333 cur->href = xmlStrdup(ns->href); 3334 if (ns->prefix != NULL) 3335 cur->prefix = xmlStrdup(ns->prefix); 3336 cur->next = (xmlNsPtr) node; 3337 return((xmlNodePtr) cur); 3338} 3339 3340/** 3341 * xmlXPathNodeSetFreeNs: 3342 * @ns: the XPath namespace node found in a nodeset. 3343 * 3344 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3345 * the namespace nodes are duplicated and the next pointer is set to the 3346 * parent node in the XPath semantic. Check if such a node needs to be freed 3347 */ 3348void 3349xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3350 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3351 return; 3352 3353 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3354 if (ns->href != NULL) 3355 xmlFree((xmlChar *)ns->href); 3356 if (ns->prefix != NULL) 3357 xmlFree((xmlChar *)ns->prefix); 3358 xmlFree(ns); 3359 } 3360} 3361 3362/** 3363 * xmlXPathNodeSetCreate: 3364 * @val: an initial xmlNodePtr, or NULL 3365 * 3366 * Create a new xmlNodeSetPtr of type double and of value @val 3367 * 3368 * Returns the newly created object. 3369 */ 3370xmlNodeSetPtr 3371xmlXPathNodeSetCreate(xmlNodePtr val) { 3372 xmlNodeSetPtr ret; 3373 3374 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3375 if (ret == NULL) { 3376 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3377 return(NULL); 3378 } 3379 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3380 if (val != NULL) { 3381 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3382 sizeof(xmlNodePtr)); 3383 if (ret->nodeTab == NULL) { 3384 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3385 xmlFree(ret); 3386 return(NULL); 3387 } 3388 memset(ret->nodeTab, 0 , 3389 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3390 ret->nodeMax = XML_NODESET_DEFAULT; 3391 if (val->type == XML_NAMESPACE_DECL) { 3392 xmlNsPtr ns = (xmlNsPtr) val; 3393 3394 ret->nodeTab[ret->nodeNr++] = 3395 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3396 } else 3397 ret->nodeTab[ret->nodeNr++] = val; 3398 } 3399 return(ret); 3400} 3401 3402/** 3403 * xmlXPathNodeSetContains: 3404 * @cur: the node-set 3405 * @val: the node 3406 * 3407 * checks whether @cur contains @val 3408 * 3409 * Returns true (1) if @cur contains @val, false (0) otherwise 3410 */ 3411int 3412xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3413 int i; 3414 3415 if ((cur == NULL) || (val == NULL)) return(0); 3416 if (val->type == XML_NAMESPACE_DECL) { 3417 for (i = 0; i < cur->nodeNr; i++) { 3418 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3419 xmlNsPtr ns1, ns2; 3420 3421 ns1 = (xmlNsPtr) val; 3422 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3423 if (ns1 == ns2) 3424 return(1); 3425 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3426 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3427 return(1); 3428 } 3429 } 3430 } else { 3431 for (i = 0; i < cur->nodeNr; i++) { 3432 if (cur->nodeTab[i] == val) 3433 return(1); 3434 } 3435 } 3436 return(0); 3437} 3438 3439/** 3440 * xmlXPathNodeSetAddNs: 3441 * @cur: the initial node set 3442 * @node: the hosting node 3443 * @ns: a the namespace node 3444 * 3445 * add a new namespace node to an existing NodeSet 3446 */ 3447void 3448xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3449 int i; 3450 3451 3452 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3453 (ns->type != XML_NAMESPACE_DECL) || 3454 (node->type != XML_ELEMENT_NODE)) 3455 return; 3456 3457 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3458 /* 3459 * prevent duplicates 3460 */ 3461 for (i = 0;i < cur->nodeNr;i++) { 3462 if ((cur->nodeTab[i] != NULL) && 3463 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3464 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3465 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3466 return; 3467 } 3468 3469 /* 3470 * grow the nodeTab if needed 3471 */ 3472 if (cur->nodeMax == 0) { 3473 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3474 sizeof(xmlNodePtr)); 3475 if (cur->nodeTab == NULL) { 3476 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3477 return; 3478 } 3479 memset(cur->nodeTab, 0 , 3480 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3481 cur->nodeMax = XML_NODESET_DEFAULT; 3482 } else if (cur->nodeNr == cur->nodeMax) { 3483 xmlNodePtr *temp; 3484 3485 cur->nodeMax *= 2; 3486 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3487 sizeof(xmlNodePtr)); 3488 if (temp == NULL) { 3489 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3490 return; 3491 } 3492 cur->nodeTab = temp; 3493 } 3494 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3495} 3496 3497/** 3498 * xmlXPathNodeSetAdd: 3499 * @cur: the initial node set 3500 * @val: a new xmlNodePtr 3501 * 3502 * add a new xmlNodePtr to an existing NodeSet 3503 */ 3504void 3505xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3506 int i; 3507 3508 if ((cur == NULL) || (val == NULL)) return; 3509 3510#if 0 3511 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3512 return; /* an XSLT fake node */ 3513#endif 3514 3515 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3516 /* 3517 * prevent duplcates 3518 */ 3519 for (i = 0;i < cur->nodeNr;i++) 3520 if (cur->nodeTab[i] == val) return; 3521 3522 /* 3523 * grow the nodeTab if needed 3524 */ 3525 if (cur->nodeMax == 0) { 3526 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3527 sizeof(xmlNodePtr)); 3528 if (cur->nodeTab == NULL) { 3529 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3530 return; 3531 } 3532 memset(cur->nodeTab, 0 , 3533 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3534 cur->nodeMax = XML_NODESET_DEFAULT; 3535 } else if (cur->nodeNr == cur->nodeMax) { 3536 xmlNodePtr *temp; 3537 3538 cur->nodeMax *= 2; 3539 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3540 sizeof(xmlNodePtr)); 3541 if (temp == NULL) { 3542 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3543 return; 3544 } 3545 cur->nodeTab = temp; 3546 } 3547 if (val->type == XML_NAMESPACE_DECL) { 3548 xmlNsPtr ns = (xmlNsPtr) val; 3549 3550 cur->nodeTab[cur->nodeNr++] = 3551 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3552 } else 3553 cur->nodeTab[cur->nodeNr++] = val; 3554} 3555 3556/** 3557 * xmlXPathNodeSetAddUnique: 3558 * @cur: the initial node set 3559 * @val: a new xmlNodePtr 3560 * 3561 * add a new xmlNodePtr to an existing NodeSet, optimized version 3562 * when we are sure the node is not already in the set. 3563 */ 3564void 3565xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3566 if ((cur == NULL) || (val == NULL)) return; 3567 3568#if 0 3569 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3570 return; /* an XSLT fake node */ 3571#endif 3572 3573 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3574 /* 3575 * grow the nodeTab if needed 3576 */ 3577 if (cur->nodeMax == 0) { 3578 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3579 sizeof(xmlNodePtr)); 3580 if (cur->nodeTab == NULL) { 3581 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3582 return; 3583 } 3584 memset(cur->nodeTab, 0 , 3585 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3586 cur->nodeMax = XML_NODESET_DEFAULT; 3587 } else if (cur->nodeNr == cur->nodeMax) { 3588 xmlNodePtr *temp; 3589 3590 cur->nodeMax *= 2; 3591 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 3592 sizeof(xmlNodePtr)); 3593 if (temp == NULL) { 3594 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3595 return; 3596 } 3597 cur->nodeTab = temp; 3598 } 3599 if (val->type == XML_NAMESPACE_DECL) { 3600 xmlNsPtr ns = (xmlNsPtr) val; 3601 3602 cur->nodeTab[cur->nodeNr++] = 3603 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3604 } else 3605 cur->nodeTab[cur->nodeNr++] = val; 3606} 3607 3608/** 3609 * xmlXPathNodeSetMerge: 3610 * @val1: the first NodeSet or NULL 3611 * @val2: the second NodeSet 3612 * 3613 * Merges two nodesets, all nodes from @val2 are added to @val1 3614 * if @val1 is NULL, a new set is created and copied from @val2 3615 * 3616 * Returns @val1 once extended or NULL in case of error. 3617 */ 3618xmlNodeSetPtr 3619xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3620 int i, j, initNr, skip; 3621 xmlNodePtr n1, n2; 3622 3623 if (val2 == NULL) return(val1); 3624 if (val1 == NULL) { 3625 val1 = xmlXPathNodeSetCreate(NULL); 3626#if 0 3627 /* 3628 * TODO: The optimization won't work in every case, since 3629 * those nasty namespace nodes need to be added with 3630 * xmlXPathNodeSetDupNs() to the set; thus a pure 3631 * memcpy is not possible. 3632 * If there was a flag on the nodesetval, indicating that 3633 * some temporary nodes are in, that would be helpfull. 3634 */ 3635 /* 3636 * Optimization: Create an equally sized node-set 3637 * and memcpy the content. 3638 */ 3639 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3640 if (val1 == NULL) 3641 return(NULL); 3642 if (val2->nodeNr != 0) { 3643 if (val2->nodeNr == 1) 3644 *(val1->nodeTab) = *(val2->nodeTab); 3645 else { 3646 memcpy(val1->nodeTab, val2->nodeTab, 3647 val2->nodeNr * sizeof(xmlNodePtr)); 3648 } 3649 val1->nodeNr = val2->nodeNr; 3650 } 3651 return(val1); 3652#endif 3653 } 3654 3655 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3656 initNr = val1->nodeNr; 3657 3658 for (i = 0;i < val2->nodeNr;i++) { 3659 n2 = val2->nodeTab[i]; 3660 /* 3661 * check against duplicates 3662 */ 3663 skip = 0; 3664 for (j = 0; j < initNr; j++) { 3665 n1 = val1->nodeTab[j]; 3666 if (n1 == n2) { 3667 skip = 1; 3668 break; 3669 } else if ((n1->type == XML_NAMESPACE_DECL) && 3670 (n2->type == XML_NAMESPACE_DECL)) { 3671 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3672 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3673 ((xmlNsPtr) n2)->prefix))) 3674 { 3675 skip = 1; 3676 break; 3677 } 3678 } 3679 } 3680 if (skip) 3681 continue; 3682 3683 /* 3684 * grow the nodeTab if needed 3685 */ 3686 if (val1->nodeMax == 0) { 3687 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3688 sizeof(xmlNodePtr)); 3689 if (val1->nodeTab == NULL) { 3690 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3691 return(NULL); 3692 } 3693 memset(val1->nodeTab, 0 , 3694 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3695 val1->nodeMax = XML_NODESET_DEFAULT; 3696 } else if (val1->nodeNr == val1->nodeMax) { 3697 xmlNodePtr *temp; 3698 3699 val1->nodeMax *= 2; 3700 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 3701 sizeof(xmlNodePtr)); 3702 if (temp == NULL) { 3703 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3704 return(NULL); 3705 } 3706 val1->nodeTab = temp; 3707 } 3708 if (n2->type == XML_NAMESPACE_DECL) { 3709 xmlNsPtr ns = (xmlNsPtr) n2; 3710 3711 val1->nodeTab[val1->nodeNr++] = 3712 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3713 } else 3714 val1->nodeTab[val1->nodeNr++] = n2; 3715 } 3716 3717 return(val1); 3718} 3719 3720/** 3721 * xmlXPathNodeSetMergeUnique: 3722 * @val1: the first NodeSet or NULL 3723 * @val2: the second NodeSet 3724 * 3725 * Merges two nodesets, all nodes from @val2 are added to @val1 3726 * if @val1 is NULL, a new set is created and copied from @val2 3727 * 3728 * Returns @val1 once extended or NULL in case of error. 3729 */ 3730static xmlNodeSetPtr 3731xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3732 int i; 3733 3734 if (val2 == NULL) return(val1); 3735 if (val1 == NULL) { 3736 val1 = xmlXPathNodeSetCreate(NULL); 3737 } 3738 3739 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3740 3741 for (i = 0;i < val2->nodeNr;i++) { 3742 /* 3743 * grow the nodeTab if needed 3744 */ 3745 if (val1->nodeMax == 0) { 3746 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3747 sizeof(xmlNodePtr)); 3748 if (val1->nodeTab == NULL) { 3749 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3750 return(NULL); 3751 } 3752 memset(val1->nodeTab, 0 , 3753 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3754 val1->nodeMax = XML_NODESET_DEFAULT; 3755 } else if (val1->nodeNr == val1->nodeMax) { 3756 xmlNodePtr *temp; 3757 3758 val1->nodeMax *= 2; 3759 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 3760 sizeof(xmlNodePtr)); 3761 if (temp == NULL) { 3762 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3763 return(NULL); 3764 } 3765 val1->nodeTab = temp; 3766 } 3767 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3768 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; 3769 3770 val1->nodeTab[val1->nodeNr++] = 3771 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3772 } else 3773 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; 3774 } 3775 3776 return(val1); 3777} 3778 3779/** 3780 * xmlXPathNodeSetDel: 3781 * @cur: the initial node set 3782 * @val: an xmlNodePtr 3783 * 3784 * Removes an xmlNodePtr from an existing NodeSet 3785 */ 3786void 3787xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 3788 int i; 3789 3790 if (cur == NULL) return; 3791 if (val == NULL) return; 3792 3793 /* 3794 * find node in nodeTab 3795 */ 3796 for (i = 0;i < cur->nodeNr;i++) 3797 if (cur->nodeTab[i] == val) break; 3798 3799 if (i >= cur->nodeNr) { /* not found */ 3800#ifdef DEBUG 3801 xmlGenericError(xmlGenericErrorContext, 3802 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 3803 val->name); 3804#endif 3805 return; 3806 } 3807 if ((cur->nodeTab[i] != NULL) && 3808 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 3809 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 3810 cur->nodeNr--; 3811 for (;i < cur->nodeNr;i++) 3812 cur->nodeTab[i] = cur->nodeTab[i + 1]; 3813 cur->nodeTab[cur->nodeNr] = NULL; 3814} 3815 3816/** 3817 * xmlXPathNodeSetRemove: 3818 * @cur: the initial node set 3819 * @val: the index to remove 3820 * 3821 * Removes an entry from an existing NodeSet list. 3822 */ 3823void 3824xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 3825 if (cur == NULL) return; 3826 if (val >= cur->nodeNr) return; 3827 if ((cur->nodeTab[val] != NULL) && 3828 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 3829 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 3830 cur->nodeNr--; 3831 for (;val < cur->nodeNr;val++) 3832 cur->nodeTab[val] = cur->nodeTab[val + 1]; 3833 cur->nodeTab[cur->nodeNr] = NULL; 3834} 3835 3836/** 3837 * xmlXPathFreeNodeSet: 3838 * @obj: the xmlNodeSetPtr to free 3839 * 3840 * Free the NodeSet compound (not the actual nodes !). 3841 */ 3842void 3843xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 3844 if (obj == NULL) return; 3845 if (obj->nodeTab != NULL) { 3846 int i; 3847 3848 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3849 for (i = 0;i < obj->nodeNr;i++) 3850 if ((obj->nodeTab[i] != NULL) && 3851 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 3852 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 3853 xmlFree(obj->nodeTab); 3854 } 3855 xmlFree(obj); 3856} 3857 3858/** 3859 * xmlXPathNodeSetClear: 3860 * @set: the xmlNodeSetPtr to free 3861 * 3862 * Clears the list from all temporary XPath objects (e.g. namespace nodes 3863 * are feed), but does *not* free the list itself. Sets the length of the 3864 * list to 0. 3865 */ 3866static void 3867xmlXPathNodeSetClear(xmlNodeSetPtr set) 3868{ 3869 int i; 3870 xmlNodePtr node; 3871 3872 if ((set == NULL) || (set->nodeNr <= 0)) 3873 return; 3874 3875 for (i = 0; i < set->nodeNr; i++) { 3876 node = set->nodeTab[i]; 3877 if ((node != NULL) && 3878 (node->type == XML_NAMESPACE_DECL)) 3879 { 3880 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 3881 } 3882 } 3883 set->nodeNr = 0; 3884} 3885 3886/** 3887 * xmlXPathFreeValueTree: 3888 * @obj: the xmlNodeSetPtr to free 3889 * 3890 * Free the NodeSet compound and the actual tree, this is different 3891 * from xmlXPathFreeNodeSet() 3892 */ 3893static void 3894xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 3895 int i; 3896 3897 if (obj == NULL) return; 3898 3899 if (obj->nodeTab != NULL) { 3900 for (i = 0;i < obj->nodeNr;i++) { 3901 if (obj->nodeTab[i] != NULL) { 3902 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3903 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 3904 } else { 3905 xmlFreeNodeList(obj->nodeTab[i]); 3906 } 3907 } 3908 } 3909 xmlFree(obj->nodeTab); 3910 } 3911 xmlFree(obj); 3912} 3913 3914#if defined(DEBUG) || defined(DEBUG_STEP) 3915/** 3916 * xmlGenericErrorContextNodeSet: 3917 * @output: a FILE * for the output 3918 * @obj: the xmlNodeSetPtr to display 3919 * 3920 * Quick display of a NodeSet 3921 */ 3922void 3923xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 3924 int i; 3925 3926 if (output == NULL) output = xmlGenericErrorContext; 3927 if (obj == NULL) { 3928 fprintf(output, "NodeSet == NULL !\n"); 3929 return; 3930 } 3931 if (obj->nodeNr == 0) { 3932 fprintf(output, "NodeSet is empty\n"); 3933 return; 3934 } 3935 if (obj->nodeTab == NULL) { 3936 fprintf(output, " nodeTab == NULL !\n"); 3937 return; 3938 } 3939 for (i = 0; i < obj->nodeNr; i++) { 3940 if (obj->nodeTab[i] == NULL) { 3941 fprintf(output, " NULL !\n"); 3942 return; 3943 } 3944 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 3945 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 3946 fprintf(output, " /"); 3947 else if (obj->nodeTab[i]->name == NULL) 3948 fprintf(output, " noname!"); 3949 else fprintf(output, " %s", obj->nodeTab[i]->name); 3950 } 3951 fprintf(output, "\n"); 3952} 3953#endif 3954 3955/** 3956 * xmlXPathNewNodeSet: 3957 * @val: the NodePtr value 3958 * 3959 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 3960 * it with the single Node @val 3961 * 3962 * Returns the newly created object. 3963 */ 3964xmlXPathObjectPtr 3965xmlXPathNewNodeSet(xmlNodePtr val) { 3966 xmlXPathObjectPtr ret; 3967 3968 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3969 if (ret == NULL) { 3970 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3971 return(NULL); 3972 } 3973 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 3974 ret->type = XPATH_NODESET; 3975 ret->boolval = 0; 3976 ret->nodesetval = xmlXPathNodeSetCreate(val); 3977 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3978#ifdef XP_DEBUG_OBJ_USAGE 3979 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 3980#endif 3981 return(ret); 3982} 3983 3984/** 3985 * xmlXPathNewValueTree: 3986 * @val: the NodePtr value 3987 * 3988 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 3989 * it with the tree root @val 3990 * 3991 * Returns the newly created object. 3992 */ 3993xmlXPathObjectPtr 3994xmlXPathNewValueTree(xmlNodePtr val) { 3995 xmlXPathObjectPtr ret; 3996 3997 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3998 if (ret == NULL) { 3999 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4000 return(NULL); 4001 } 4002 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4003 ret->type = XPATH_XSLT_TREE; 4004 ret->boolval = 1; 4005 ret->user = (void *) val; 4006 ret->nodesetval = xmlXPathNodeSetCreate(val); 4007#ifdef XP_DEBUG_OBJ_USAGE 4008 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4009#endif 4010 return(ret); 4011} 4012 4013/** 4014 * xmlXPathNewNodeSetList: 4015 * @val: an existing NodeSet 4016 * 4017 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4018 * it with the Nodeset @val 4019 * 4020 * Returns the newly created object. 4021 */ 4022xmlXPathObjectPtr 4023xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4024{ 4025 xmlXPathObjectPtr ret; 4026 int i; 4027 4028 if (val == NULL) 4029 ret = NULL; 4030 else if (val->nodeTab == NULL) 4031 ret = xmlXPathNewNodeSet(NULL); 4032 else { 4033 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4034 for (i = 1; i < val->nodeNr; ++i) 4035 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]); 4036 } 4037 4038 return (ret); 4039} 4040 4041/** 4042 * xmlXPathWrapNodeSet: 4043 * @val: the NodePtr value 4044 * 4045 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4046 * 4047 * Returns the newly created object. 4048 */ 4049xmlXPathObjectPtr 4050xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4051 xmlXPathObjectPtr ret; 4052 4053 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4054 if (ret == NULL) { 4055 xmlXPathErrMemory(NULL, "creating node set object\n"); 4056 return(NULL); 4057 } 4058 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4059 ret->type = XPATH_NODESET; 4060 ret->nodesetval = val; 4061#ifdef XP_DEBUG_OBJ_USAGE 4062 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4063#endif 4064 return(ret); 4065} 4066 4067/** 4068 * xmlXPathFreeNodeSetList: 4069 * @obj: an existing NodeSetList object 4070 * 4071 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4072 * the list contrary to xmlXPathFreeObject(). 4073 */ 4074void 4075xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4076 if (obj == NULL) return; 4077#ifdef XP_DEBUG_OBJ_USAGE 4078 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4079#endif 4080 xmlFree(obj); 4081} 4082 4083/** 4084 * xmlXPathDifference: 4085 * @nodes1: a node-set 4086 * @nodes2: a node-set 4087 * 4088 * Implements the EXSLT - Sets difference() function: 4089 * node-set set:difference (node-set, node-set) 4090 * 4091 * Returns the difference between the two node sets, or nodes1 if 4092 * nodes2 is empty 4093 */ 4094xmlNodeSetPtr 4095xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4096 xmlNodeSetPtr ret; 4097 int i, l1; 4098 xmlNodePtr cur; 4099 4100 if (xmlXPathNodeSetIsEmpty(nodes2)) 4101 return(nodes1); 4102 4103 ret = xmlXPathNodeSetCreate(NULL); 4104 if (xmlXPathNodeSetIsEmpty(nodes1)) 4105 return(ret); 4106 4107 l1 = xmlXPathNodeSetGetLength(nodes1); 4108 4109 for (i = 0; i < l1; i++) { 4110 cur = xmlXPathNodeSetItem(nodes1, i); 4111 if (!xmlXPathNodeSetContains(nodes2, cur)) 4112 xmlXPathNodeSetAddUnique(ret, cur); 4113 } 4114 return(ret); 4115} 4116 4117/** 4118 * xmlXPathIntersection: 4119 * @nodes1: a node-set 4120 * @nodes2: a node-set 4121 * 4122 * Implements the EXSLT - Sets intersection() function: 4123 * node-set set:intersection (node-set, node-set) 4124 * 4125 * Returns a node set comprising the nodes that are within both the 4126 * node sets passed as arguments 4127 */ 4128xmlNodeSetPtr 4129xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4130 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4131 int i, l1; 4132 xmlNodePtr cur; 4133 4134 if (xmlXPathNodeSetIsEmpty(nodes1)) 4135 return(ret); 4136 if (xmlXPathNodeSetIsEmpty(nodes2)) 4137 return(ret); 4138 4139 l1 = xmlXPathNodeSetGetLength(nodes1); 4140 4141 for (i = 0; i < l1; i++) { 4142 cur = xmlXPathNodeSetItem(nodes1, i); 4143 if (xmlXPathNodeSetContains(nodes2, cur)) 4144 xmlXPathNodeSetAddUnique(ret, cur); 4145 } 4146 return(ret); 4147} 4148 4149/** 4150 * xmlXPathDistinctSorted: 4151 * @nodes: a node-set, sorted by document order 4152 * 4153 * Implements the EXSLT - Sets distinct() function: 4154 * node-set set:distinct (node-set) 4155 * 4156 * Returns a subset of the nodes contained in @nodes, or @nodes if 4157 * it is empty 4158 */ 4159xmlNodeSetPtr 4160xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4161 xmlNodeSetPtr ret; 4162 xmlHashTablePtr hash; 4163 int i, l; 4164 xmlChar * strval; 4165 xmlNodePtr cur; 4166 4167 if (xmlXPathNodeSetIsEmpty(nodes)) 4168 return(nodes); 4169 4170 ret = xmlXPathNodeSetCreate(NULL); 4171 l = xmlXPathNodeSetGetLength(nodes); 4172 hash = xmlHashCreate (l); 4173 for (i = 0; i < l; i++) { 4174 cur = xmlXPathNodeSetItem(nodes, i); 4175 strval = xmlXPathCastNodeToString(cur); 4176 if (xmlHashLookup(hash, strval) == NULL) { 4177 xmlHashAddEntry(hash, strval, strval); 4178 xmlXPathNodeSetAddUnique(ret, cur); 4179 } else { 4180 xmlFree(strval); 4181 } 4182 } 4183 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 4184 return(ret); 4185} 4186 4187/** 4188 * xmlXPathDistinct: 4189 * @nodes: a node-set 4190 * 4191 * Implements the EXSLT - Sets distinct() function: 4192 * node-set set:distinct (node-set) 4193 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4194 * is called with the sorted node-set 4195 * 4196 * Returns a subset of the nodes contained in @nodes, or @nodes if 4197 * it is empty 4198 */ 4199xmlNodeSetPtr 4200xmlXPathDistinct (xmlNodeSetPtr nodes) { 4201 if (xmlXPathNodeSetIsEmpty(nodes)) 4202 return(nodes); 4203 4204 xmlXPathNodeSetSort(nodes); 4205 return(xmlXPathDistinctSorted(nodes)); 4206} 4207 4208/** 4209 * xmlXPathHasSameNodes: 4210 * @nodes1: a node-set 4211 * @nodes2: a node-set 4212 * 4213 * Implements the EXSLT - Sets has-same-nodes function: 4214 * boolean set:has-same-node(node-set, node-set) 4215 * 4216 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4217 * otherwise 4218 */ 4219int 4220xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4221 int i, l; 4222 xmlNodePtr cur; 4223 4224 if (xmlXPathNodeSetIsEmpty(nodes1) || 4225 xmlXPathNodeSetIsEmpty(nodes2)) 4226 return(0); 4227 4228 l = xmlXPathNodeSetGetLength(nodes1); 4229 for (i = 0; i < l; i++) { 4230 cur = xmlXPathNodeSetItem(nodes1, i); 4231 if (xmlXPathNodeSetContains(nodes2, cur)) 4232 return(1); 4233 } 4234 return(0); 4235} 4236 4237/** 4238 * xmlXPathNodeLeadingSorted: 4239 * @nodes: a node-set, sorted by document order 4240 * @node: a node 4241 * 4242 * Implements the EXSLT - Sets leading() function: 4243 * node-set set:leading (node-set, node-set) 4244 * 4245 * Returns the nodes in @nodes that precede @node in document order, 4246 * @nodes if @node is NULL or an empty node-set if @nodes 4247 * doesn't contain @node 4248 */ 4249xmlNodeSetPtr 4250xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4251 int i, l; 4252 xmlNodePtr cur; 4253 xmlNodeSetPtr ret; 4254 4255 if (node == NULL) 4256 return(nodes); 4257 4258 ret = xmlXPathNodeSetCreate(NULL); 4259 if (xmlXPathNodeSetIsEmpty(nodes) || 4260 (!xmlXPathNodeSetContains(nodes, node))) 4261 return(ret); 4262 4263 l = xmlXPathNodeSetGetLength(nodes); 4264 for (i = 0; i < l; i++) { 4265 cur = xmlXPathNodeSetItem(nodes, i); 4266 if (cur == node) 4267 break; 4268 xmlXPathNodeSetAddUnique(ret, cur); 4269 } 4270 return(ret); 4271} 4272 4273/** 4274 * xmlXPathNodeLeading: 4275 * @nodes: a node-set 4276 * @node: a node 4277 * 4278 * Implements the EXSLT - Sets leading() function: 4279 * node-set set:leading (node-set, node-set) 4280 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4281 * is called. 4282 * 4283 * Returns the nodes in @nodes that precede @node in document order, 4284 * @nodes if @node is NULL or an empty node-set if @nodes 4285 * doesn't contain @node 4286 */ 4287xmlNodeSetPtr 4288xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4289 xmlXPathNodeSetSort(nodes); 4290 return(xmlXPathNodeLeadingSorted(nodes, node)); 4291} 4292 4293/** 4294 * xmlXPathLeadingSorted: 4295 * @nodes1: a node-set, sorted by document order 4296 * @nodes2: a node-set, sorted by document order 4297 * 4298 * Implements the EXSLT - Sets leading() function: 4299 * node-set set:leading (node-set, node-set) 4300 * 4301 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4302 * in document order, @nodes1 if @nodes2 is NULL or empty or 4303 * an empty node-set if @nodes1 doesn't contain @nodes2 4304 */ 4305xmlNodeSetPtr 4306xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4307 if (xmlXPathNodeSetIsEmpty(nodes2)) 4308 return(nodes1); 4309 return(xmlXPathNodeLeadingSorted(nodes1, 4310 xmlXPathNodeSetItem(nodes2, 1))); 4311} 4312 4313/** 4314 * xmlXPathLeading: 4315 * @nodes1: a node-set 4316 * @nodes2: a node-set 4317 * 4318 * Implements the EXSLT - Sets leading() function: 4319 * node-set set:leading (node-set, node-set) 4320 * @nodes1 and @nodes2 are sorted by document order, then 4321 * #exslSetsLeadingSorted is called. 4322 * 4323 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4324 * in document order, @nodes1 if @nodes2 is NULL or empty or 4325 * an empty node-set if @nodes1 doesn't contain @nodes2 4326 */ 4327xmlNodeSetPtr 4328xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4329 if (xmlXPathNodeSetIsEmpty(nodes2)) 4330 return(nodes1); 4331 if (xmlXPathNodeSetIsEmpty(nodes1)) 4332 return(xmlXPathNodeSetCreate(NULL)); 4333 xmlXPathNodeSetSort(nodes1); 4334 xmlXPathNodeSetSort(nodes2); 4335 return(xmlXPathNodeLeadingSorted(nodes1, 4336 xmlXPathNodeSetItem(nodes2, 1))); 4337} 4338 4339/** 4340 * xmlXPathNodeTrailingSorted: 4341 * @nodes: a node-set, sorted by document order 4342 * @node: a node 4343 * 4344 * Implements the EXSLT - Sets trailing() function: 4345 * node-set set:trailing (node-set, node-set) 4346 * 4347 * Returns the nodes in @nodes that follow @node in document order, 4348 * @nodes if @node is NULL or an empty node-set if @nodes 4349 * doesn't contain @node 4350 */ 4351xmlNodeSetPtr 4352xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4353 int i, l; 4354 xmlNodePtr cur; 4355 xmlNodeSetPtr ret; 4356 4357 if (node == NULL) 4358 return(nodes); 4359 4360 ret = xmlXPathNodeSetCreate(NULL); 4361 if (xmlXPathNodeSetIsEmpty(nodes) || 4362 (!xmlXPathNodeSetContains(nodes, node))) 4363 return(ret); 4364 4365 l = xmlXPathNodeSetGetLength(nodes); 4366 for (i = l; i > 0; i--) { 4367 cur = xmlXPathNodeSetItem(nodes, i); 4368 if (cur == node) 4369 break; 4370 xmlXPathNodeSetAddUnique(ret, cur); 4371 } 4372 return(ret); 4373} 4374 4375/** 4376 * xmlXPathNodeTrailing: 4377 * @nodes: a node-set 4378 * @node: a node 4379 * 4380 * Implements the EXSLT - Sets trailing() function: 4381 * node-set set:trailing (node-set, node-set) 4382 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4383 * is called. 4384 * 4385 * Returns the nodes in @nodes that follow @node in document order, 4386 * @nodes if @node is NULL or an empty node-set if @nodes 4387 * doesn't contain @node 4388 */ 4389xmlNodeSetPtr 4390xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4391 xmlXPathNodeSetSort(nodes); 4392 return(xmlXPathNodeTrailingSorted(nodes, node)); 4393} 4394 4395/** 4396 * xmlXPathTrailingSorted: 4397 * @nodes1: a node-set, sorted by document order 4398 * @nodes2: a node-set, sorted by document order 4399 * 4400 * Implements the EXSLT - Sets trailing() function: 4401 * node-set set:trailing (node-set, node-set) 4402 * 4403 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4404 * in document order, @nodes1 if @nodes2 is NULL or empty or 4405 * an empty node-set if @nodes1 doesn't contain @nodes2 4406 */ 4407xmlNodeSetPtr 4408xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4409 if (xmlXPathNodeSetIsEmpty(nodes2)) 4410 return(nodes1); 4411 return(xmlXPathNodeTrailingSorted(nodes1, 4412 xmlXPathNodeSetItem(nodes2, 0))); 4413} 4414 4415/** 4416 * xmlXPathTrailing: 4417 * @nodes1: a node-set 4418 * @nodes2: a node-set 4419 * 4420 * Implements the EXSLT - Sets trailing() function: 4421 * node-set set:trailing (node-set, node-set) 4422 * @nodes1 and @nodes2 are sorted by document order, then 4423 * #xmlXPathTrailingSorted is called. 4424 * 4425 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4426 * in document order, @nodes1 if @nodes2 is NULL or empty or 4427 * an empty node-set if @nodes1 doesn't contain @nodes2 4428 */ 4429xmlNodeSetPtr 4430xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4431 if (xmlXPathNodeSetIsEmpty(nodes2)) 4432 return(nodes1); 4433 if (xmlXPathNodeSetIsEmpty(nodes1)) 4434 return(xmlXPathNodeSetCreate(NULL)); 4435 xmlXPathNodeSetSort(nodes1); 4436 xmlXPathNodeSetSort(nodes2); 4437 return(xmlXPathNodeTrailingSorted(nodes1, 4438 xmlXPathNodeSetItem(nodes2, 0))); 4439} 4440 4441/************************************************************************ 4442 * * 4443 * Routines to handle extra functions * 4444 * * 4445 ************************************************************************/ 4446 4447/** 4448 * xmlXPathRegisterFunc: 4449 * @ctxt: the XPath context 4450 * @name: the function name 4451 * @f: the function implementation or NULL 4452 * 4453 * Register a new function. If @f is NULL it unregisters the function 4454 * 4455 * Returns 0 in case of success, -1 in case of error 4456 */ 4457int 4458xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4459 xmlXPathFunction f) { 4460 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4461} 4462 4463/** 4464 * xmlXPathRegisterFuncNS: 4465 * @ctxt: the XPath context 4466 * @name: the function name 4467 * @ns_uri: the function namespace URI 4468 * @f: the function implementation or NULL 4469 * 4470 * Register a new function. If @f is NULL it unregisters the function 4471 * 4472 * Returns 0 in case of success, -1 in case of error 4473 */ 4474int 4475xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4476 const xmlChar *ns_uri, xmlXPathFunction f) { 4477 if (ctxt == NULL) 4478 return(-1); 4479 if (name == NULL) 4480 return(-1); 4481 4482 if (ctxt->funcHash == NULL) 4483 ctxt->funcHash = xmlHashCreate(0); 4484 if (ctxt->funcHash == NULL) 4485 return(-1); 4486 if (f == NULL) 4487 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4488 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f))); 4489} 4490 4491/** 4492 * xmlXPathRegisterFuncLookup: 4493 * @ctxt: the XPath context 4494 * @f: the lookup function 4495 * @funcCtxt: the lookup data 4496 * 4497 * Registers an external mechanism to do function lookup. 4498 */ 4499void 4500xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4501 xmlXPathFuncLookupFunc f, 4502 void *funcCtxt) { 4503 if (ctxt == NULL) 4504 return; 4505 ctxt->funcLookupFunc = f; 4506 ctxt->funcLookupData = funcCtxt; 4507} 4508 4509/** 4510 * xmlXPathFunctionLookup: 4511 * @ctxt: the XPath context 4512 * @name: the function name 4513 * 4514 * Search in the Function array of the context for the given 4515 * function. 4516 * 4517 * Returns the xmlXPathFunction or NULL if not found 4518 */ 4519xmlXPathFunction 4520xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4521 if (ctxt == NULL) 4522 return (NULL); 4523 4524 if (ctxt->funcLookupFunc != NULL) { 4525 xmlXPathFunction ret; 4526 xmlXPathFuncLookupFunc f; 4527 4528 f = ctxt->funcLookupFunc; 4529 ret = f(ctxt->funcLookupData, name, NULL); 4530 if (ret != NULL) 4531 return(ret); 4532 } 4533 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4534} 4535 4536/** 4537 * xmlXPathFunctionLookupNS: 4538 * @ctxt: the XPath context 4539 * @name: the function name 4540 * @ns_uri: the function namespace URI 4541 * 4542 * Search in the Function array of the context for the given 4543 * function. 4544 * 4545 * Returns the xmlXPathFunction or NULL if not found 4546 */ 4547xmlXPathFunction 4548xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4549 const xmlChar *ns_uri) { 4550 xmlXPathFunction ret; 4551 4552 if (ctxt == NULL) 4553 return(NULL); 4554 if (name == NULL) 4555 return(NULL); 4556 4557 if (ctxt->funcLookupFunc != NULL) { 4558 xmlXPathFuncLookupFunc f; 4559 4560 f = ctxt->funcLookupFunc; 4561 ret = f(ctxt->funcLookupData, name, ns_uri); 4562 if (ret != NULL) 4563 return(ret); 4564 } 4565 4566 if (ctxt->funcHash == NULL) 4567 return(NULL); 4568 4569 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4570 return(ret); 4571} 4572 4573/** 4574 * xmlXPathRegisteredFuncsCleanup: 4575 * @ctxt: the XPath context 4576 * 4577 * Cleanup the XPath context data associated to registered functions 4578 */ 4579void 4580xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4581 if (ctxt == NULL) 4582 return; 4583 4584 xmlHashFree(ctxt->funcHash, NULL); 4585 ctxt->funcHash = NULL; 4586} 4587 4588/************************************************************************ 4589 * * 4590 * Routines to handle Variables * 4591 * * 4592 ************************************************************************/ 4593 4594/** 4595 * xmlXPathRegisterVariable: 4596 * @ctxt: the XPath context 4597 * @name: the variable name 4598 * @value: the variable value or NULL 4599 * 4600 * Register a new variable value. If @value is NULL it unregisters 4601 * the variable 4602 * 4603 * Returns 0 in case of success, -1 in case of error 4604 */ 4605int 4606xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 4607 xmlXPathObjectPtr value) { 4608 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 4609} 4610 4611/** 4612 * xmlXPathRegisterVariableNS: 4613 * @ctxt: the XPath context 4614 * @name: the variable name 4615 * @ns_uri: the variable namespace URI 4616 * @value: the variable value or NULL 4617 * 4618 * Register a new variable value. If @value is NULL it unregisters 4619 * the variable 4620 * 4621 * Returns 0 in case of success, -1 in case of error 4622 */ 4623int 4624xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4625 const xmlChar *ns_uri, 4626 xmlXPathObjectPtr value) { 4627 if (ctxt == NULL) 4628 return(-1); 4629 if (name == NULL) 4630 return(-1); 4631 4632 if (ctxt->varHash == NULL) 4633 ctxt->varHash = xmlHashCreate(0); 4634 if (ctxt->varHash == NULL) 4635 return(-1); 4636 if (value == NULL) 4637 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 4638 (xmlHashDeallocator)xmlXPathFreeObject)); 4639 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 4640 (void *) value, 4641 (xmlHashDeallocator)xmlXPathFreeObject)); 4642} 4643 4644/** 4645 * xmlXPathRegisterVariableLookup: 4646 * @ctxt: the XPath context 4647 * @f: the lookup function 4648 * @data: the lookup data 4649 * 4650 * register an external mechanism to do variable lookup 4651 */ 4652void 4653xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 4654 xmlXPathVariableLookupFunc f, void *data) { 4655 if (ctxt == NULL) 4656 return; 4657 ctxt->varLookupFunc = f; 4658 ctxt->varLookupData = data; 4659} 4660 4661/** 4662 * xmlXPathVariableLookup: 4663 * @ctxt: the XPath context 4664 * @name: the variable name 4665 * 4666 * Search in the Variable array of the context for the given 4667 * variable value. 4668 * 4669 * Returns a copy of the value or NULL if not found 4670 */ 4671xmlXPathObjectPtr 4672xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4673 if (ctxt == NULL) 4674 return(NULL); 4675 4676 if (ctxt->varLookupFunc != NULL) { 4677 xmlXPathObjectPtr ret; 4678 4679 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 4680 (ctxt->varLookupData, name, NULL); 4681 return(ret); 4682 } 4683 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 4684} 4685 4686/** 4687 * xmlXPathVariableLookupNS: 4688 * @ctxt: the XPath context 4689 * @name: the variable name 4690 * @ns_uri: the variable namespace URI 4691 * 4692 * Search in the Variable array of the context for the given 4693 * variable value. 4694 * 4695 * Returns the a copy of the value or NULL if not found 4696 */ 4697xmlXPathObjectPtr 4698xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4699 const xmlChar *ns_uri) { 4700 if (ctxt == NULL) 4701 return(NULL); 4702 4703 if (ctxt->varLookupFunc != NULL) { 4704 xmlXPathObjectPtr ret; 4705 4706 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 4707 (ctxt->varLookupData, name, ns_uri); 4708 if (ret != NULL) return(ret); 4709 } 4710 4711 if (ctxt->varHash == NULL) 4712 return(NULL); 4713 if (name == NULL) 4714 return(NULL); 4715 4716 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 4717 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 4718} 4719 4720/** 4721 * xmlXPathRegisteredVariablesCleanup: 4722 * @ctxt: the XPath context 4723 * 4724 * Cleanup the XPath context data associated to registered variables 4725 */ 4726void 4727xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 4728 if (ctxt == NULL) 4729 return; 4730 4731 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 4732 ctxt->varHash = NULL; 4733} 4734 4735/** 4736 * xmlXPathRegisterNs: 4737 * @ctxt: the XPath context 4738 * @prefix: the namespace prefix 4739 * @ns_uri: the namespace name 4740 * 4741 * Register a new namespace. If @ns_uri is NULL it unregisters 4742 * the namespace 4743 * 4744 * Returns 0 in case of success, -1 in case of error 4745 */ 4746int 4747xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 4748 const xmlChar *ns_uri) { 4749 if (ctxt == NULL) 4750 return(-1); 4751 if (prefix == NULL) 4752 return(-1); 4753 4754 if (ctxt->nsHash == NULL) 4755 ctxt->nsHash = xmlHashCreate(10); 4756 if (ctxt->nsHash == NULL) 4757 return(-1); 4758 if (ns_uri == NULL) 4759 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 4760 (xmlHashDeallocator)xmlFree)); 4761 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), 4762 (xmlHashDeallocator)xmlFree)); 4763} 4764 4765/** 4766 * xmlXPathNsLookup: 4767 * @ctxt: the XPath context 4768 * @prefix: the namespace prefix value 4769 * 4770 * Search in the namespace declaration array of the context for the given 4771 * namespace name associated to the given prefix 4772 * 4773 * Returns the value or NULL if not found 4774 */ 4775const xmlChar * 4776xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 4777 if (ctxt == NULL) 4778 return(NULL); 4779 if (prefix == NULL) 4780 return(NULL); 4781 4782#ifdef XML_XML_NAMESPACE 4783 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 4784 return(XML_XML_NAMESPACE); 4785#endif 4786 4787 if (ctxt->namespaces != NULL) { 4788 int i; 4789 4790 for (i = 0;i < ctxt->nsNr;i++) { 4791 if ((ctxt->namespaces[i] != NULL) && 4792 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 4793 return(ctxt->namespaces[i]->href); 4794 } 4795 } 4796 4797 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 4798} 4799 4800/** 4801 * xmlXPathRegisteredNsCleanup: 4802 * @ctxt: the XPath context 4803 * 4804 * Cleanup the XPath context data associated to registered variables 4805 */ 4806void 4807xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 4808 if (ctxt == NULL) 4809 return; 4810 4811 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); 4812 ctxt->nsHash = NULL; 4813} 4814 4815/************************************************************************ 4816 * * 4817 * Routines to handle Values * 4818 * * 4819 ************************************************************************/ 4820 4821/* Allocations are terrible, one needs to optimize all this !!! */ 4822 4823/** 4824 * xmlXPathNewFloat: 4825 * @val: the double value 4826 * 4827 * Create a new xmlXPathObjectPtr of type double and of value @val 4828 * 4829 * Returns the newly created object. 4830 */ 4831xmlXPathObjectPtr 4832xmlXPathNewFloat(double val) { 4833 xmlXPathObjectPtr ret; 4834 4835 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4836 if (ret == NULL) { 4837 xmlXPathErrMemory(NULL, "creating float object\n"); 4838 return(NULL); 4839 } 4840 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4841 ret->type = XPATH_NUMBER; 4842 ret->floatval = val; 4843#ifdef XP_DEBUG_OBJ_USAGE 4844 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); 4845#endif 4846 return(ret); 4847} 4848 4849/** 4850 * xmlXPathNewBoolean: 4851 * @val: the boolean value 4852 * 4853 * Create a new xmlXPathObjectPtr of type boolean and of value @val 4854 * 4855 * Returns the newly created object. 4856 */ 4857xmlXPathObjectPtr 4858xmlXPathNewBoolean(int val) { 4859 xmlXPathObjectPtr ret; 4860 4861 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4862 if (ret == NULL) { 4863 xmlXPathErrMemory(NULL, "creating boolean object\n"); 4864 return(NULL); 4865 } 4866 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4867 ret->type = XPATH_BOOLEAN; 4868 ret->boolval = (val != 0); 4869#ifdef XP_DEBUG_OBJ_USAGE 4870 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); 4871#endif 4872 return(ret); 4873} 4874 4875/** 4876 * xmlXPathNewString: 4877 * @val: the xmlChar * value 4878 * 4879 * Create a new xmlXPathObjectPtr of type string and of value @val 4880 * 4881 * Returns the newly created object. 4882 */ 4883xmlXPathObjectPtr 4884xmlXPathNewString(const xmlChar *val) { 4885 xmlXPathObjectPtr ret; 4886 4887 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4888 if (ret == NULL) { 4889 xmlXPathErrMemory(NULL, "creating string object\n"); 4890 return(NULL); 4891 } 4892 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4893 ret->type = XPATH_STRING; 4894 if (val != NULL) 4895 ret->stringval = xmlStrdup(val); 4896 else 4897 ret->stringval = xmlStrdup((const xmlChar *)""); 4898#ifdef XP_DEBUG_OBJ_USAGE 4899 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 4900#endif 4901 return(ret); 4902} 4903 4904/** 4905 * xmlXPathWrapString: 4906 * @val: the xmlChar * value 4907 * 4908 * Wraps the @val string into an XPath object. 4909 * 4910 * Returns the newly created object. 4911 */ 4912xmlXPathObjectPtr 4913xmlXPathWrapString (xmlChar *val) { 4914 xmlXPathObjectPtr ret; 4915 4916 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4917 if (ret == NULL) { 4918 xmlXPathErrMemory(NULL, "creating string object\n"); 4919 return(NULL); 4920 } 4921 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4922 ret->type = XPATH_STRING; 4923 ret->stringval = val; 4924#ifdef XP_DEBUG_OBJ_USAGE 4925 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 4926#endif 4927 return(ret); 4928} 4929 4930/** 4931 * xmlXPathNewCString: 4932 * @val: the char * value 4933 * 4934 * Create a new xmlXPathObjectPtr of type string and of value @val 4935 * 4936 * Returns the newly created object. 4937 */ 4938xmlXPathObjectPtr 4939xmlXPathNewCString(const char *val) { 4940 xmlXPathObjectPtr ret; 4941 4942 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4943 if (ret == NULL) { 4944 xmlXPathErrMemory(NULL, "creating string object\n"); 4945 return(NULL); 4946 } 4947 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4948 ret->type = XPATH_STRING; 4949 ret->stringval = xmlStrdup(BAD_CAST val); 4950#ifdef XP_DEBUG_OBJ_USAGE 4951 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); 4952#endif 4953 return(ret); 4954} 4955 4956/** 4957 * xmlXPathWrapCString: 4958 * @val: the char * value 4959 * 4960 * Wraps a string into an XPath object. 4961 * 4962 * Returns the newly created object. 4963 */ 4964xmlXPathObjectPtr 4965xmlXPathWrapCString (char * val) { 4966 return(xmlXPathWrapString((xmlChar *)(val))); 4967} 4968 4969/** 4970 * xmlXPathWrapExternal: 4971 * @val: the user data 4972 * 4973 * Wraps the @val data into an XPath object. 4974 * 4975 * Returns the newly created object. 4976 */ 4977xmlXPathObjectPtr 4978xmlXPathWrapExternal (void *val) { 4979 xmlXPathObjectPtr ret; 4980 4981 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4982 if (ret == NULL) { 4983 xmlXPathErrMemory(NULL, "creating user object\n"); 4984 return(NULL); 4985 } 4986 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4987 ret->type = XPATH_USERS; 4988 ret->user = val; 4989#ifdef XP_DEBUG_OBJ_USAGE 4990 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); 4991#endif 4992 return(ret); 4993} 4994 4995/** 4996 * xmlXPathObjectCopy: 4997 * @val: the original object 4998 * 4999 * allocate a new copy of a given object 5000 * 5001 * Returns the newly created object. 5002 */ 5003xmlXPathObjectPtr 5004xmlXPathObjectCopy(xmlXPathObjectPtr val) { 5005 xmlXPathObjectPtr ret; 5006 5007 if (val == NULL) 5008 return(NULL); 5009 5010 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 5011 if (ret == NULL) { 5012 xmlXPathErrMemory(NULL, "copying object\n"); 5013 return(NULL); 5014 } 5015 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 5016#ifdef XP_DEBUG_OBJ_USAGE 5017 xmlXPathDebugObjUsageRequested(NULL, val->type); 5018#endif 5019 switch (val->type) { 5020 case XPATH_BOOLEAN: 5021 case XPATH_NUMBER: 5022 case XPATH_POINT: 5023 case XPATH_RANGE: 5024 break; 5025 case XPATH_STRING: 5026 ret->stringval = xmlStrdup(val->stringval); 5027 break; 5028 case XPATH_XSLT_TREE: 5029#if 0 5030/* 5031 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that 5032 this previous handling is no longer correct, and can cause some serious 5033 problems (ref. bug 145547) 5034*/ 5035 if ((val->nodesetval != NULL) && 5036 (val->nodesetval->nodeTab != NULL)) { 5037 xmlNodePtr cur, tmp; 5038 xmlDocPtr top; 5039 5040 ret->boolval = 1; 5041 top = xmlNewDoc(NULL); 5042 top->name = (char *) 5043 xmlStrdup(val->nodesetval->nodeTab[0]->name); 5044 ret->user = top; 5045 if (top != NULL) { 5046 top->doc = top; 5047 cur = val->nodesetval->nodeTab[0]->children; 5048 while (cur != NULL) { 5049 tmp = xmlDocCopyNode(cur, top, 1); 5050 xmlAddChild((xmlNodePtr) top, tmp); 5051 cur = cur->next; 5052 } 5053 } 5054 5055 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); 5056 } else 5057 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 5058 /* Deallocate the copied tree value */ 5059 break; 5060#endif 5061 case XPATH_NODESET: 5062 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 5063 /* Do not deallocate the copied tree value */ 5064 ret->boolval = 0; 5065 break; 5066 case XPATH_LOCATIONSET: 5067#ifdef LIBXML_XPTR_ENABLED 5068 { 5069 xmlLocationSetPtr loc = val->user; 5070 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 5071 break; 5072 } 5073#endif 5074 case XPATH_USERS: 5075 ret->user = val->user; 5076 break; 5077 case XPATH_UNDEFINED: 5078 xmlGenericError(xmlGenericErrorContext, 5079 "xmlXPathObjectCopy: unsupported type %d\n", 5080 val->type); 5081 break; 5082 } 5083 return(ret); 5084} 5085 5086/** 5087 * xmlXPathFreeObject: 5088 * @obj: the object to free 5089 * 5090 * Free up an xmlXPathObjectPtr object. 5091 */ 5092void 5093xmlXPathFreeObject(xmlXPathObjectPtr obj) { 5094 if (obj == NULL) return; 5095 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 5096 if (obj->boolval) { 5097#if 0 5098 if (obj->user != NULL) { 5099 xmlXPathFreeNodeSet(obj->nodesetval); 5100 xmlFreeNodeList((xmlNodePtr) obj->user); 5101 } else 5102#endif 5103 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ 5104 if (obj->nodesetval != NULL) 5105 xmlXPathFreeValueTree(obj->nodesetval); 5106 } else { 5107 if (obj->nodesetval != NULL) 5108 xmlXPathFreeNodeSet(obj->nodesetval); 5109 } 5110#ifdef LIBXML_XPTR_ENABLED 5111 } else if (obj->type == XPATH_LOCATIONSET) { 5112 if (obj->user != NULL) 5113 xmlXPtrFreeLocationSet(obj->user); 5114#endif 5115 } else if (obj->type == XPATH_STRING) { 5116 if (obj->stringval != NULL) 5117 xmlFree(obj->stringval); 5118 } 5119#ifdef XP_DEBUG_OBJ_USAGE 5120 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5121#endif 5122 xmlFree(obj); 5123} 5124 5125/** 5126 * xmlXPathReleaseObject: 5127 * @obj: the xmlXPathObjectPtr to free or to cache 5128 * 5129 * Depending on the state of the cache this frees the given 5130 * XPath object or stores it in the cache. 5131 */ 5132static void 5133xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) 5134{ 5135#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ 5136 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ 5137 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; 5138 5139#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) 5140 5141 if (obj == NULL) 5142 return; 5143 if ((ctxt == NULL) || (ctxt->cache == NULL)) { 5144 xmlXPathFreeObject(obj); 5145 } else { 5146 xmlXPathContextCachePtr cache = 5147 (xmlXPathContextCachePtr) ctxt->cache; 5148 5149 switch (obj->type) { 5150 case XPATH_NODESET: 5151 case XPATH_XSLT_TREE: 5152 if (obj->nodesetval != NULL) { 5153 if (obj->boolval) { 5154 /* 5155 * It looks like the @boolval is used for 5156 * evaluation if this an XSLT Result Tree Fragment. 5157 * TODO: Check if this assumption is correct. 5158 */ 5159 obj->type = XPATH_XSLT_TREE; /* just for debugging */ 5160 xmlXPathFreeValueTree(obj->nodesetval); 5161 obj->nodesetval = NULL; 5162 } else if ((obj->nodesetval->nodeMax <= 40) && 5163 (XP_CACHE_WANTS(cache->nodesetObjs, 5164 cache->maxNodeset))) 5165 { 5166 XP_CACHE_ADD(cache->nodesetObjs, obj); 5167 goto obj_cached; 5168 } else { 5169 xmlXPathFreeNodeSet(obj->nodesetval); 5170 obj->nodesetval = NULL; 5171 } 5172 } 5173 break; 5174 case XPATH_STRING: 5175 if (obj->stringval != NULL) 5176 xmlFree(obj->stringval); 5177 5178 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { 5179 XP_CACHE_ADD(cache->stringObjs, obj); 5180 goto obj_cached; 5181 } 5182 break; 5183 case XPATH_BOOLEAN: 5184 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { 5185 XP_CACHE_ADD(cache->booleanObjs, obj); 5186 goto obj_cached; 5187 } 5188 break; 5189 case XPATH_NUMBER: 5190 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { 5191 XP_CACHE_ADD(cache->numberObjs, obj); 5192 goto obj_cached; 5193 } 5194 break; 5195#ifdef LIBXML_XPTR_ENABLED 5196 case XPATH_LOCATIONSET: 5197 if (obj->user != NULL) { 5198 xmlXPtrFreeLocationSet(obj->user); 5199 } 5200 goto free_obj; 5201#endif 5202 default: 5203 goto free_obj; 5204 } 5205 5206 /* 5207 * Fallback to adding to the misc-objects slot. 5208 */ 5209 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { 5210 XP_CACHE_ADD(cache->miscObjs, obj); 5211 } else 5212 goto free_obj; 5213 5214obj_cached: 5215 5216#ifdef XP_DEBUG_OBJ_USAGE 5217 xmlXPathDebugObjUsageReleased(ctxt, obj->type); 5218#endif 5219 5220 if (obj->nodesetval != NULL) { 5221 xmlNodeSetPtr tmpset = obj->nodesetval; 5222 5223 /* 5224 * TODO: Due to those nasty ns-nodes, we need to traverse 5225 * the list and free the ns-nodes. 5226 * URGENT TODO: Check if it's actually slowing things down. 5227 * Maybe we shouldn't try to preserve the list. 5228 */ 5229 if (tmpset->nodeNr > 1) { 5230 int i; 5231 xmlNodePtr node; 5232 5233 for (i = 0; i < tmpset->nodeNr; i++) { 5234 node = tmpset->nodeTab[i]; 5235 if ((node != NULL) && 5236 (node->type == XML_NAMESPACE_DECL)) 5237 { 5238 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 5239 } 5240 } 5241 } else if (tmpset->nodeNr == 1) { 5242 if ((tmpset->nodeTab[0] != NULL) && 5243 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) 5244 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); 5245 } 5246 tmpset->nodeNr = 0; 5247 memset(obj, 0, sizeof(xmlXPathObject)); 5248 obj->nodesetval = tmpset; 5249 } else 5250 memset(obj, 0, sizeof(xmlXPathObject)); 5251 5252 return; 5253 5254free_obj: 5255 /* 5256 * Cache is full; free the object. 5257 */ 5258 if (obj->nodesetval != NULL) 5259 xmlXPathFreeNodeSet(obj->nodesetval); 5260#ifdef XP_DEBUG_OBJ_USAGE 5261 xmlXPathDebugObjUsageReleased(NULL, obj->type); 5262#endif 5263 xmlFree(obj); 5264 } 5265 return; 5266} 5267 5268 5269/************************************************************************ 5270 * * 5271 * Type Casting Routines * 5272 * * 5273 ************************************************************************/ 5274 5275/** 5276 * xmlXPathCastBooleanToString: 5277 * @val: a boolean 5278 * 5279 * Converts a boolean to its string value. 5280 * 5281 * Returns a newly allocated string. 5282 */ 5283xmlChar * 5284xmlXPathCastBooleanToString (int val) { 5285 xmlChar *ret; 5286 if (val) 5287 ret = xmlStrdup((const xmlChar *) "true"); 5288 else 5289 ret = xmlStrdup((const xmlChar *) "false"); 5290 return(ret); 5291} 5292 5293/** 5294 * xmlXPathCastNumberToString: 5295 * @val: a number 5296 * 5297 * Converts a number to its string value. 5298 * 5299 * Returns a newly allocated string. 5300 */ 5301xmlChar * 5302xmlXPathCastNumberToString (double val) { 5303 xmlChar *ret; 5304 switch (xmlXPathIsInf(val)) { 5305 case 1: 5306 ret = xmlStrdup((const xmlChar *) "Infinity"); 5307 break; 5308 case -1: 5309 ret = xmlStrdup((const xmlChar *) "-Infinity"); 5310 break; 5311 default: 5312 if (xmlXPathIsNaN(val)) { 5313 ret = xmlStrdup((const xmlChar *) "NaN"); 5314 } else if (val == 0 && xmlXPathGetSign(val) != 0) { 5315 ret = xmlStrdup((const xmlChar *) "0"); 5316 } else { 5317 /* could be improved */ 5318 char buf[100]; 5319 xmlXPathFormatNumber(val, buf, 99); 5320 buf[99] = 0; 5321 ret = xmlStrdup((const xmlChar *) buf); 5322 } 5323 } 5324 return(ret); 5325} 5326 5327/** 5328 * xmlXPathCastNodeToString: 5329 * @node: a node 5330 * 5331 * Converts a node to its string value. 5332 * 5333 * Returns a newly allocated string. 5334 */ 5335xmlChar * 5336xmlXPathCastNodeToString (xmlNodePtr node) { 5337 return(xmlNodeGetContent(node)); 5338} 5339 5340/** 5341 * xmlXPathCastNodeSetToString: 5342 * @ns: a node-set 5343 * 5344 * Converts a node-set to its string value. 5345 * 5346 * Returns a newly allocated string. 5347 */ 5348xmlChar * 5349xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 5350 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 5351 return(xmlStrdup((const xmlChar *) "")); 5352 5353 if (ns->nodeNr > 1) 5354 xmlXPathNodeSetSort(ns); 5355 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 5356} 5357 5358/** 5359 * xmlXPathCastToString: 5360 * @val: an XPath object 5361 * 5362 * Converts an existing object to its string() equivalent 5363 * 5364 * Returns the string value of the object, NULL in case of error. 5365 * A new string is allocated only if needed (@val isn't a 5366 * string object). 5367 */ 5368xmlChar * 5369xmlXPathCastToString(xmlXPathObjectPtr val) { 5370 xmlChar *ret = NULL; 5371 5372 if (val == NULL) 5373 return(xmlStrdup((const xmlChar *) "")); 5374 switch (val->type) { 5375 case XPATH_UNDEFINED: 5376#ifdef DEBUG_EXPR 5377 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 5378#endif 5379 ret = xmlStrdup((const xmlChar *) ""); 5380 break; 5381 case XPATH_NODESET: 5382 case XPATH_XSLT_TREE: 5383 ret = xmlXPathCastNodeSetToString(val->nodesetval); 5384 break; 5385 case XPATH_STRING: 5386 return(xmlStrdup(val->stringval)); 5387 case XPATH_BOOLEAN: 5388 ret = xmlXPathCastBooleanToString(val->boolval); 5389 break; 5390 case XPATH_NUMBER: { 5391 ret = xmlXPathCastNumberToString(val->floatval); 5392 break; 5393 } 5394 case XPATH_USERS: 5395 case XPATH_POINT: 5396 case XPATH_RANGE: 5397 case XPATH_LOCATIONSET: 5398 TODO 5399 ret = xmlStrdup((const xmlChar *) ""); 5400 break; 5401 } 5402 return(ret); 5403} 5404 5405/** 5406 * xmlXPathConvertString: 5407 * @val: an XPath object 5408 * 5409 * Converts an existing object to its string() equivalent 5410 * 5411 * Returns the new object, the old one is freed (or the operation 5412 * is done directly on @val) 5413 */ 5414xmlXPathObjectPtr 5415xmlXPathConvertString(xmlXPathObjectPtr val) { 5416 xmlChar *res = NULL; 5417 5418 if (val == NULL) 5419 return(xmlXPathNewCString("")); 5420 5421 switch (val->type) { 5422 case XPATH_UNDEFINED: 5423#ifdef DEBUG_EXPR 5424 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 5425#endif 5426 break; 5427 case XPATH_NODESET: 5428 case XPATH_XSLT_TREE: 5429 res = xmlXPathCastNodeSetToString(val->nodesetval); 5430 break; 5431 case XPATH_STRING: 5432 return(val); 5433 case XPATH_BOOLEAN: 5434 res = xmlXPathCastBooleanToString(val->boolval); 5435 break; 5436 case XPATH_NUMBER: 5437 res = xmlXPathCastNumberToString(val->floatval); 5438 break; 5439 case XPATH_USERS: 5440 case XPATH_POINT: 5441 case XPATH_RANGE: 5442 case XPATH_LOCATIONSET: 5443 TODO; 5444 break; 5445 } 5446 xmlXPathFreeObject(val); 5447 if (res == NULL) 5448 return(xmlXPathNewCString("")); 5449 return(xmlXPathWrapString(res)); 5450} 5451 5452/** 5453 * xmlXPathCastBooleanToNumber: 5454 * @val: a boolean 5455 * 5456 * Converts a boolean to its number value 5457 * 5458 * Returns the number value 5459 */ 5460double 5461xmlXPathCastBooleanToNumber(int val) { 5462 if (val) 5463 return(1.0); 5464 return(0.0); 5465} 5466 5467/** 5468 * xmlXPathCastStringToNumber: 5469 * @val: a string 5470 * 5471 * Converts a string to its number value 5472 * 5473 * Returns the number value 5474 */ 5475double 5476xmlXPathCastStringToNumber(const xmlChar * val) { 5477 return(xmlXPathStringEvalNumber(val)); 5478} 5479 5480/** 5481 * xmlXPathCastNodeToNumber: 5482 * @node: a node 5483 * 5484 * Converts a node to its number value 5485 * 5486 * Returns the number value 5487 */ 5488double 5489xmlXPathCastNodeToNumber (xmlNodePtr node) { 5490 xmlChar *strval; 5491 double ret; 5492 5493 if (node == NULL) 5494 return(xmlXPathNAN); 5495 strval = xmlXPathCastNodeToString(node); 5496 if (strval == NULL) 5497 return(xmlXPathNAN); 5498 ret = xmlXPathCastStringToNumber(strval); 5499 xmlFree(strval); 5500 5501 return(ret); 5502} 5503 5504/** 5505 * xmlXPathCastNodeSetToNumber: 5506 * @ns: a node-set 5507 * 5508 * Converts a node-set to its number value 5509 * 5510 * Returns the number value 5511 */ 5512double 5513xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 5514 xmlChar *str; 5515 double ret; 5516 5517 if (ns == NULL) 5518 return(xmlXPathNAN); 5519 str = xmlXPathCastNodeSetToString(ns); 5520 ret = xmlXPathCastStringToNumber(str); 5521 xmlFree(str); 5522 return(ret); 5523} 5524 5525/** 5526 * xmlXPathCastToNumber: 5527 * @val: an XPath object 5528 * 5529 * Converts an XPath object to its number value 5530 * 5531 * Returns the number value 5532 */ 5533double 5534xmlXPathCastToNumber(xmlXPathObjectPtr val) { 5535 double ret = 0.0; 5536 5537 if (val == NULL) 5538 return(xmlXPathNAN); 5539 switch (val->type) { 5540 case XPATH_UNDEFINED: 5541#ifdef DEGUB_EXPR 5542 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 5543#endif 5544 ret = xmlXPathNAN; 5545 break; 5546 case XPATH_NODESET: 5547 case XPATH_XSLT_TREE: 5548 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 5549 break; 5550 case XPATH_STRING: 5551 ret = xmlXPathCastStringToNumber(val->stringval); 5552 break; 5553 case XPATH_NUMBER: 5554 ret = val->floatval; 5555 break; 5556 case XPATH_BOOLEAN: 5557 ret = xmlXPathCastBooleanToNumber(val->boolval); 5558 break; 5559 case XPATH_USERS: 5560 case XPATH_POINT: 5561 case XPATH_RANGE: 5562 case XPATH_LOCATIONSET: 5563 TODO; 5564 ret = xmlXPathNAN; 5565 break; 5566 } 5567 return(ret); 5568} 5569 5570/** 5571 * xmlXPathConvertNumber: 5572 * @val: an XPath object 5573 * 5574 * Converts an existing object to its number() equivalent 5575 * 5576 * Returns the new object, the old one is freed (or the operation 5577 * is done directly on @val) 5578 */ 5579xmlXPathObjectPtr 5580xmlXPathConvertNumber(xmlXPathObjectPtr val) { 5581 xmlXPathObjectPtr ret; 5582 5583 if (val == NULL) 5584 return(xmlXPathNewFloat(0.0)); 5585 if (val->type == XPATH_NUMBER) 5586 return(val); 5587 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 5588 xmlXPathFreeObject(val); 5589 return(ret); 5590} 5591 5592/** 5593 * xmlXPathCastNumberToBoolean: 5594 * @val: a number 5595 * 5596 * Converts a number to its boolean value 5597 * 5598 * Returns the boolean value 5599 */ 5600int 5601xmlXPathCastNumberToBoolean (double val) { 5602 if (xmlXPathIsNaN(val) || (val == 0.0)) 5603 return(0); 5604 return(1); 5605} 5606 5607/** 5608 * xmlXPathCastStringToBoolean: 5609 * @val: a string 5610 * 5611 * Converts a string to its boolean value 5612 * 5613 * Returns the boolean value 5614 */ 5615int 5616xmlXPathCastStringToBoolean (const xmlChar *val) { 5617 if ((val == NULL) || (xmlStrlen(val) == 0)) 5618 return(0); 5619 return(1); 5620} 5621 5622/** 5623 * xmlXPathCastNodeSetToBoolean: 5624 * @ns: a node-set 5625 * 5626 * Converts a node-set to its boolean value 5627 * 5628 * Returns the boolean value 5629 */ 5630int 5631xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 5632 if ((ns == NULL) || (ns->nodeNr == 0)) 5633 return(0); 5634 return(1); 5635} 5636 5637/** 5638 * xmlXPathCastToBoolean: 5639 * @val: an XPath object 5640 * 5641 * Converts an XPath object to its boolean value 5642 * 5643 * Returns the boolean value 5644 */ 5645int 5646xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 5647 int ret = 0; 5648 5649 if (val == NULL) 5650 return(0); 5651 switch (val->type) { 5652 case XPATH_UNDEFINED: 5653#ifdef DEBUG_EXPR 5654 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 5655#endif 5656 ret = 0; 5657 break; 5658 case XPATH_NODESET: 5659 case XPATH_XSLT_TREE: 5660 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 5661 break; 5662 case XPATH_STRING: 5663 ret = xmlXPathCastStringToBoolean(val->stringval); 5664 break; 5665 case XPATH_NUMBER: 5666 ret = xmlXPathCastNumberToBoolean(val->floatval); 5667 break; 5668 case XPATH_BOOLEAN: 5669 ret = val->boolval; 5670 break; 5671 case XPATH_USERS: 5672 case XPATH_POINT: 5673 case XPATH_RANGE: 5674 case XPATH_LOCATIONSET: 5675 TODO; 5676 ret = 0; 5677 break; 5678 } 5679 return(ret); 5680} 5681 5682 5683/** 5684 * xmlXPathConvertBoolean: 5685 * @val: an XPath object 5686 * 5687 * Converts an existing object to its boolean() equivalent 5688 * 5689 * Returns the new object, the old one is freed (or the operation 5690 * is done directly on @val) 5691 */ 5692xmlXPathObjectPtr 5693xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 5694 xmlXPathObjectPtr ret; 5695 5696 if (val == NULL) 5697 return(xmlXPathNewBoolean(0)); 5698 if (val->type == XPATH_BOOLEAN) 5699 return(val); 5700 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 5701 xmlXPathFreeObject(val); 5702 return(ret); 5703} 5704 5705/************************************************************************ 5706 * * 5707 * Routines to handle XPath contexts * 5708 * * 5709 ************************************************************************/ 5710 5711/** 5712 * xmlXPathNewContext: 5713 * @doc: the XML document 5714 * 5715 * Create a new xmlXPathContext 5716 * 5717 * Returns the xmlXPathContext just allocated. The caller will need to free it. 5718 */ 5719xmlXPathContextPtr 5720xmlXPathNewContext(xmlDocPtr doc) { 5721 xmlXPathContextPtr ret; 5722 5723 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 5724 if (ret == NULL) { 5725 xmlXPathErrMemory(NULL, "creating context\n"); 5726 return(NULL); 5727 } 5728 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 5729 ret->doc = doc; 5730 ret->node = NULL; 5731 5732 ret->varHash = NULL; 5733 5734 ret->nb_types = 0; 5735 ret->max_types = 0; 5736 ret->types = NULL; 5737 5738 ret->funcHash = xmlHashCreate(0); 5739 5740 ret->nb_axis = 0; 5741 ret->max_axis = 0; 5742 ret->axis = NULL; 5743 5744 ret->nsHash = NULL; 5745 ret->user = NULL; 5746 5747 ret->contextSize = -1; 5748 ret->proximityPosition = -1; 5749 5750#ifdef XP_DEFAULT_CACHE_ON 5751 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { 5752 xmlXPathFreeContext(ret); 5753 return(NULL); 5754 } 5755#endif 5756 5757 xmlXPathRegisterAllFunctions(ret); 5758 5759 return(ret); 5760} 5761 5762/** 5763 * xmlXPathFreeContext: 5764 * @ctxt: the context to free 5765 * 5766 * Free up an xmlXPathContext 5767 */ 5768void 5769xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 5770 if (ctxt == NULL) return; 5771 5772 if (ctxt->cache != NULL) 5773 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 5774 xmlXPathRegisteredNsCleanup(ctxt); 5775 xmlXPathRegisteredFuncsCleanup(ctxt); 5776 xmlXPathRegisteredVariablesCleanup(ctxt); 5777 xmlResetError(&ctxt->lastError); 5778 xmlFree(ctxt); 5779} 5780 5781/************************************************************************ 5782 * * 5783 * Routines to handle XPath parser contexts * 5784 * * 5785 ************************************************************************/ 5786 5787#define CHECK_CTXT(ctxt) \ 5788 if (ctxt == NULL) { \ 5789 __xmlRaiseError(NULL, NULL, NULL, \ 5790 NULL, NULL, XML_FROM_XPATH, \ 5791 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ 5792 __FILE__, __LINE__, \ 5793 NULL, NULL, NULL, 0, 0, \ 5794 "NULL context pointer\n"); \ 5795 return(NULL); \ 5796 } \ 5797 5798 5799#define CHECK_CONTEXT(ctxt) \ 5800 if ((ctxt == NULL) || (ctxt->doc == NULL) || \ 5801 (ctxt->doc->children == NULL)) { \ 5802 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ 5803 return(NULL); \ 5804 } 5805 5806 5807/** 5808 * xmlXPathNewParserContext: 5809 * @str: the XPath expression 5810 * @ctxt: the XPath context 5811 * 5812 * Create a new xmlXPathParserContext 5813 * 5814 * Returns the xmlXPathParserContext just allocated. 5815 */ 5816xmlXPathParserContextPtr 5817xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 5818 xmlXPathParserContextPtr ret; 5819 5820 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 5821 if (ret == NULL) { 5822 xmlXPathErrMemory(ctxt, "creating parser context\n"); 5823 return(NULL); 5824 } 5825 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 5826 ret->cur = ret->base = str; 5827 ret->context = ctxt; 5828 5829 ret->comp = xmlXPathNewCompExpr(); 5830 if (ret->comp == NULL) { 5831 xmlFree(ret->valueTab); 5832 xmlFree(ret); 5833 return(NULL); 5834 } 5835 if ((ctxt != NULL) && (ctxt->dict != NULL)) { 5836 ret->comp->dict = ctxt->dict; 5837 xmlDictReference(ret->comp->dict); 5838 } 5839 5840 return(ret); 5841} 5842 5843/** 5844 * xmlXPathCompParserContext: 5845 * @comp: the XPath compiled expression 5846 * @ctxt: the XPath context 5847 * 5848 * Create a new xmlXPathParserContext when processing a compiled expression 5849 * 5850 * Returns the xmlXPathParserContext just allocated. 5851 */ 5852static xmlXPathParserContextPtr 5853xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 5854 xmlXPathParserContextPtr ret; 5855 5856 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 5857 if (ret == NULL) { 5858 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 5859 return(NULL); 5860 } 5861 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 5862 5863 /* Allocate the value stack */ 5864 ret->valueTab = (xmlXPathObjectPtr *) 5865 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 5866 if (ret->valueTab == NULL) { 5867 xmlFree(ret); 5868 xmlXPathErrMemory(ctxt, "creating evaluation context\n"); 5869 return(NULL); 5870 } 5871 ret->valueNr = 0; 5872 ret->valueMax = 10; 5873 ret->value = NULL; 5874 5875 ret->context = ctxt; 5876 ret->comp = comp; 5877 5878 return(ret); 5879} 5880 5881/** 5882 * xmlXPathFreeParserContext: 5883 * @ctxt: the context to free 5884 * 5885 * Free up an xmlXPathParserContext 5886 */ 5887void 5888xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 5889 if (ctxt->valueTab != NULL) { 5890 xmlFree(ctxt->valueTab); 5891 } 5892 if (ctxt->comp != NULL) { 5893#ifdef XPATH_STREAMING 5894 if (ctxt->comp->stream != NULL) { 5895 xmlFreePatternList(ctxt->comp->stream); 5896 ctxt->comp->stream = NULL; 5897 } 5898#endif 5899 xmlXPathFreeCompExpr(ctxt->comp); 5900 } 5901 xmlFree(ctxt); 5902} 5903 5904/************************************************************************ 5905 * * 5906 * The implicit core function library * 5907 * * 5908 ************************************************************************/ 5909 5910/** 5911 * xmlXPathNodeValHash: 5912 * @node: a node pointer 5913 * 5914 * Function computing the beginning of the string value of the node, 5915 * used to speed up comparisons 5916 * 5917 * Returns an int usable as a hash 5918 */ 5919static unsigned int 5920xmlXPathNodeValHash(xmlNodePtr node) { 5921 int len = 2; 5922 const xmlChar * string = NULL; 5923 xmlNodePtr tmp = NULL; 5924 unsigned int ret = 0; 5925 5926 if (node == NULL) 5927 return(0); 5928 5929 if (node->type == XML_DOCUMENT_NODE) { 5930 tmp = xmlDocGetRootElement((xmlDocPtr) node); 5931 if (tmp == NULL) 5932 node = node->children; 5933 else 5934 node = tmp; 5935 5936 if (node == NULL) 5937 return(0); 5938 } 5939 5940 switch (node->type) { 5941 case XML_COMMENT_NODE: 5942 case XML_PI_NODE: 5943 case XML_CDATA_SECTION_NODE: 5944 case XML_TEXT_NODE: 5945 string = node->content; 5946 if (string == NULL) 5947 return(0); 5948 if (string[0] == 0) 5949 return(0); 5950 return(((unsigned int) string[0]) + 5951 (((unsigned int) string[1]) << 8)); 5952 case XML_NAMESPACE_DECL: 5953 string = ((xmlNsPtr)node)->href; 5954 if (string == NULL) 5955 return(0); 5956 if (string[0] == 0) 5957 return(0); 5958 return(((unsigned int) string[0]) + 5959 (((unsigned int) string[1]) << 8)); 5960 case XML_ATTRIBUTE_NODE: 5961 tmp = ((xmlAttrPtr) node)->children; 5962 break; 5963 case XML_ELEMENT_NODE: 5964 tmp = node->children; 5965 break; 5966 default: 5967 return(0); 5968 } 5969 while (tmp != NULL) { 5970 switch (tmp->type) { 5971 case XML_COMMENT_NODE: 5972 case XML_PI_NODE: 5973 case XML_CDATA_SECTION_NODE: 5974 case XML_TEXT_NODE: 5975 string = tmp->content; 5976 break; 5977 case XML_NAMESPACE_DECL: 5978 string = ((xmlNsPtr)tmp)->href; 5979 break; 5980 default: 5981 break; 5982 } 5983 if ((string != NULL) && (string[0] != 0)) { 5984 if (len == 1) { 5985 return(ret + (((unsigned int) string[0]) << 8)); 5986 } 5987 if (string[1] == 0) { 5988 len = 1; 5989 ret = (unsigned int) string[0]; 5990 } else { 5991 return(((unsigned int) string[0]) + 5992 (((unsigned int) string[1]) << 8)); 5993 } 5994 } 5995 /* 5996 * Skip to next node 5997 */ 5998 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 5999 if (tmp->children->type != XML_ENTITY_DECL) { 6000 tmp = tmp->children; 6001 continue; 6002 } 6003 } 6004 if (tmp == node) 6005 break; 6006 6007 if (tmp->next != NULL) { 6008 tmp = tmp->next; 6009 continue; 6010 } 6011 6012 do { 6013 tmp = tmp->parent; 6014 if (tmp == NULL) 6015 break; 6016 if (tmp == node) { 6017 tmp = NULL; 6018 break; 6019 } 6020 if (tmp->next != NULL) { 6021 tmp = tmp->next; 6022 break; 6023 } 6024 } while (tmp != NULL); 6025 } 6026 return(ret); 6027} 6028 6029/** 6030 * xmlXPathStringHash: 6031 * @string: a string 6032 * 6033 * Function computing the beginning of the string value of the node, 6034 * used to speed up comparisons 6035 * 6036 * Returns an int usable as a hash 6037 */ 6038static unsigned int 6039xmlXPathStringHash(const xmlChar * string) { 6040 if (string == NULL) 6041 return((unsigned int) 0); 6042 if (string[0] == 0) 6043 return(0); 6044 return(((unsigned int) string[0]) + 6045 (((unsigned int) string[1]) << 8)); 6046} 6047 6048/** 6049 * xmlXPathCompareNodeSetFloat: 6050 * @ctxt: the XPath Parser context 6051 * @inf: less than (1) or greater than (0) 6052 * @strict: is the comparison strict 6053 * @arg: the node set 6054 * @f: the value 6055 * 6056 * Implement the compare operation between a nodeset and a number 6057 * @ns < @val (1, 1, ... 6058 * @ns <= @val (1, 0, ... 6059 * @ns > @val (0, 1, ... 6060 * @ns >= @val (0, 0, ... 6061 * 6062 * If one object to be compared is a node-set and the other is a number, 6063 * then the comparison will be true if and only if there is a node in the 6064 * node-set such that the result of performing the comparison on the number 6065 * to be compared and on the result of converting the string-value of that 6066 * node to a number using the number function is true. 6067 * 6068 * Returns 0 or 1 depending on the results of the test. 6069 */ 6070static int 6071xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 6072 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 6073 int i, ret = 0; 6074 xmlNodeSetPtr ns; 6075 xmlChar *str2; 6076 6077 if ((f == NULL) || (arg == NULL) || 6078 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6079 xmlXPathReleaseObject(ctxt->context, arg); 6080 xmlXPathReleaseObject(ctxt->context, f); 6081 return(0); 6082 } 6083 ns = arg->nodesetval; 6084 if (ns != NULL) { 6085 for (i = 0;i < ns->nodeNr;i++) { 6086 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6087 if (str2 != NULL) { 6088 valuePush(ctxt, 6089 xmlXPathCacheNewString(ctxt->context, str2)); 6090 xmlFree(str2); 6091 xmlXPathNumberFunction(ctxt, 1); 6092 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); 6093 ret = xmlXPathCompareValues(ctxt, inf, strict); 6094 if (ret) 6095 break; 6096 } 6097 } 6098 } 6099 xmlXPathReleaseObject(ctxt->context, arg); 6100 xmlXPathReleaseObject(ctxt->context, f); 6101 return(ret); 6102} 6103 6104/** 6105 * xmlXPathCompareNodeSetString: 6106 * @ctxt: the XPath Parser context 6107 * @inf: less than (1) or greater than (0) 6108 * @strict: is the comparison strict 6109 * @arg: the node set 6110 * @s: the value 6111 * 6112 * Implement the compare operation between a nodeset and a string 6113 * @ns < @val (1, 1, ... 6114 * @ns <= @val (1, 0, ... 6115 * @ns > @val (0, 1, ... 6116 * @ns >= @val (0, 0, ... 6117 * 6118 * If one object to be compared is a node-set and the other is a string, 6119 * then the comparison will be true if and only if there is a node in 6120 * the node-set such that the result of performing the comparison on the 6121 * string-value of the node and the other string is true. 6122 * 6123 * Returns 0 or 1 depending on the results of the test. 6124 */ 6125static int 6126xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 6127 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 6128 int i, ret = 0; 6129 xmlNodeSetPtr ns; 6130 xmlChar *str2; 6131 6132 if ((s == NULL) || (arg == NULL) || 6133 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 6134 xmlXPathReleaseObject(ctxt->context, arg); 6135 xmlXPathReleaseObject(ctxt->context, s); 6136 return(0); 6137 } 6138 ns = arg->nodesetval; 6139 if (ns != NULL) { 6140 for (i = 0;i < ns->nodeNr;i++) { 6141 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6142 if (str2 != NULL) { 6143 valuePush(ctxt, 6144 xmlXPathCacheNewString(ctxt->context, str2)); 6145 xmlFree(str2); 6146 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); 6147 ret = xmlXPathCompareValues(ctxt, inf, strict); 6148 if (ret) 6149 break; 6150 } 6151 } 6152 } 6153 xmlXPathReleaseObject(ctxt->context, arg); 6154 xmlXPathReleaseObject(ctxt->context, s); 6155 return(ret); 6156} 6157 6158/** 6159 * xmlXPathCompareNodeSets: 6160 * @inf: less than (1) or greater than (0) 6161 * @strict: is the comparison strict 6162 * @arg1: the first node set object 6163 * @arg2: the second node set object 6164 * 6165 * Implement the compare operation on nodesets: 6166 * 6167 * If both objects to be compared are node-sets, then the comparison 6168 * will be true if and only if there is a node in the first node-set 6169 * and a node in the second node-set such that the result of performing 6170 * the comparison on the string-values of the two nodes is true. 6171 * .... 6172 * When neither object to be compared is a node-set and the operator 6173 * is <=, <, >= or >, then the objects are compared by converting both 6174 * objects to numbers and comparing the numbers according to IEEE 754. 6175 * .... 6176 * The number function converts its argument to a number as follows: 6177 * - a string that consists of optional whitespace followed by an 6178 * optional minus sign followed by a Number followed by whitespace 6179 * is converted to the IEEE 754 number that is nearest (according 6180 * to the IEEE 754 round-to-nearest rule) to the mathematical value 6181 * represented by the string; any other string is converted to NaN 6182 * 6183 * Conclusion all nodes need to be converted first to their string value 6184 * and then the comparison must be done when possible 6185 */ 6186static int 6187xmlXPathCompareNodeSets(int inf, int strict, 6188 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6189 int i, j, init = 0; 6190 double val1; 6191 double *values2; 6192 int ret = 0; 6193 xmlNodeSetPtr ns1; 6194 xmlNodeSetPtr ns2; 6195 6196 if ((arg1 == NULL) || 6197 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 6198 xmlXPathFreeObject(arg2); 6199 return(0); 6200 } 6201 if ((arg2 == NULL) || 6202 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 6203 xmlXPathFreeObject(arg1); 6204 xmlXPathFreeObject(arg2); 6205 return(0); 6206 } 6207 6208 ns1 = arg1->nodesetval; 6209 ns2 = arg2->nodesetval; 6210 6211 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 6212 xmlXPathFreeObject(arg1); 6213 xmlXPathFreeObject(arg2); 6214 return(0); 6215 } 6216 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 6217 xmlXPathFreeObject(arg1); 6218 xmlXPathFreeObject(arg2); 6219 return(0); 6220 } 6221 6222 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 6223 if (values2 == NULL) { 6224 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6225 xmlXPathFreeObject(arg1); 6226 xmlXPathFreeObject(arg2); 6227 return(0); 6228 } 6229 for (i = 0;i < ns1->nodeNr;i++) { 6230 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 6231 if (xmlXPathIsNaN(val1)) 6232 continue; 6233 for (j = 0;j < ns2->nodeNr;j++) { 6234 if (init == 0) { 6235 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 6236 } 6237 if (xmlXPathIsNaN(values2[j])) 6238 continue; 6239 if (inf && strict) 6240 ret = (val1 < values2[j]); 6241 else if (inf && !strict) 6242 ret = (val1 <= values2[j]); 6243 else if (!inf && strict) 6244 ret = (val1 > values2[j]); 6245 else if (!inf && !strict) 6246 ret = (val1 >= values2[j]); 6247 if (ret) 6248 break; 6249 } 6250 if (ret) 6251 break; 6252 init = 1; 6253 } 6254 xmlFree(values2); 6255 xmlXPathFreeObject(arg1); 6256 xmlXPathFreeObject(arg2); 6257 return(ret); 6258} 6259 6260/** 6261 * xmlXPathCompareNodeSetValue: 6262 * @ctxt: the XPath Parser context 6263 * @inf: less than (1) or greater than (0) 6264 * @strict: is the comparison strict 6265 * @arg: the node set 6266 * @val: the value 6267 * 6268 * Implement the compare operation between a nodeset and a value 6269 * @ns < @val (1, 1, ... 6270 * @ns <= @val (1, 0, ... 6271 * @ns > @val (0, 1, ... 6272 * @ns >= @val (0, 0, ... 6273 * 6274 * If one object to be compared is a node-set and the other is a boolean, 6275 * then the comparison will be true if and only if the result of performing 6276 * the comparison on the boolean and on the result of converting 6277 * the node-set to a boolean using the boolean function is true. 6278 * 6279 * Returns 0 or 1 depending on the results of the test. 6280 */ 6281static int 6282xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 6283 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 6284 if ((val == NULL) || (arg == NULL) || 6285 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6286 return(0); 6287 6288 switch(val->type) { 6289 case XPATH_NUMBER: 6290 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 6291 case XPATH_NODESET: 6292 case XPATH_XSLT_TREE: 6293 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 6294 case XPATH_STRING: 6295 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 6296 case XPATH_BOOLEAN: 6297 valuePush(ctxt, arg); 6298 xmlXPathBooleanFunction(ctxt, 1); 6299 valuePush(ctxt, val); 6300 return(xmlXPathCompareValues(ctxt, inf, strict)); 6301 default: 6302 TODO 6303 } 6304 return(0); 6305} 6306 6307/** 6308 * xmlXPathEqualNodeSetString: 6309 * @arg: the nodeset object argument 6310 * @str: the string to compare to. 6311 * @neq: flag to show whether for '=' (0) or '!=' (1) 6312 * 6313 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6314 * If one object to be compared is a node-set and the other is a string, 6315 * then the comparison will be true if and only if there is a node in 6316 * the node-set such that the result of performing the comparison on the 6317 * string-value of the node and the other string is true. 6318 * 6319 * Returns 0 or 1 depending on the results of the test. 6320 */ 6321static int 6322xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) 6323{ 6324 int i; 6325 xmlNodeSetPtr ns; 6326 xmlChar *str2; 6327 unsigned int hash; 6328 6329 if ((str == NULL) || (arg == NULL) || 6330 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6331 return (0); 6332 ns = arg->nodesetval; 6333 /* 6334 * A NULL nodeset compared with a string is always false 6335 * (since there is no node equal, and no node not equal) 6336 */ 6337 if ((ns == NULL) || (ns->nodeNr <= 0) ) 6338 return (0); 6339 hash = xmlXPathStringHash(str); 6340 for (i = 0; i < ns->nodeNr; i++) { 6341 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 6342 str2 = xmlNodeGetContent(ns->nodeTab[i]); 6343 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 6344 xmlFree(str2); 6345 if (neq) 6346 continue; 6347 return (1); 6348 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { 6349 if (neq) 6350 continue; 6351 return (1); 6352 } else if (neq) { 6353 if (str2 != NULL) 6354 xmlFree(str2); 6355 return (1); 6356 } 6357 if (str2 != NULL) 6358 xmlFree(str2); 6359 } else if (neq) 6360 return (1); 6361 } 6362 return (0); 6363} 6364 6365/** 6366 * xmlXPathEqualNodeSetFloat: 6367 * @arg: the nodeset object argument 6368 * @f: the float to compare to 6369 * @neq: flag to show whether to compare '=' (0) or '!=' (1) 6370 * 6371 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6372 * If one object to be compared is a node-set and the other is a number, 6373 * then the comparison will be true if and only if there is a node in 6374 * the node-set such that the result of performing the comparison on the 6375 * number to be compared and on the result of converting the string-value 6376 * of that node to a number using the number function is true. 6377 * 6378 * Returns 0 or 1 depending on the results of the test. 6379 */ 6380static int 6381xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, 6382 xmlXPathObjectPtr arg, double f, int neq) { 6383 int i, ret=0; 6384 xmlNodeSetPtr ns; 6385 xmlChar *str2; 6386 xmlXPathObjectPtr val; 6387 double v; 6388 6389 if ((arg == NULL) || 6390 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 6391 return(0); 6392 6393 ns = arg->nodesetval; 6394 if (ns != NULL) { 6395 for (i=0;i<ns->nodeNr;i++) { 6396 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 6397 if (str2 != NULL) { 6398 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); 6399 xmlFree(str2); 6400 xmlXPathNumberFunction(ctxt, 1); 6401 val = valuePop(ctxt); 6402 v = val->floatval; 6403 xmlXPathReleaseObject(ctxt->context, val); 6404 if (!xmlXPathIsNaN(v)) { 6405 if ((!neq) && (v==f)) { 6406 ret = 1; 6407 break; 6408 } else if ((neq) && (v!=f)) { 6409 ret = 1; 6410 break; 6411 } 6412 } else { /* NaN is unequal to any value */ 6413 if (neq) 6414 ret = 1; 6415 } 6416 } 6417 } 6418 } 6419 6420 return(ret); 6421} 6422 6423 6424/** 6425 * xmlXPathEqualNodeSets: 6426 * @arg1: first nodeset object argument 6427 * @arg2: second nodeset object argument 6428 * @neq: flag to show whether to test '=' (0) or '!=' (1) 6429 * 6430 * Implement the equal / not equal operation on XPath nodesets: 6431 * @arg1 == @arg2 or @arg1 != @arg2 6432 * If both objects to be compared are node-sets, then the comparison 6433 * will be true if and only if there is a node in the first node-set and 6434 * a node in the second node-set such that the result of performing the 6435 * comparison on the string-values of the two nodes is true. 6436 * 6437 * (needless to say, this is a costly operation) 6438 * 6439 * Returns 0 or 1 depending on the results of the test. 6440 */ 6441static int 6442xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { 6443 int i, j; 6444 unsigned int *hashs1; 6445 unsigned int *hashs2; 6446 xmlChar **values1; 6447 xmlChar **values2; 6448 int ret = 0; 6449 xmlNodeSetPtr ns1; 6450 xmlNodeSetPtr ns2; 6451 6452 if ((arg1 == NULL) || 6453 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 6454 return(0); 6455 if ((arg2 == NULL) || 6456 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 6457 return(0); 6458 6459 ns1 = arg1->nodesetval; 6460 ns2 = arg2->nodesetval; 6461 6462 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 6463 return(0); 6464 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 6465 return(0); 6466 6467 /* 6468 * for equal, check if there is a node pertaining to both sets 6469 */ 6470 if (neq == 0) 6471 for (i = 0;i < ns1->nodeNr;i++) 6472 for (j = 0;j < ns2->nodeNr;j++) 6473 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 6474 return(1); 6475 6476 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 6477 if (values1 == NULL) { 6478 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6479 return(0); 6480 } 6481 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 6482 if (hashs1 == NULL) { 6483 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6484 xmlFree(values1); 6485 return(0); 6486 } 6487 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 6488 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 6489 if (values2 == NULL) { 6490 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6491 xmlFree(hashs1); 6492 xmlFree(values1); 6493 return(0); 6494 } 6495 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 6496 if (hashs2 == NULL) { 6497 xmlXPathErrMemory(NULL, "comparing nodesets\n"); 6498 xmlFree(hashs1); 6499 xmlFree(values1); 6500 xmlFree(values2); 6501 return(0); 6502 } 6503 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 6504 for (i = 0;i < ns1->nodeNr;i++) { 6505 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 6506 for (j = 0;j < ns2->nodeNr;j++) { 6507 if (i == 0) 6508 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 6509 if (hashs1[i] != hashs2[j]) { 6510 if (neq) { 6511 ret = 1; 6512 break; 6513 } 6514 } 6515 else { 6516 if (values1[i] == NULL) 6517 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 6518 if (values2[j] == NULL) 6519 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 6520 ret = xmlStrEqual(values1[i], values2[j]) ^ neq; 6521 if (ret) 6522 break; 6523 } 6524 } 6525 if (ret) 6526 break; 6527 } 6528 for (i = 0;i < ns1->nodeNr;i++) 6529 if (values1[i] != NULL) 6530 xmlFree(values1[i]); 6531 for (j = 0;j < ns2->nodeNr;j++) 6532 if (values2[j] != NULL) 6533 xmlFree(values2[j]); 6534 xmlFree(values1); 6535 xmlFree(values2); 6536 xmlFree(hashs1); 6537 xmlFree(hashs2); 6538 return(ret); 6539} 6540 6541static int 6542xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, 6543 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 6544 int ret = 0; 6545 /* 6546 *At this point we are assured neither arg1 nor arg2 6547 *is a nodeset, so we can just pick the appropriate routine. 6548 */ 6549 switch (arg1->type) { 6550 case XPATH_UNDEFINED: 6551#ifdef DEBUG_EXPR 6552 xmlGenericError(xmlGenericErrorContext, 6553 "Equal: undefined\n"); 6554#endif 6555 break; 6556 case XPATH_BOOLEAN: 6557 switch (arg2->type) { 6558 case XPATH_UNDEFINED: 6559#ifdef DEBUG_EXPR 6560 xmlGenericError(xmlGenericErrorContext, 6561 "Equal: undefined\n"); 6562#endif 6563 break; 6564 case XPATH_BOOLEAN: 6565#ifdef DEBUG_EXPR 6566 xmlGenericError(xmlGenericErrorContext, 6567 "Equal: %d boolean %d \n", 6568 arg1->boolval, arg2->boolval); 6569#endif 6570 ret = (arg1->boolval == arg2->boolval); 6571 break; 6572 case XPATH_NUMBER: 6573 ret = (arg1->boolval == 6574 xmlXPathCastNumberToBoolean(arg2->floatval)); 6575 break; 6576 case XPATH_STRING: 6577 if ((arg2->stringval == NULL) || 6578 (arg2->stringval[0] == 0)) ret = 0; 6579 else 6580 ret = 1; 6581 ret = (arg1->boolval == ret); 6582 break; 6583 case XPATH_USERS: 6584 case XPATH_POINT: 6585 case XPATH_RANGE: 6586 case XPATH_LOCATIONSET: 6587 TODO 6588 break; 6589 case XPATH_NODESET: 6590 case XPATH_XSLT_TREE: 6591 break; 6592 } 6593 break; 6594 case XPATH_NUMBER: 6595 switch (arg2->type) { 6596 case XPATH_UNDEFINED: 6597#ifdef DEBUG_EXPR 6598 xmlGenericError(xmlGenericErrorContext, 6599 "Equal: undefined\n"); 6600#endif 6601 break; 6602 case XPATH_BOOLEAN: 6603 ret = (arg2->boolval== 6604 xmlXPathCastNumberToBoolean(arg1->floatval)); 6605 break; 6606 case XPATH_STRING: 6607 valuePush(ctxt, arg2); 6608 xmlXPathNumberFunction(ctxt, 1); 6609 arg2 = valuePop(ctxt); 6610 /* no break on purpose */ 6611 case XPATH_NUMBER: 6612 /* Hand check NaN and Infinity equalities */ 6613 if (xmlXPathIsNaN(arg1->floatval) || 6614 xmlXPathIsNaN(arg2->floatval)) { 6615 ret = 0; 6616 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 6617 if (xmlXPathIsInf(arg2->floatval) == 1) 6618 ret = 1; 6619 else 6620 ret = 0; 6621 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 6622 if (xmlXPathIsInf(arg2->floatval) == -1) 6623 ret = 1; 6624 else 6625 ret = 0; 6626 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 6627 if (xmlXPathIsInf(arg1->floatval) == 1) 6628 ret = 1; 6629 else 6630 ret = 0; 6631 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 6632 if (xmlXPathIsInf(arg1->floatval) == -1) 6633 ret = 1; 6634 else 6635 ret = 0; 6636 } else { 6637 ret = (arg1->floatval == arg2->floatval); 6638 } 6639 break; 6640 case XPATH_USERS: 6641 case XPATH_POINT: 6642 case XPATH_RANGE: 6643 case XPATH_LOCATIONSET: 6644 TODO 6645 break; 6646 case XPATH_NODESET: 6647 case XPATH_XSLT_TREE: 6648 break; 6649 } 6650 break; 6651 case XPATH_STRING: 6652 switch (arg2->type) { 6653 case XPATH_UNDEFINED: 6654#ifdef DEBUG_EXPR 6655 xmlGenericError(xmlGenericErrorContext, 6656 "Equal: undefined\n"); 6657#endif 6658 break; 6659 case XPATH_BOOLEAN: 6660 if ((arg1->stringval == NULL) || 6661 (arg1->stringval[0] == 0)) ret = 0; 6662 else 6663 ret = 1; 6664 ret = (arg2->boolval == ret); 6665 break; 6666 case XPATH_STRING: 6667 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 6668 break; 6669 case XPATH_NUMBER: 6670 valuePush(ctxt, arg1); 6671 xmlXPathNumberFunction(ctxt, 1); 6672 arg1 = valuePop(ctxt); 6673 /* Hand check NaN and Infinity equalities */ 6674 if (xmlXPathIsNaN(arg1->floatval) || 6675 xmlXPathIsNaN(arg2->floatval)) { 6676 ret = 0; 6677 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 6678 if (xmlXPathIsInf(arg2->floatval) == 1) 6679 ret = 1; 6680 else 6681 ret = 0; 6682 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 6683 if (xmlXPathIsInf(arg2->floatval) == -1) 6684 ret = 1; 6685 else 6686 ret = 0; 6687 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 6688 if (xmlXPathIsInf(arg1->floatval) == 1) 6689 ret = 1; 6690 else 6691 ret = 0; 6692 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 6693 if (xmlXPathIsInf(arg1->floatval) == -1) 6694 ret = 1; 6695 else 6696 ret = 0; 6697 } else { 6698 ret = (arg1->floatval == arg2->floatval); 6699 } 6700 break; 6701 case XPATH_USERS: 6702 case XPATH_POINT: 6703 case XPATH_RANGE: 6704 case XPATH_LOCATIONSET: 6705 TODO 6706 break; 6707 case XPATH_NODESET: 6708 case XPATH_XSLT_TREE: 6709 break; 6710 } 6711 break; 6712 case XPATH_USERS: 6713 case XPATH_POINT: 6714 case XPATH_RANGE: 6715 case XPATH_LOCATIONSET: 6716 TODO 6717 break; 6718 case XPATH_NODESET: 6719 case XPATH_XSLT_TREE: 6720 break; 6721 } 6722 xmlXPathReleaseObject(ctxt->context, arg1); 6723 xmlXPathReleaseObject(ctxt->context, arg2); 6724 return(ret); 6725} 6726 6727/** 6728 * xmlXPathEqualValues: 6729 * @ctxt: the XPath Parser context 6730 * 6731 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6732 * 6733 * Returns 0 or 1 depending on the results of the test. 6734 */ 6735int 6736xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 6737 xmlXPathObjectPtr arg1, arg2, argtmp; 6738 int ret = 0; 6739 6740 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 6741 arg2 = valuePop(ctxt); 6742 arg1 = valuePop(ctxt); 6743 if ((arg1 == NULL) || (arg2 == NULL)) { 6744 if (arg1 != NULL) 6745 xmlXPathReleaseObject(ctxt->context, arg1); 6746 else 6747 xmlXPathReleaseObject(ctxt->context, arg2); 6748 XP_ERROR0(XPATH_INVALID_OPERAND); 6749 } 6750 6751 if (arg1 == arg2) { 6752#ifdef DEBUG_EXPR 6753 xmlGenericError(xmlGenericErrorContext, 6754 "Equal: by pointer\n"); 6755#endif 6756 xmlXPathFreeObject(arg1); 6757 return(1); 6758 } 6759 6760 /* 6761 *If either argument is a nodeset, it's a 'special case' 6762 */ 6763 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 6764 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 6765 /* 6766 *Hack it to assure arg1 is the nodeset 6767 */ 6768 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 6769 argtmp = arg2; 6770 arg2 = arg1; 6771 arg1 = argtmp; 6772 } 6773 switch (arg2->type) { 6774 case XPATH_UNDEFINED: 6775#ifdef DEBUG_EXPR 6776 xmlGenericError(xmlGenericErrorContext, 6777 "Equal: undefined\n"); 6778#endif 6779 break; 6780 case XPATH_NODESET: 6781 case XPATH_XSLT_TREE: 6782 ret = xmlXPathEqualNodeSets(arg1, arg2, 0); 6783 break; 6784 case XPATH_BOOLEAN: 6785 if ((arg1->nodesetval == NULL) || 6786 (arg1->nodesetval->nodeNr == 0)) ret = 0; 6787 else 6788 ret = 1; 6789 ret = (ret == arg2->boolval); 6790 break; 6791 case XPATH_NUMBER: 6792 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); 6793 break; 6794 case XPATH_STRING: 6795 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); 6796 break; 6797 case XPATH_USERS: 6798 case XPATH_POINT: 6799 case XPATH_RANGE: 6800 case XPATH_LOCATIONSET: 6801 TODO 6802 break; 6803 } 6804 xmlXPathReleaseObject(ctxt->context, arg1); 6805 xmlXPathReleaseObject(ctxt->context, arg2); 6806 return(ret); 6807 } 6808 6809 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 6810} 6811 6812/** 6813 * xmlXPathNotEqualValues: 6814 * @ctxt: the XPath Parser context 6815 * 6816 * Implement the equal operation on XPath objects content: @arg1 == @arg2 6817 * 6818 * Returns 0 or 1 depending on the results of the test. 6819 */ 6820int 6821xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { 6822 xmlXPathObjectPtr arg1, arg2, argtmp; 6823 int ret = 0; 6824 6825 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 6826 arg2 = valuePop(ctxt); 6827 arg1 = valuePop(ctxt); 6828 if ((arg1 == NULL) || (arg2 == NULL)) { 6829 if (arg1 != NULL) 6830 xmlXPathReleaseObject(ctxt->context, arg1); 6831 else 6832 xmlXPathReleaseObject(ctxt->context, arg2); 6833 XP_ERROR0(XPATH_INVALID_OPERAND); 6834 } 6835 6836 if (arg1 == arg2) { 6837#ifdef DEBUG_EXPR 6838 xmlGenericError(xmlGenericErrorContext, 6839 "NotEqual: by pointer\n"); 6840#endif 6841 xmlXPathReleaseObject(ctxt->context, arg1); 6842 return(0); 6843 } 6844 6845 /* 6846 *If either argument is a nodeset, it's a 'special case' 6847 */ 6848 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 6849 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 6850 /* 6851 *Hack it to assure arg1 is the nodeset 6852 */ 6853 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { 6854 argtmp = arg2; 6855 arg2 = arg1; 6856 arg1 = argtmp; 6857 } 6858 switch (arg2->type) { 6859 case XPATH_UNDEFINED: 6860#ifdef DEBUG_EXPR 6861 xmlGenericError(xmlGenericErrorContext, 6862 "NotEqual: undefined\n"); 6863#endif 6864 break; 6865 case XPATH_NODESET: 6866 case XPATH_XSLT_TREE: 6867 ret = xmlXPathEqualNodeSets(arg1, arg2, 1); 6868 break; 6869 case XPATH_BOOLEAN: 6870 if ((arg1->nodesetval == NULL) || 6871 (arg1->nodesetval->nodeNr == 0)) ret = 0; 6872 else 6873 ret = 1; 6874 ret = (ret != arg2->boolval); 6875 break; 6876 case XPATH_NUMBER: 6877 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); 6878 break; 6879 case XPATH_STRING: 6880 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); 6881 break; 6882 case XPATH_USERS: 6883 case XPATH_POINT: 6884 case XPATH_RANGE: 6885 case XPATH_LOCATIONSET: 6886 TODO 6887 break; 6888 } 6889 xmlXPathReleaseObject(ctxt->context, arg1); 6890 xmlXPathReleaseObject(ctxt->context, arg2); 6891 return(ret); 6892 } 6893 6894 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); 6895} 6896 6897/** 6898 * xmlXPathCompareValues: 6899 * @ctxt: the XPath Parser context 6900 * @inf: less than (1) or greater than (0) 6901 * @strict: is the comparison strict 6902 * 6903 * Implement the compare operation on XPath objects: 6904 * @arg1 < @arg2 (1, 1, ... 6905 * @arg1 <= @arg2 (1, 0, ... 6906 * @arg1 > @arg2 (0, 1, ... 6907 * @arg1 >= @arg2 (0, 0, ... 6908 * 6909 * When neither object to be compared is a node-set and the operator is 6910 * <=, <, >=, >, then the objects are compared by converted both objects 6911 * to numbers and comparing the numbers according to IEEE 754. The < 6912 * comparison will be true if and only if the first number is less than the 6913 * second number. The <= comparison will be true if and only if the first 6914 * number is less than or equal to the second number. The > comparison 6915 * will be true if and only if the first number is greater than the second 6916 * number. The >= comparison will be true if and only if the first number 6917 * is greater than or equal to the second number. 6918 * 6919 * Returns 1 if the comparison succeeded, 0 if it failed 6920 */ 6921int 6922xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 6923 int ret = 0, arg1i = 0, arg2i = 0; 6924 xmlXPathObjectPtr arg1, arg2; 6925 6926 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); 6927 arg2 = valuePop(ctxt); 6928 arg1 = valuePop(ctxt); 6929 if ((arg1 == NULL) || (arg2 == NULL)) { 6930 if (arg1 != NULL) 6931 xmlXPathReleaseObject(ctxt->context, arg1); 6932 else 6933 xmlXPathReleaseObject(ctxt->context, arg2); 6934 XP_ERROR0(XPATH_INVALID_OPERAND); 6935 } 6936 6937 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || 6938 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 6939 /* 6940 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments 6941 * are not freed from within this routine; they will be freed from the 6942 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue 6943 */ 6944 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && 6945 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ 6946 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 6947 } else { 6948 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { 6949 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 6950 arg1, arg2); 6951 } else { 6952 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 6953 arg2, arg1); 6954 } 6955 } 6956 return(ret); 6957 } 6958 6959 if (arg1->type != XPATH_NUMBER) { 6960 valuePush(ctxt, arg1); 6961 xmlXPathNumberFunction(ctxt, 1); 6962 arg1 = valuePop(ctxt); 6963 } 6964 if (arg1->type != XPATH_NUMBER) { 6965 xmlXPathFreeObject(arg1); 6966 xmlXPathFreeObject(arg2); 6967 XP_ERROR0(XPATH_INVALID_OPERAND); 6968 } 6969 if (arg2->type != XPATH_NUMBER) { 6970 valuePush(ctxt, arg2); 6971 xmlXPathNumberFunction(ctxt, 1); 6972 arg2 = valuePop(ctxt); 6973 } 6974 if (arg2->type != XPATH_NUMBER) { 6975 xmlXPathReleaseObject(ctxt->context, arg1); 6976 xmlXPathReleaseObject(ctxt->context, arg2); 6977 XP_ERROR0(XPATH_INVALID_OPERAND); 6978 } 6979 /* 6980 * Add tests for infinity and nan 6981 * => feedback on 3.4 for Inf and NaN 6982 */ 6983 /* Hand check NaN and Infinity comparisons */ 6984 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 6985 ret=0; 6986 } else { 6987 arg1i=xmlXPathIsInf(arg1->floatval); 6988 arg2i=xmlXPathIsInf(arg2->floatval); 6989 if (inf && strict) { 6990 if ((arg1i == -1 && arg2i != -1) || 6991 (arg2i == 1 && arg1i != 1)) { 6992 ret = 1; 6993 } else if (arg1i == 0 && arg2i == 0) { 6994 ret = (arg1->floatval < arg2->floatval); 6995 } else { 6996 ret = 0; 6997 } 6998 } 6999 else if (inf && !strict) { 7000 if (arg1i == -1 || arg2i == 1) { 7001 ret = 1; 7002 } else if (arg1i == 0 && arg2i == 0) { 7003 ret = (arg1->floatval <= arg2->floatval); 7004 } else { 7005 ret = 0; 7006 } 7007 } 7008 else if (!inf && strict) { 7009 if ((arg1i == 1 && arg2i != 1) || 7010 (arg2i == -1 && arg1i != -1)) { 7011 ret = 1; 7012 } else if (arg1i == 0 && arg2i == 0) { 7013 ret = (arg1->floatval > arg2->floatval); 7014 } else { 7015 ret = 0; 7016 } 7017 } 7018 else if (!inf && !strict) { 7019 if (arg1i == 1 || arg2i == -1) { 7020 ret = 1; 7021 } else if (arg1i == 0 && arg2i == 0) { 7022 ret = (arg1->floatval >= arg2->floatval); 7023 } else { 7024 ret = 0; 7025 } 7026 } 7027 } 7028 xmlXPathReleaseObject(ctxt->context, arg1); 7029 xmlXPathReleaseObject(ctxt->context, arg2); 7030 return(ret); 7031} 7032 7033/** 7034 * xmlXPathValueFlipSign: 7035 * @ctxt: the XPath Parser context 7036 * 7037 * Implement the unary - operation on an XPath object 7038 * The numeric operators convert their operands to numbers as if 7039 * by calling the number function. 7040 */ 7041void 7042xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 7043 if ((ctxt == NULL) || (ctxt->context == NULL)) return; 7044 CAST_TO_NUMBER; 7045 CHECK_TYPE(XPATH_NUMBER); 7046 if (xmlXPathIsNaN(ctxt->value->floatval)) 7047 ctxt->value->floatval=xmlXPathNAN; 7048 else if (xmlXPathIsInf(ctxt->value->floatval) == 1) 7049 ctxt->value->floatval=xmlXPathNINF; 7050 else if (xmlXPathIsInf(ctxt->value->floatval) == -1) 7051 ctxt->value->floatval=xmlXPathPINF; 7052 else if (ctxt->value->floatval == 0) { 7053 if (xmlXPathGetSign(ctxt->value->floatval) == 0) 7054 ctxt->value->floatval = xmlXPathNZERO; 7055 else 7056 ctxt->value->floatval = 0; 7057 } 7058 else 7059 ctxt->value->floatval = - ctxt->value->floatval; 7060} 7061 7062/** 7063 * xmlXPathAddValues: 7064 * @ctxt: the XPath Parser context 7065 * 7066 * Implement the add operation on XPath objects: 7067 * The numeric operators convert their operands to numbers as if 7068 * by calling the number function. 7069 */ 7070void 7071xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 7072 xmlXPathObjectPtr arg; 7073 double val; 7074 7075 arg = valuePop(ctxt); 7076 if (arg == NULL) 7077 XP_ERROR(XPATH_INVALID_OPERAND); 7078 val = xmlXPathCastToNumber(arg); 7079 xmlXPathReleaseObject(ctxt->context, arg); 7080 CAST_TO_NUMBER; 7081 CHECK_TYPE(XPATH_NUMBER); 7082 ctxt->value->floatval += val; 7083} 7084 7085/** 7086 * xmlXPathSubValues: 7087 * @ctxt: the XPath Parser context 7088 * 7089 * Implement the subtraction operation on XPath objects: 7090 * The numeric operators convert their operands to numbers as if 7091 * by calling the number function. 7092 */ 7093void 7094xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 7095 xmlXPathObjectPtr arg; 7096 double val; 7097 7098 arg = valuePop(ctxt); 7099 if (arg == NULL) 7100 XP_ERROR(XPATH_INVALID_OPERAND); 7101 val = xmlXPathCastToNumber(arg); 7102 xmlXPathReleaseObject(ctxt->context, arg); 7103 CAST_TO_NUMBER; 7104 CHECK_TYPE(XPATH_NUMBER); 7105 ctxt->value->floatval -= val; 7106} 7107 7108/** 7109 * xmlXPathMultValues: 7110 * @ctxt: the XPath Parser context 7111 * 7112 * Implement the multiply operation on XPath objects: 7113 * The numeric operators convert their operands to numbers as if 7114 * by calling the number function. 7115 */ 7116void 7117xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 7118 xmlXPathObjectPtr arg; 7119 double val; 7120 7121 arg = valuePop(ctxt); 7122 if (arg == NULL) 7123 XP_ERROR(XPATH_INVALID_OPERAND); 7124 val = xmlXPathCastToNumber(arg); 7125 xmlXPathReleaseObject(ctxt->context, arg); 7126 CAST_TO_NUMBER; 7127 CHECK_TYPE(XPATH_NUMBER); 7128 ctxt->value->floatval *= val; 7129} 7130 7131/** 7132 * xmlXPathDivValues: 7133 * @ctxt: the XPath Parser context 7134 * 7135 * Implement the div operation on XPath objects @arg1 / @arg2: 7136 * The numeric operators convert their operands to numbers as if 7137 * by calling the number function. 7138 */ 7139void 7140xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 7141 xmlXPathObjectPtr arg; 7142 double val; 7143 7144 arg = valuePop(ctxt); 7145 if (arg == NULL) 7146 XP_ERROR(XPATH_INVALID_OPERAND); 7147 val = xmlXPathCastToNumber(arg); 7148 xmlXPathReleaseObject(ctxt->context, arg); 7149 CAST_TO_NUMBER; 7150 CHECK_TYPE(XPATH_NUMBER); 7151 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) 7152 ctxt->value->floatval = xmlXPathNAN; 7153 else if (val == 0 && xmlXPathGetSign(val) != 0) { 7154 if (ctxt->value->floatval == 0) 7155 ctxt->value->floatval = xmlXPathNAN; 7156 else if (ctxt->value->floatval > 0) 7157 ctxt->value->floatval = xmlXPathNINF; 7158 else if (ctxt->value->floatval < 0) 7159 ctxt->value->floatval = xmlXPathPINF; 7160 } 7161 else if (val == 0) { 7162 if (ctxt->value->floatval == 0) 7163 ctxt->value->floatval = xmlXPathNAN; 7164 else if (ctxt->value->floatval > 0) 7165 ctxt->value->floatval = xmlXPathPINF; 7166 else if (ctxt->value->floatval < 0) 7167 ctxt->value->floatval = xmlXPathNINF; 7168 } else 7169 ctxt->value->floatval /= val; 7170} 7171 7172/** 7173 * xmlXPathModValues: 7174 * @ctxt: the XPath Parser context 7175 * 7176 * Implement the mod operation on XPath objects: @arg1 / @arg2 7177 * The numeric operators convert their operands to numbers as if 7178 * by calling the number function. 7179 */ 7180void 7181xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 7182 xmlXPathObjectPtr arg; 7183 double arg1, arg2; 7184 7185 arg = valuePop(ctxt); 7186 if (arg == NULL) 7187 XP_ERROR(XPATH_INVALID_OPERAND); 7188 arg2 = xmlXPathCastToNumber(arg); 7189 xmlXPathReleaseObject(ctxt->context, arg); 7190 CAST_TO_NUMBER; 7191 CHECK_TYPE(XPATH_NUMBER); 7192 arg1 = ctxt->value->floatval; 7193 if (arg2 == 0) 7194 ctxt->value->floatval = xmlXPathNAN; 7195 else { 7196 ctxt->value->floatval = fmod(arg1, arg2); 7197 } 7198} 7199 7200/************************************************************************ 7201 * * 7202 * The traversal functions * 7203 * * 7204 ************************************************************************/ 7205 7206/* 7207 * A traversal function enumerates nodes along an axis. 7208 * Initially it must be called with NULL, and it indicates 7209 * termination on the axis by returning NULL. 7210 */ 7211typedef xmlNodePtr (*xmlXPathTraversalFunction) 7212 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 7213 7214/* 7215 * xmlXPathTraversalFunctionExt: 7216 * A traversal function enumerates nodes along an axis. 7217 * Initially it must be called with NULL, and it indicates 7218 * termination on the axis by returning NULL. 7219 * The context node of the traversal is specified via @contextNode. 7220 */ 7221typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) 7222 (xmlNodePtr cur, xmlNodePtr contextNode); 7223 7224 7225/** 7226 * xmlXPathNextSelf: 7227 * @ctxt: the XPath Parser context 7228 * @cur: the current node in the traversal 7229 * 7230 * Traversal function for the "self" direction 7231 * The self axis contains just the context node itself 7232 * 7233 * Returns the next element following that axis 7234 */ 7235xmlNodePtr 7236xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7237 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7238 if (cur == NULL) 7239 return(ctxt->context->node); 7240 return(NULL); 7241} 7242 7243/** 7244 * xmlXPathNextChild: 7245 * @ctxt: the XPath Parser context 7246 * @cur: the current node in the traversal 7247 * 7248 * Traversal function for the "child" direction 7249 * The child axis contains the children of the context node in document order. 7250 * 7251 * Returns the next element following that axis 7252 */ 7253xmlNodePtr 7254xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7255 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7256 if (cur == NULL) { 7257 if (ctxt->context->node == NULL) return(NULL); 7258 switch (ctxt->context->node->type) { 7259 case XML_ELEMENT_NODE: 7260 case XML_TEXT_NODE: 7261 case XML_CDATA_SECTION_NODE: 7262 case XML_ENTITY_REF_NODE: 7263 case XML_ENTITY_NODE: 7264 case XML_PI_NODE: 7265 case XML_COMMENT_NODE: 7266 case XML_NOTATION_NODE: 7267 case XML_DTD_NODE: 7268 return(ctxt->context->node->children); 7269 case XML_DOCUMENT_NODE: 7270 case XML_DOCUMENT_TYPE_NODE: 7271 case XML_DOCUMENT_FRAG_NODE: 7272 case XML_HTML_DOCUMENT_NODE: 7273#ifdef LIBXML_DOCB_ENABLED 7274 case XML_DOCB_DOCUMENT_NODE: 7275#endif 7276 return(((xmlDocPtr) ctxt->context->node)->children); 7277 case XML_ELEMENT_DECL: 7278 case XML_ATTRIBUTE_DECL: 7279 case XML_ENTITY_DECL: 7280 case XML_ATTRIBUTE_NODE: 7281 case XML_NAMESPACE_DECL: 7282 case XML_XINCLUDE_START: 7283 case XML_XINCLUDE_END: 7284 return(NULL); 7285 } 7286 return(NULL); 7287 } 7288 if ((cur->type == XML_DOCUMENT_NODE) || 7289 (cur->type == XML_HTML_DOCUMENT_NODE)) 7290 return(NULL); 7291 return(cur->next); 7292} 7293 7294/** 7295 * xmlXPathNextChildElement: 7296 * @ctxt: the XPath Parser context 7297 * @cur: the current node in the traversal 7298 * 7299 * Traversal function for the "child" direction and nodes of type element. 7300 * The child axis contains the children of the context node in document order. 7301 * 7302 * Returns the next element following that axis 7303 */ 7304static xmlNodePtr 7305xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7306 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7307 if (cur == NULL) { 7308 cur = ctxt->context->node; 7309 if (cur == NULL) return(NULL); 7310 /* 7311 * Get the first element child. 7312 */ 7313 switch (cur->type) { 7314 case XML_ELEMENT_NODE: 7315 case XML_DOCUMENT_FRAG_NODE: 7316 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ 7317 case XML_ENTITY_NODE: 7318 cur = cur->children; 7319 if (cur != NULL) { 7320 if (cur->type == XML_ELEMENT_NODE) 7321 return(cur); 7322 do { 7323 cur = cur->next; 7324 } while ((cur != NULL) && 7325 (cur->type != XML_ELEMENT_NODE)); 7326 return(cur); 7327 } 7328 return(NULL); 7329 case XML_DOCUMENT_NODE: 7330 case XML_HTML_DOCUMENT_NODE: 7331#ifdef LIBXML_DOCB_ENABLED 7332 case XML_DOCB_DOCUMENT_NODE: 7333#endif 7334 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7335 default: 7336 return(NULL); 7337 } 7338 return(NULL); 7339 } 7340 /* 7341 * Get the next sibling element node. 7342 */ 7343 switch (cur->type) { 7344 case XML_ELEMENT_NODE: 7345 case XML_TEXT_NODE: 7346 case XML_ENTITY_REF_NODE: 7347 case XML_ENTITY_NODE: 7348 case XML_CDATA_SECTION_NODE: 7349 case XML_PI_NODE: 7350 case XML_COMMENT_NODE: 7351 case XML_XINCLUDE_END: 7352 break; 7353 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ 7354 default: 7355 return(NULL); 7356 } 7357 if (cur->next != NULL) { 7358 if (cur->next->type == XML_ELEMENT_NODE) 7359 return(cur->next); 7360 cur = cur->next; 7361 do { 7362 cur = cur->next; 7363 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); 7364 return(cur); 7365 } 7366 return(NULL); 7367} 7368 7369/** 7370 * xmlXPathNextDescendantOrSelfElemParent: 7371 * @ctxt: the XPath Parser context 7372 * @cur: the current node in the traversal 7373 * 7374 * Traversal function for the "descendant-or-self" axis. 7375 * Additionally it returns only nodes which can be parents of 7376 * element nodes. 7377 * 7378 * 7379 * Returns the next element following that axis 7380 */ 7381static xmlNodePtr 7382xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, 7383 xmlNodePtr contextNode) 7384{ 7385 if (cur == NULL) { 7386 if (contextNode == NULL) 7387 return(NULL); 7388 switch (contextNode->type) { 7389 case XML_ELEMENT_NODE: 7390 case XML_XINCLUDE_START: 7391 case XML_DOCUMENT_FRAG_NODE: 7392 case XML_DOCUMENT_NODE: 7393#ifdef LIBXML_DOCB_ENABLED 7394 case XML_DOCB_DOCUMENT_NODE: 7395#endif 7396 case XML_HTML_DOCUMENT_NODE: 7397 return(contextNode); 7398 default: 7399 return(NULL); 7400 } 7401 return(NULL); 7402 } else { 7403 xmlNodePtr start = cur; 7404 7405 while (cur != NULL) { 7406 switch (cur->type) { 7407 case XML_ELEMENT_NODE: 7408 /* TODO: OK to have XInclude here? */ 7409 case XML_XINCLUDE_START: 7410 case XML_DOCUMENT_FRAG_NODE: 7411 if (cur != start) 7412 return(cur); 7413 if (cur->children != NULL) { 7414 cur = cur->children; 7415 continue; 7416 } 7417 break; 7418#ifdef LIBXML_DOCB_ENABLED 7419 /* Not sure if we need those here. */ 7420 case XML_DOCUMENT_NODE: 7421 case XML_DOCB_DOCUMENT_NODE: 7422#endif 7423 case XML_HTML_DOCUMENT_NODE: 7424 if (cur != start) 7425 return(cur); 7426 return(xmlDocGetRootElement((xmlDocPtr) cur)); 7427 default: 7428 break; 7429 } 7430 7431next_sibling: 7432 if ((cur == NULL) || (cur == contextNode)) 7433 return(NULL); 7434 if (cur->next != NULL) { 7435 cur = cur->next; 7436 } else { 7437 cur = cur->parent; 7438 goto next_sibling; 7439 } 7440 } 7441 } 7442 return(NULL); 7443} 7444 7445/** 7446 * xmlXPathNextDescendant: 7447 * @ctxt: the XPath Parser context 7448 * @cur: the current node in the traversal 7449 * 7450 * Traversal function for the "descendant" direction 7451 * the descendant axis contains the descendants of the context node in document 7452 * order; a descendant is a child or a child of a child and so on. 7453 * 7454 * Returns the next element following that axis 7455 */ 7456xmlNodePtr 7457xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7458 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7459 if (cur == NULL) { 7460 if (ctxt->context->node == NULL) 7461 return(NULL); 7462 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7463 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7464 return(NULL); 7465 7466 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 7467 return(ctxt->context->doc->children); 7468 return(ctxt->context->node->children); 7469 } 7470 7471 if (cur->children != NULL) { 7472 /* 7473 * Do not descend on entities declarations 7474 */ 7475 if (cur->children->type != XML_ENTITY_DECL) { 7476 cur = cur->children; 7477 /* 7478 * Skip DTDs 7479 */ 7480 if (cur->type != XML_DTD_NODE) 7481 return(cur); 7482 } 7483 } 7484 7485 if (cur == ctxt->context->node) return(NULL); 7486 7487 while (cur->next != NULL) { 7488 cur = cur->next; 7489 if ((cur->type != XML_ENTITY_DECL) && 7490 (cur->type != XML_DTD_NODE)) 7491 return(cur); 7492 } 7493 7494 do { 7495 cur = cur->parent; 7496 if (cur == NULL) break; 7497 if (cur == ctxt->context->node) return(NULL); 7498 if (cur->next != NULL) { 7499 cur = cur->next; 7500 return(cur); 7501 } 7502 } while (cur != NULL); 7503 return(cur); 7504} 7505 7506/** 7507 * xmlXPathNextDescendantOrSelf: 7508 * @ctxt: the XPath Parser context 7509 * @cur: the current node in the traversal 7510 * 7511 * Traversal function for the "descendant-or-self" direction 7512 * the descendant-or-self axis contains the context node and the descendants 7513 * of the context node in document order; thus the context node is the first 7514 * node on the axis, and the first child of the context node is the second node 7515 * on the axis 7516 * 7517 * Returns the next element following that axis 7518 */ 7519xmlNodePtr 7520xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7521 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7522 if (cur == NULL) { 7523 if (ctxt->context->node == NULL) 7524 return(NULL); 7525 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7526 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7527 return(NULL); 7528 return(ctxt->context->node); 7529 } 7530 7531 return(xmlXPathNextDescendant(ctxt, cur)); 7532} 7533 7534/** 7535 * xmlXPathNextParent: 7536 * @ctxt: the XPath Parser context 7537 * @cur: the current node in the traversal 7538 * 7539 * Traversal function for the "parent" direction 7540 * The parent axis contains the parent of the context node, if there is one. 7541 * 7542 * Returns the next element following that axis 7543 */ 7544xmlNodePtr 7545xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7546 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7547 /* 7548 * the parent of an attribute or namespace node is the element 7549 * to which the attribute or namespace node is attached 7550 * Namespace handling !!! 7551 */ 7552 if (cur == NULL) { 7553 if (ctxt->context->node == NULL) return(NULL); 7554 switch (ctxt->context->node->type) { 7555 case XML_ELEMENT_NODE: 7556 case XML_TEXT_NODE: 7557 case XML_CDATA_SECTION_NODE: 7558 case XML_ENTITY_REF_NODE: 7559 case XML_ENTITY_NODE: 7560 case XML_PI_NODE: 7561 case XML_COMMENT_NODE: 7562 case XML_NOTATION_NODE: 7563 case XML_DTD_NODE: 7564 case XML_ELEMENT_DECL: 7565 case XML_ATTRIBUTE_DECL: 7566 case XML_XINCLUDE_START: 7567 case XML_XINCLUDE_END: 7568 case XML_ENTITY_DECL: 7569 if (ctxt->context->node->parent == NULL) 7570 return((xmlNodePtr) ctxt->context->doc); 7571 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7572 ((ctxt->context->node->parent->name[0] == ' ') || 7573 (xmlStrEqual(ctxt->context->node->parent->name, 7574 BAD_CAST "fake node libxslt")))) 7575 return(NULL); 7576 return(ctxt->context->node->parent); 7577 case XML_ATTRIBUTE_NODE: { 7578 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7579 7580 return(att->parent); 7581 } 7582 case XML_DOCUMENT_NODE: 7583 case XML_DOCUMENT_TYPE_NODE: 7584 case XML_DOCUMENT_FRAG_NODE: 7585 case XML_HTML_DOCUMENT_NODE: 7586#ifdef LIBXML_DOCB_ENABLED 7587 case XML_DOCB_DOCUMENT_NODE: 7588#endif 7589 return(NULL); 7590 case XML_NAMESPACE_DECL: { 7591 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7592 7593 if ((ns->next != NULL) && 7594 (ns->next->type != XML_NAMESPACE_DECL)) 7595 return((xmlNodePtr) ns->next); 7596 return(NULL); 7597 } 7598 } 7599 } 7600 return(NULL); 7601} 7602 7603/** 7604 * xmlXPathNextAncestor: 7605 * @ctxt: the XPath Parser context 7606 * @cur: the current node in the traversal 7607 * 7608 * Traversal function for the "ancestor" direction 7609 * the ancestor axis contains the ancestors of the context node; the ancestors 7610 * of the context node consist of the parent of context node and the parent's 7611 * parent and so on; the nodes are ordered in reverse document order; thus the 7612 * parent is the first node on the axis, and the parent's parent is the second 7613 * node on the axis 7614 * 7615 * Returns the next element following that axis 7616 */ 7617xmlNodePtr 7618xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7619 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7620 /* 7621 * the parent of an attribute or namespace node is the element 7622 * to which the attribute or namespace node is attached 7623 * !!!!!!!!!!!!! 7624 */ 7625 if (cur == NULL) { 7626 if (ctxt->context->node == NULL) return(NULL); 7627 switch (ctxt->context->node->type) { 7628 case XML_ELEMENT_NODE: 7629 case XML_TEXT_NODE: 7630 case XML_CDATA_SECTION_NODE: 7631 case XML_ENTITY_REF_NODE: 7632 case XML_ENTITY_NODE: 7633 case XML_PI_NODE: 7634 case XML_COMMENT_NODE: 7635 case XML_DTD_NODE: 7636 case XML_ELEMENT_DECL: 7637 case XML_ATTRIBUTE_DECL: 7638 case XML_ENTITY_DECL: 7639 case XML_NOTATION_NODE: 7640 case XML_XINCLUDE_START: 7641 case XML_XINCLUDE_END: 7642 if (ctxt->context->node->parent == NULL) 7643 return((xmlNodePtr) ctxt->context->doc); 7644 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && 7645 ((ctxt->context->node->parent->name[0] == ' ') || 7646 (xmlStrEqual(ctxt->context->node->parent->name, 7647 BAD_CAST "fake node libxslt")))) 7648 return(NULL); 7649 return(ctxt->context->node->parent); 7650 case XML_ATTRIBUTE_NODE: { 7651 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 7652 7653 return(tmp->parent); 7654 } 7655 case XML_DOCUMENT_NODE: 7656 case XML_DOCUMENT_TYPE_NODE: 7657 case XML_DOCUMENT_FRAG_NODE: 7658 case XML_HTML_DOCUMENT_NODE: 7659#ifdef LIBXML_DOCB_ENABLED 7660 case XML_DOCB_DOCUMENT_NODE: 7661#endif 7662 return(NULL); 7663 case XML_NAMESPACE_DECL: { 7664 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7665 7666 if ((ns->next != NULL) && 7667 (ns->next->type != XML_NAMESPACE_DECL)) 7668 return((xmlNodePtr) ns->next); 7669 /* Bad, how did that namespace end up here ? */ 7670 return(NULL); 7671 } 7672 } 7673 return(NULL); 7674 } 7675 if (cur == ctxt->context->doc->children) 7676 return((xmlNodePtr) ctxt->context->doc); 7677 if (cur == (xmlNodePtr) ctxt->context->doc) 7678 return(NULL); 7679 switch (cur->type) { 7680 case XML_ELEMENT_NODE: 7681 case XML_TEXT_NODE: 7682 case XML_CDATA_SECTION_NODE: 7683 case XML_ENTITY_REF_NODE: 7684 case XML_ENTITY_NODE: 7685 case XML_PI_NODE: 7686 case XML_COMMENT_NODE: 7687 case XML_NOTATION_NODE: 7688 case XML_DTD_NODE: 7689 case XML_ELEMENT_DECL: 7690 case XML_ATTRIBUTE_DECL: 7691 case XML_ENTITY_DECL: 7692 case XML_XINCLUDE_START: 7693 case XML_XINCLUDE_END: 7694 if (cur->parent == NULL) 7695 return(NULL); 7696 if ((cur->parent->type == XML_ELEMENT_NODE) && 7697 ((cur->parent->name[0] == ' ') || 7698 (xmlStrEqual(cur->parent->name, 7699 BAD_CAST "fake node libxslt")))) 7700 return(NULL); 7701 return(cur->parent); 7702 case XML_ATTRIBUTE_NODE: { 7703 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 7704 7705 return(att->parent); 7706 } 7707 case XML_NAMESPACE_DECL: { 7708 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 7709 7710 if ((ns->next != NULL) && 7711 (ns->next->type != XML_NAMESPACE_DECL)) 7712 return((xmlNodePtr) ns->next); 7713 /* Bad, how did that namespace end up here ? */ 7714 return(NULL); 7715 } 7716 case XML_DOCUMENT_NODE: 7717 case XML_DOCUMENT_TYPE_NODE: 7718 case XML_DOCUMENT_FRAG_NODE: 7719 case XML_HTML_DOCUMENT_NODE: 7720#ifdef LIBXML_DOCB_ENABLED 7721 case XML_DOCB_DOCUMENT_NODE: 7722#endif 7723 return(NULL); 7724 } 7725 return(NULL); 7726} 7727 7728/** 7729 * xmlXPathNextAncestorOrSelf: 7730 * @ctxt: the XPath Parser context 7731 * @cur: the current node in the traversal 7732 * 7733 * Traversal function for the "ancestor-or-self" direction 7734 * he ancestor-or-self axis contains the context node and ancestors of 7735 * the context node in reverse document order; thus the context node is 7736 * the first node on the axis, and the context node's parent the second; 7737 * parent here is defined the same as with the parent axis. 7738 * 7739 * Returns the next element following that axis 7740 */ 7741xmlNodePtr 7742xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7743 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7744 if (cur == NULL) 7745 return(ctxt->context->node); 7746 return(xmlXPathNextAncestor(ctxt, cur)); 7747} 7748 7749/** 7750 * xmlXPathNextFollowingSibling: 7751 * @ctxt: the XPath Parser context 7752 * @cur: the current node in the traversal 7753 * 7754 * Traversal function for the "following-sibling" direction 7755 * The following-sibling axis contains the following siblings of the context 7756 * node in document order. 7757 * 7758 * Returns the next element following that axis 7759 */ 7760xmlNodePtr 7761xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7762 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7763 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7764 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7765 return(NULL); 7766 if (cur == (xmlNodePtr) ctxt->context->doc) 7767 return(NULL); 7768 if (cur == NULL) 7769 return(ctxt->context->node->next); 7770 return(cur->next); 7771} 7772 7773/** 7774 * xmlXPathNextPrecedingSibling: 7775 * @ctxt: the XPath Parser context 7776 * @cur: the current node in the traversal 7777 * 7778 * Traversal function for the "preceding-sibling" direction 7779 * The preceding-sibling axis contains the preceding siblings of the context 7780 * node in reverse document order; the first preceding sibling is first on the 7781 * axis; the sibling preceding that node is the second on the axis and so on. 7782 * 7783 * Returns the next element following that axis 7784 */ 7785xmlNodePtr 7786xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7787 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7788 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 7789 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 7790 return(NULL); 7791 if (cur == (xmlNodePtr) ctxt->context->doc) 7792 return(NULL); 7793 if (cur == NULL) 7794 return(ctxt->context->node->prev); 7795 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 7796 cur = cur->prev; 7797 if (cur == NULL) 7798 return(ctxt->context->node->prev); 7799 } 7800 return(cur->prev); 7801} 7802 7803/** 7804 * xmlXPathNextFollowing: 7805 * @ctxt: the XPath Parser context 7806 * @cur: the current node in the traversal 7807 * 7808 * Traversal function for the "following" direction 7809 * The following axis contains all nodes in the same document as the context 7810 * node that are after the context node in document order, excluding any 7811 * descendants and excluding attribute nodes and namespace nodes; the nodes 7812 * are ordered in document order 7813 * 7814 * Returns the next element following that axis 7815 */ 7816xmlNodePtr 7817xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7818 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7819 if (cur != NULL && cur->children != NULL) 7820 return cur->children ; 7821 if (cur == NULL) cur = ctxt->context->node; 7822 if (cur == NULL) return(NULL) ; /* ERROR */ 7823 if (cur->next != NULL) return(cur->next) ; 7824 do { 7825 cur = cur->parent; 7826 if (cur == NULL) break; 7827 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 7828 if (cur->next != NULL) return(cur->next); 7829 } while (cur != NULL); 7830 return(cur); 7831} 7832 7833/* 7834 * xmlXPathIsAncestor: 7835 * @ancestor: the ancestor node 7836 * @node: the current node 7837 * 7838 * Check that @ancestor is a @node's ancestor 7839 * 7840 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 7841 */ 7842static int 7843xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 7844 if ((ancestor == NULL) || (node == NULL)) return(0); 7845 /* nodes need to be in the same document */ 7846 if (ancestor->doc != node->doc) return(0); 7847 /* avoid searching if ancestor or node is the root node */ 7848 if (ancestor == (xmlNodePtr) node->doc) return(1); 7849 if (node == (xmlNodePtr) ancestor->doc) return(0); 7850 while (node->parent != NULL) { 7851 if (node->parent == ancestor) 7852 return(1); 7853 node = node->parent; 7854 } 7855 return(0); 7856} 7857 7858/** 7859 * xmlXPathNextPreceding: 7860 * @ctxt: the XPath Parser context 7861 * @cur: the current node in the traversal 7862 * 7863 * Traversal function for the "preceding" direction 7864 * the preceding axis contains all nodes in the same document as the context 7865 * node that are before the context node in document order, excluding any 7866 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 7867 * ordered in reverse document order 7868 * 7869 * Returns the next element following that axis 7870 */ 7871xmlNodePtr 7872xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 7873{ 7874 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7875 if (cur == NULL) 7876 cur = ctxt->context->node; 7877 if (cur == NULL) 7878 return (NULL); 7879 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 7880 cur = cur->prev; 7881 do { 7882 if (cur->prev != NULL) { 7883 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 7884 return (cur); 7885 } 7886 7887 cur = cur->parent; 7888 if (cur == NULL) 7889 return (NULL); 7890 if (cur == ctxt->context->doc->children) 7891 return (NULL); 7892 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 7893 return (cur); 7894} 7895 7896/** 7897 * xmlXPathNextPrecedingInternal: 7898 * @ctxt: the XPath Parser context 7899 * @cur: the current node in the traversal 7900 * 7901 * Traversal function for the "preceding" direction 7902 * the preceding axis contains all nodes in the same document as the context 7903 * node that are before the context node in document order, excluding any 7904 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 7905 * ordered in reverse document order 7906 * This is a faster implementation but internal only since it requires a 7907 * state kept in the parser context: ctxt->ancestor. 7908 * 7909 * Returns the next element following that axis 7910 */ 7911static xmlNodePtr 7912xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 7913 xmlNodePtr cur) 7914{ 7915 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7916 if (cur == NULL) { 7917 cur = ctxt->context->node; 7918 if (cur == NULL) 7919 return (NULL); 7920 if (cur->type == XML_NAMESPACE_DECL) 7921 cur = (xmlNodePtr)((xmlNsPtr)cur)->next; 7922 ctxt->ancestor = cur->parent; 7923 } 7924 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 7925 cur = cur->prev; 7926 while (cur->prev == NULL) { 7927 cur = cur->parent; 7928 if (cur == NULL) 7929 return (NULL); 7930 if (cur == ctxt->context->doc->children) 7931 return (NULL); 7932 if (cur != ctxt->ancestor) 7933 return (cur); 7934 ctxt->ancestor = cur->parent; 7935 } 7936 cur = cur->prev; 7937 while (cur->last != NULL) 7938 cur = cur->last; 7939 return (cur); 7940} 7941 7942/** 7943 * xmlXPathNextNamespace: 7944 * @ctxt: the XPath Parser context 7945 * @cur: the current attribute in the traversal 7946 * 7947 * Traversal function for the "namespace" direction 7948 * the namespace axis contains the namespace nodes of the context node; 7949 * the order of nodes on this axis is implementation-defined; the axis will 7950 * be empty unless the context node is an element 7951 * 7952 * We keep the XML namespace node at the end of the list. 7953 * 7954 * Returns the next element following that axis 7955 */ 7956xmlNodePtr 7957xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7958 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7959 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 7960 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) { 7961 if (ctxt->context->tmpNsList != NULL) 7962 xmlFree(ctxt->context->tmpNsList); 7963 ctxt->context->tmpNsList = 7964 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 7965 ctxt->context->tmpNsNr = 0; 7966 if (ctxt->context->tmpNsList != NULL) { 7967 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { 7968 ctxt->context->tmpNsNr++; 7969 } 7970 } 7971 return((xmlNodePtr) xmlXPathXMLNamespace); 7972 } 7973 if (ctxt->context->tmpNsNr > 0) { 7974 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; 7975 } else { 7976 if (ctxt->context->tmpNsList != NULL) 7977 xmlFree(ctxt->context->tmpNsList); 7978 ctxt->context->tmpNsList = NULL; 7979 return(NULL); 7980 } 7981} 7982 7983/** 7984 * xmlXPathNextAttribute: 7985 * @ctxt: the XPath Parser context 7986 * @cur: the current attribute in the traversal 7987 * 7988 * Traversal function for the "attribute" direction 7989 * TODO: support DTD inherited default attributes 7990 * 7991 * Returns the next element following that axis 7992 */ 7993xmlNodePtr 7994xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 7995 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); 7996 if (ctxt->context->node == NULL) 7997 return(NULL); 7998 if (ctxt->context->node->type != XML_ELEMENT_NODE) 7999 return(NULL); 8000 if (cur == NULL) { 8001 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 8002 return(NULL); 8003 return((xmlNodePtr)ctxt->context->node->properties); 8004 } 8005 return((xmlNodePtr)cur->next); 8006} 8007 8008/************************************************************************ 8009 * * 8010 * NodeTest Functions * 8011 * * 8012 ************************************************************************/ 8013 8014#define IS_FUNCTION 200 8015 8016 8017/************************************************************************ 8018 * * 8019 * Implicit tree core function library * 8020 * * 8021 ************************************************************************/ 8022 8023/** 8024 * xmlXPathRoot: 8025 * @ctxt: the XPath Parser context 8026 * 8027 * Initialize the context to the root of the document 8028 */ 8029void 8030xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 8031 if ((ctxt == NULL) || (ctxt->context == NULL)) 8032 return; 8033 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 8034 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8035 ctxt->context->node)); 8036} 8037 8038/************************************************************************ 8039 * * 8040 * The explicit core function library * 8041 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 8042 * * 8043 ************************************************************************/ 8044 8045 8046/** 8047 * xmlXPathLastFunction: 8048 * @ctxt: the XPath Parser context 8049 * @nargs: the number of arguments 8050 * 8051 * Implement the last() XPath function 8052 * number last() 8053 * The last function returns the number of nodes in the context node list. 8054 */ 8055void 8056xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8057 CHECK_ARITY(0); 8058 if (ctxt->context->contextSize >= 0) { 8059 valuePush(ctxt, 8060 xmlXPathCacheNewFloat(ctxt->context, 8061 (double) ctxt->context->contextSize)); 8062#ifdef DEBUG_EXPR 8063 xmlGenericError(xmlGenericErrorContext, 8064 "last() : %d\n", ctxt->context->contextSize); 8065#endif 8066 } else { 8067 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 8068 } 8069} 8070 8071/** 8072 * xmlXPathPositionFunction: 8073 * @ctxt: the XPath Parser context 8074 * @nargs: the number of arguments 8075 * 8076 * Implement the position() XPath function 8077 * number position() 8078 * The position function returns the position of the context node in the 8079 * context node list. The first position is 1, and so the last position 8080 * will be equal to last(). 8081 */ 8082void 8083xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8084 CHECK_ARITY(0); 8085 if (ctxt->context->proximityPosition >= 0) { 8086 valuePush(ctxt, 8087 xmlXPathCacheNewFloat(ctxt->context, 8088 (double) ctxt->context->proximityPosition)); 8089#ifdef DEBUG_EXPR 8090 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 8091 ctxt->context->proximityPosition); 8092#endif 8093 } else { 8094 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 8095 } 8096} 8097 8098/** 8099 * xmlXPathCountFunction: 8100 * @ctxt: the XPath Parser context 8101 * @nargs: the number of arguments 8102 * 8103 * Implement the count() XPath function 8104 * number count(node-set) 8105 */ 8106void 8107xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8108 xmlXPathObjectPtr cur; 8109 8110 CHECK_ARITY(1); 8111 if ((ctxt->value == NULL) || 8112 ((ctxt->value->type != XPATH_NODESET) && 8113 (ctxt->value->type != XPATH_XSLT_TREE))) 8114 XP_ERROR(XPATH_INVALID_TYPE); 8115 cur = valuePop(ctxt); 8116 8117 if ((cur == NULL) || (cur->nodesetval == NULL)) 8118 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8119 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { 8120 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8121 (double) cur->nodesetval->nodeNr)); 8122 } else { 8123 if ((cur->nodesetval->nodeNr != 1) || 8124 (cur->nodesetval->nodeTab == NULL)) { 8125 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); 8126 } else { 8127 xmlNodePtr tmp; 8128 int i = 0; 8129 8130 tmp = cur->nodesetval->nodeTab[0]; 8131 if (tmp != NULL) { 8132 tmp = tmp->children; 8133 while (tmp != NULL) { 8134 tmp = tmp->next; 8135 i++; 8136 } 8137 } 8138 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); 8139 } 8140 } 8141 xmlXPathReleaseObject(ctxt->context, cur); 8142} 8143 8144/** 8145 * xmlXPathGetElementsByIds: 8146 * @doc: the document 8147 * @ids: a whitespace separated list of IDs 8148 * 8149 * Selects elements by their unique ID. 8150 * 8151 * Returns a node-set of selected elements. 8152 */ 8153static xmlNodeSetPtr 8154xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 8155 xmlNodeSetPtr ret; 8156 const xmlChar *cur = ids; 8157 xmlChar *ID; 8158 xmlAttrPtr attr; 8159 xmlNodePtr elem = NULL; 8160 8161 if (ids == NULL) return(NULL); 8162 8163 ret = xmlXPathNodeSetCreate(NULL); 8164 8165 while (IS_BLANK_CH(*cur)) cur++; 8166 while (*cur != 0) { 8167 while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) 8168 cur++; 8169 8170 ID = xmlStrndup(ids, cur - ids); 8171 if (ID != NULL) { 8172 /* 8173 * We used to check the fact that the value passed 8174 * was an NCName, but this generated much troubles for 8175 * me and Aleksey Sanin, people blatantly violated that 8176 * constaint, like Visa3D spec. 8177 * if (xmlValidateNCName(ID, 1) == 0) 8178 */ 8179 attr = xmlGetID(doc, ID); 8180 if (attr != NULL) { 8181 if (attr->type == XML_ATTRIBUTE_NODE) 8182 elem = attr->parent; 8183 else if (attr->type == XML_ELEMENT_NODE) 8184 elem = (xmlNodePtr) attr; 8185 else 8186 elem = NULL; 8187 if (elem != NULL) 8188 xmlXPathNodeSetAdd(ret, elem); 8189 } 8190 xmlFree(ID); 8191 } 8192 8193 while (IS_BLANK_CH(*cur)) cur++; 8194 ids = cur; 8195 } 8196 return(ret); 8197} 8198 8199/** 8200 * xmlXPathIdFunction: 8201 * @ctxt: the XPath Parser context 8202 * @nargs: the number of arguments 8203 * 8204 * Implement the id() XPath function 8205 * node-set id(object) 8206 * The id function selects elements by their unique ID 8207 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 8208 * then the result is the union of the result of applying id to the 8209 * string value of each of the nodes in the argument node-set. When the 8210 * argument to id is of any other type, the argument is converted to a 8211 * string as if by a call to the string function; the string is split 8212 * into a whitespace-separated list of tokens (whitespace is any sequence 8213 * of characters matching the production S); the result is a node-set 8214 * containing the elements in the same document as the context node that 8215 * have a unique ID equal to any of the tokens in the list. 8216 */ 8217void 8218xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8219 xmlChar *tokens; 8220 xmlNodeSetPtr ret; 8221 xmlXPathObjectPtr obj; 8222 8223 CHECK_ARITY(1); 8224 obj = valuePop(ctxt); 8225 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8226 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 8227 xmlNodeSetPtr ns; 8228 int i; 8229 8230 ret = xmlXPathNodeSetCreate(NULL); 8231 8232 if (obj->nodesetval != NULL) { 8233 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 8234 tokens = 8235 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 8236 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 8237 ret = xmlXPathNodeSetMerge(ret, ns); 8238 xmlXPathFreeNodeSet(ns); 8239 if (tokens != NULL) 8240 xmlFree(tokens); 8241 } 8242 } 8243 xmlXPathReleaseObject(ctxt->context, obj); 8244 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8245 return; 8246 } 8247 obj = xmlXPathCacheConvertString(ctxt->context, obj); 8248 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 8249 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); 8250 xmlXPathReleaseObject(ctxt->context, obj); 8251 return; 8252} 8253 8254/** 8255 * xmlXPathLocalNameFunction: 8256 * @ctxt: the XPath Parser context 8257 * @nargs: the number of arguments 8258 * 8259 * Implement the local-name() XPath function 8260 * string local-name(node-set?) 8261 * The local-name function returns a string containing the local part 8262 * of the name of the node in the argument node-set that is first in 8263 * document order. If the node-set is empty or the first node has no 8264 * name, an empty string is returned. If the argument is omitted it 8265 * defaults to the context node. 8266 */ 8267void 8268xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8269 xmlXPathObjectPtr cur; 8270 8271 if (ctxt == NULL) return; 8272 8273 if (nargs == 0) { 8274 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8275 ctxt->context->node)); 8276 nargs = 1; 8277 } 8278 8279 CHECK_ARITY(1); 8280 if ((ctxt->value == NULL) || 8281 ((ctxt->value->type != XPATH_NODESET) && 8282 (ctxt->value->type != XPATH_XSLT_TREE))) 8283 XP_ERROR(XPATH_INVALID_TYPE); 8284 cur = valuePop(ctxt); 8285 8286 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8287 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8288 } else { 8289 int i = 0; /* Should be first in document order !!!!! */ 8290 switch (cur->nodesetval->nodeTab[i]->type) { 8291 case XML_ELEMENT_NODE: 8292 case XML_ATTRIBUTE_NODE: 8293 case XML_PI_NODE: 8294 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8295 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8296 else 8297 valuePush(ctxt, 8298 xmlXPathCacheNewString(ctxt->context, 8299 cur->nodesetval->nodeTab[i]->name)); 8300 break; 8301 case XML_NAMESPACE_DECL: 8302 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8303 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 8304 break; 8305 default: 8306 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8307 } 8308 } 8309 xmlXPathReleaseObject(ctxt->context, cur); 8310} 8311 8312/** 8313 * xmlXPathNamespaceURIFunction: 8314 * @ctxt: the XPath Parser context 8315 * @nargs: the number of arguments 8316 * 8317 * Implement the namespace-uri() XPath function 8318 * string namespace-uri(node-set?) 8319 * The namespace-uri function returns a string containing the 8320 * namespace URI of the expanded name of the node in the argument 8321 * node-set that is first in document order. If the node-set is empty, 8322 * the first node has no name, or the expanded name has no namespace 8323 * URI, an empty string is returned. If the argument is omitted it 8324 * defaults to the context node. 8325 */ 8326void 8327xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8328 xmlXPathObjectPtr cur; 8329 8330 if (ctxt == NULL) return; 8331 8332 if (nargs == 0) { 8333 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8334 ctxt->context->node)); 8335 nargs = 1; 8336 } 8337 CHECK_ARITY(1); 8338 if ((ctxt->value == NULL) || 8339 ((ctxt->value->type != XPATH_NODESET) && 8340 (ctxt->value->type != XPATH_XSLT_TREE))) 8341 XP_ERROR(XPATH_INVALID_TYPE); 8342 cur = valuePop(ctxt); 8343 8344 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8345 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8346 } else { 8347 int i = 0; /* Should be first in document order !!!!! */ 8348 switch (cur->nodesetval->nodeTab[i]->type) { 8349 case XML_ELEMENT_NODE: 8350 case XML_ATTRIBUTE_NODE: 8351 if (cur->nodesetval->nodeTab[i]->ns == NULL) 8352 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8353 else 8354 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8355 cur->nodesetval->nodeTab[i]->ns->href)); 8356 break; 8357 default: 8358 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8359 } 8360 } 8361 xmlXPathReleaseObject(ctxt->context, cur); 8362} 8363 8364/** 8365 * xmlXPathNameFunction: 8366 * @ctxt: the XPath Parser context 8367 * @nargs: the number of arguments 8368 * 8369 * Implement the name() XPath function 8370 * string name(node-set?) 8371 * The name function returns a string containing a QName representing 8372 * the name of the node in the argument node-set that is first in document 8373 * order. The QName must represent the name with respect to the namespace 8374 * declarations in effect on the node whose name is being represented. 8375 * Typically, this will be the form in which the name occurred in the XML 8376 * source. This need not be the case if there are namespace declarations 8377 * in effect on the node that associate multiple prefixes with the same 8378 * namespace. However, an implementation may include information about 8379 * the original prefix in its representation of nodes; in this case, an 8380 * implementation can ensure that the returned string is always the same 8381 * as the QName used in the XML source. If the argument it omitted it 8382 * defaults to the context node. 8383 * Libxml keep the original prefix so the "real qualified name" used is 8384 * returned. 8385 */ 8386static void 8387xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 8388{ 8389 xmlXPathObjectPtr cur; 8390 8391 if (nargs == 0) { 8392 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8393 ctxt->context->node)); 8394 nargs = 1; 8395 } 8396 8397 CHECK_ARITY(1); 8398 if ((ctxt->value == NULL) || 8399 ((ctxt->value->type != XPATH_NODESET) && 8400 (ctxt->value->type != XPATH_XSLT_TREE))) 8401 XP_ERROR(XPATH_INVALID_TYPE); 8402 cur = valuePop(ctxt); 8403 8404 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 8405 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8406 } else { 8407 int i = 0; /* Should be first in document order !!!!! */ 8408 8409 switch (cur->nodesetval->nodeTab[i]->type) { 8410 case XML_ELEMENT_NODE: 8411 case XML_ATTRIBUTE_NODE: 8412 if (cur->nodesetval->nodeTab[i]->name[0] == ' ') 8413 valuePush(ctxt, 8414 xmlXPathCacheNewCString(ctxt->context, "")); 8415 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 8416 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { 8417 valuePush(ctxt, 8418 xmlXPathCacheNewString(ctxt->context, 8419 cur->nodesetval->nodeTab[i]->name)); 8420 } else { 8421 xmlChar *fullname; 8422 8423 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, 8424 cur->nodesetval->nodeTab[i]->ns->prefix, 8425 NULL, 0); 8426 if (fullname == cur->nodesetval->nodeTab[i]->name) 8427 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); 8428 if (fullname == NULL) { 8429 XP_ERROR(XPATH_MEMORY_ERROR); 8430 } 8431 valuePush(ctxt, xmlXPathCacheWrapString( 8432 ctxt->context, fullname)); 8433 } 8434 break; 8435 default: 8436 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 8437 cur->nodesetval->nodeTab[i])); 8438 xmlXPathLocalNameFunction(ctxt, 1); 8439 } 8440 } 8441 xmlXPathReleaseObject(ctxt->context, cur); 8442} 8443 8444 8445/** 8446 * xmlXPathStringFunction: 8447 * @ctxt: the XPath Parser context 8448 * @nargs: the number of arguments 8449 * 8450 * Implement the string() XPath function 8451 * string string(object?) 8452 * The string function converts an object to a string as follows: 8453 * - A node-set is converted to a string by returning the value of 8454 * the node in the node-set that is first in document order. 8455 * If the node-set is empty, an empty string is returned. 8456 * - A number is converted to a string as follows 8457 * + NaN is converted to the string NaN 8458 * + positive zero is converted to the string 0 8459 * + negative zero is converted to the string 0 8460 * + positive infinity is converted to the string Infinity 8461 * + negative infinity is converted to the string -Infinity 8462 * + if the number is an integer, the number is represented in 8463 * decimal form as a Number with no decimal point and no leading 8464 * zeros, preceded by a minus sign (-) if the number is negative 8465 * + otherwise, the number is represented in decimal form as a 8466 * Number including a decimal point with at least one digit 8467 * before the decimal point and at least one digit after the 8468 * decimal point, preceded by a minus sign (-) if the number 8469 * is negative; there must be no leading zeros before the decimal 8470 * point apart possibly from the one required digit immediately 8471 * before the decimal point; beyond the one required digit 8472 * after the decimal point there must be as many, but only as 8473 * many, more digits as are needed to uniquely distinguish the 8474 * number from all other IEEE 754 numeric values. 8475 * - The boolean false value is converted to the string false. 8476 * The boolean true value is converted to the string true. 8477 * 8478 * If the argument is omitted, it defaults to a node-set with the 8479 * context node as its only member. 8480 */ 8481void 8482xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8483 xmlXPathObjectPtr cur; 8484 8485 if (ctxt == NULL) return; 8486 if (nargs == 0) { 8487 valuePush(ctxt, 8488 xmlXPathCacheWrapString(ctxt->context, 8489 xmlXPathCastNodeToString(ctxt->context->node))); 8490 return; 8491 } 8492 8493 CHECK_ARITY(1); 8494 cur = valuePop(ctxt); 8495 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 8496 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); 8497} 8498 8499/** 8500 * xmlXPathStringLengthFunction: 8501 * @ctxt: the XPath Parser context 8502 * @nargs: the number of arguments 8503 * 8504 * Implement the string-length() XPath function 8505 * number string-length(string?) 8506 * The string-length returns the number of characters in the string 8507 * (see [3.6 Strings]). If the argument is omitted, it defaults to 8508 * the context node converted to a string, in other words the value 8509 * of the context node. 8510 */ 8511void 8512xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8513 xmlXPathObjectPtr cur; 8514 8515 if (nargs == 0) { 8516 if ((ctxt == NULL) || (ctxt->context == NULL)) 8517 return; 8518 if (ctxt->context->node == NULL) { 8519 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); 8520 } else { 8521 xmlChar *content; 8522 8523 content = xmlXPathCastNodeToString(ctxt->context->node); 8524 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8525 xmlUTF8Strlen(content))); 8526 xmlFree(content); 8527 } 8528 return; 8529 } 8530 CHECK_ARITY(1); 8531 CAST_TO_STRING; 8532 CHECK_TYPE(XPATH_STRING); 8533 cur = valuePop(ctxt); 8534 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 8535 xmlUTF8Strlen(cur->stringval))); 8536 xmlXPathReleaseObject(ctxt->context, cur); 8537} 8538 8539/** 8540 * xmlXPathConcatFunction: 8541 * @ctxt: the XPath Parser context 8542 * @nargs: the number of arguments 8543 * 8544 * Implement the concat() XPath function 8545 * string concat(string, string, string*) 8546 * The concat function returns the concatenation of its arguments. 8547 */ 8548void 8549xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8550 xmlXPathObjectPtr cur, newobj; 8551 xmlChar *tmp; 8552 8553 if (ctxt == NULL) return; 8554 if (nargs < 2) { 8555 CHECK_ARITY(2); 8556 } 8557 8558 CAST_TO_STRING; 8559 cur = valuePop(ctxt); 8560 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 8561 xmlXPathReleaseObject(ctxt->context, cur); 8562 return; 8563 } 8564 nargs--; 8565 8566 while (nargs > 0) { 8567 CAST_TO_STRING; 8568 newobj = valuePop(ctxt); 8569 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 8570 xmlXPathReleaseObject(ctxt->context, newobj); 8571 xmlXPathReleaseObject(ctxt->context, cur); 8572 XP_ERROR(XPATH_INVALID_TYPE); 8573 } 8574 tmp = xmlStrcat(newobj->stringval, cur->stringval); 8575 newobj->stringval = cur->stringval; 8576 cur->stringval = tmp; 8577 xmlXPathReleaseObject(ctxt->context, newobj); 8578 nargs--; 8579 } 8580 valuePush(ctxt, cur); 8581} 8582 8583/** 8584 * xmlXPathContainsFunction: 8585 * @ctxt: the XPath Parser context 8586 * @nargs: the number of arguments 8587 * 8588 * Implement the contains() XPath function 8589 * boolean contains(string, string) 8590 * The contains function returns true if the first argument string 8591 * contains the second argument string, and otherwise returns false. 8592 */ 8593void 8594xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8595 xmlXPathObjectPtr hay, needle; 8596 8597 CHECK_ARITY(2); 8598 CAST_TO_STRING; 8599 CHECK_TYPE(XPATH_STRING); 8600 needle = valuePop(ctxt); 8601 CAST_TO_STRING; 8602 hay = valuePop(ctxt); 8603 8604 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 8605 xmlXPathReleaseObject(ctxt->context, hay); 8606 xmlXPathReleaseObject(ctxt->context, needle); 8607 XP_ERROR(XPATH_INVALID_TYPE); 8608 } 8609 if (xmlStrstr(hay->stringval, needle->stringval)) 8610 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 8611 else 8612 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 8613 xmlXPathReleaseObject(ctxt->context, hay); 8614 xmlXPathReleaseObject(ctxt->context, needle); 8615} 8616 8617/** 8618 * xmlXPathStartsWithFunction: 8619 * @ctxt: the XPath Parser context 8620 * @nargs: the number of arguments 8621 * 8622 * Implement the starts-with() XPath function 8623 * boolean starts-with(string, string) 8624 * The starts-with function returns true if the first argument string 8625 * starts with the second argument string, and otherwise returns false. 8626 */ 8627void 8628xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8629 xmlXPathObjectPtr hay, needle; 8630 int n; 8631 8632 CHECK_ARITY(2); 8633 CAST_TO_STRING; 8634 CHECK_TYPE(XPATH_STRING); 8635 needle = valuePop(ctxt); 8636 CAST_TO_STRING; 8637 hay = valuePop(ctxt); 8638 8639 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 8640 xmlXPathReleaseObject(ctxt->context, hay); 8641 xmlXPathReleaseObject(ctxt->context, needle); 8642 XP_ERROR(XPATH_INVALID_TYPE); 8643 } 8644 n = xmlStrlen(needle->stringval); 8645 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 8646 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 8647 else 8648 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 8649 xmlXPathReleaseObject(ctxt->context, hay); 8650 xmlXPathReleaseObject(ctxt->context, needle); 8651} 8652 8653/** 8654 * xmlXPathSubstringFunction: 8655 * @ctxt: the XPath Parser context 8656 * @nargs: the number of arguments 8657 * 8658 * Implement the substring() XPath function 8659 * string substring(string, number, number?) 8660 * The substring function returns the substring of the first argument 8661 * starting at the position specified in the second argument with 8662 * length specified in the third argument. For example, 8663 * substring("12345",2,3) returns "234". If the third argument is not 8664 * specified, it returns the substring starting at the position specified 8665 * in the second argument and continuing to the end of the string. For 8666 * example, substring("12345",2) returns "2345". More precisely, each 8667 * character in the string (see [3.6 Strings]) is considered to have a 8668 * numeric position: the position of the first character is 1, the position 8669 * of the second character is 2 and so on. The returned substring contains 8670 * those characters for which the position of the character is greater than 8671 * or equal to the second argument and, if the third argument is specified, 8672 * less than the sum of the second and third arguments; the comparisons 8673 * and addition used for the above follow the standard IEEE 754 rules. Thus: 8674 * - substring("12345", 1.5, 2.6) returns "234" 8675 * - substring("12345", 0, 3) returns "12" 8676 * - substring("12345", 0 div 0, 3) returns "" 8677 * - substring("12345", 1, 0 div 0) returns "" 8678 * - substring("12345", -42, 1 div 0) returns "12345" 8679 * - substring("12345", -1 div 0, 1 div 0) returns "" 8680 */ 8681void 8682xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8683 xmlXPathObjectPtr str, start, len; 8684 double le=0, in; 8685 int i, l, m; 8686 xmlChar *ret; 8687 8688 if (nargs < 2) { 8689 CHECK_ARITY(2); 8690 } 8691 if (nargs > 3) { 8692 CHECK_ARITY(3); 8693 } 8694 /* 8695 * take care of possible last (position) argument 8696 */ 8697 if (nargs == 3) { 8698 CAST_TO_NUMBER; 8699 CHECK_TYPE(XPATH_NUMBER); 8700 len = valuePop(ctxt); 8701 le = len->floatval; 8702 xmlXPathReleaseObject(ctxt->context, len); 8703 } 8704 8705 CAST_TO_NUMBER; 8706 CHECK_TYPE(XPATH_NUMBER); 8707 start = valuePop(ctxt); 8708 in = start->floatval; 8709 xmlXPathReleaseObject(ctxt->context, start); 8710 CAST_TO_STRING; 8711 CHECK_TYPE(XPATH_STRING); 8712 str = valuePop(ctxt); 8713 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 8714 8715 /* 8716 * If last pos not present, calculate last position 8717 */ 8718 if (nargs != 3) { 8719 le = (double)m; 8720 if (in < 1.0) 8721 in = 1.0; 8722 } 8723 8724 /* Need to check for the special cases where either 8725 * the index is NaN, the length is NaN, or both 8726 * arguments are infinity (relying on Inf + -Inf = NaN) 8727 */ 8728 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) { 8729 /* 8730 * To meet the requirements of the spec, the arguments 8731 * must be converted to integer format before 8732 * initial index calculations are done 8733 * 8734 * First we go to integer form, rounding up 8735 * and checking for special cases 8736 */ 8737 i = (int) in; 8738 if (((double)i)+0.5 <= in) i++; 8739 8740 if (xmlXPathIsInf(le) == 1) { 8741 l = m; 8742 if (i < 1) 8743 i = 1; 8744 } 8745 else if (xmlXPathIsInf(le) == -1 || le < 0.0) 8746 l = 0; 8747 else { 8748 l = (int) le; 8749 if (((double)l)+0.5 <= le) l++; 8750 } 8751 8752 /* Now we normalize inidices */ 8753 i -= 1; 8754 l += i; 8755 if (i < 0) 8756 i = 0; 8757 if (l > m) 8758 l = m; 8759 8760 /* number of chars to copy */ 8761 l -= i; 8762 8763 ret = xmlUTF8Strsub(str->stringval, i, l); 8764 } 8765 else { 8766 ret = NULL; 8767 } 8768 if (ret == NULL) 8769 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); 8770 else { 8771 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); 8772 xmlFree(ret); 8773 } 8774 xmlXPathReleaseObject(ctxt->context, str); 8775} 8776 8777/** 8778 * xmlXPathSubstringBeforeFunction: 8779 * @ctxt: the XPath Parser context 8780 * @nargs: the number of arguments 8781 * 8782 * Implement the substring-before() XPath function 8783 * string substring-before(string, string) 8784 * The substring-before function returns the substring of the first 8785 * argument string that precedes the first occurrence of the second 8786 * argument string in the first argument string, or the empty string 8787 * if the first argument string does not contain the second argument 8788 * string. For example, substring-before("1999/04/01","/") returns 1999. 8789 */ 8790void 8791xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8792 xmlXPathObjectPtr str; 8793 xmlXPathObjectPtr find; 8794 xmlBufferPtr target; 8795 const xmlChar *point; 8796 int offset; 8797 8798 CHECK_ARITY(2); 8799 CAST_TO_STRING; 8800 find = valuePop(ctxt); 8801 CAST_TO_STRING; 8802 str = valuePop(ctxt); 8803 8804 target = xmlBufferCreate(); 8805 if (target) { 8806 point = xmlStrstr(str->stringval, find->stringval); 8807 if (point) { 8808 offset = (int)(point - str->stringval); 8809 xmlBufferAdd(target, str->stringval, offset); 8810 } 8811 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8812 xmlBufferContent(target))); 8813 xmlBufferFree(target); 8814 } 8815 xmlXPathReleaseObject(ctxt->context, str); 8816 xmlXPathReleaseObject(ctxt->context, find); 8817} 8818 8819/** 8820 * xmlXPathSubstringAfterFunction: 8821 * @ctxt: the XPath Parser context 8822 * @nargs: the number of arguments 8823 * 8824 * Implement the substring-after() XPath function 8825 * string substring-after(string, string) 8826 * The substring-after function returns the substring of the first 8827 * argument string that follows the first occurrence of the second 8828 * argument string in the first argument string, or the empty stringi 8829 * if the first argument string does not contain the second argument 8830 * string. For example, substring-after("1999/04/01","/") returns 04/01, 8831 * and substring-after("1999/04/01","19") returns 99/04/01. 8832 */ 8833void 8834xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8835 xmlXPathObjectPtr str; 8836 xmlXPathObjectPtr find; 8837 xmlBufferPtr target; 8838 const xmlChar *point; 8839 int offset; 8840 8841 CHECK_ARITY(2); 8842 CAST_TO_STRING; 8843 find = valuePop(ctxt); 8844 CAST_TO_STRING; 8845 str = valuePop(ctxt); 8846 8847 target = xmlBufferCreate(); 8848 if (target) { 8849 point = xmlStrstr(str->stringval, find->stringval); 8850 if (point) { 8851 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 8852 xmlBufferAdd(target, &str->stringval[offset], 8853 xmlStrlen(str->stringval) - offset); 8854 } 8855 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8856 xmlBufferContent(target))); 8857 xmlBufferFree(target); 8858 } 8859 xmlXPathReleaseObject(ctxt->context, str); 8860 xmlXPathReleaseObject(ctxt->context, find); 8861} 8862 8863/** 8864 * xmlXPathNormalizeFunction: 8865 * @ctxt: the XPath Parser context 8866 * @nargs: the number of arguments 8867 * 8868 * Implement the normalize-space() XPath function 8869 * string normalize-space(string?) 8870 * The normalize-space function returns the argument string with white 8871 * space normalized by stripping leading and trailing whitespace 8872 * and replacing sequences of whitespace characters by a single 8873 * space. Whitespace characters are the same allowed by the S production 8874 * in XML. If the argument is omitted, it defaults to the context 8875 * node converted to a string, in other words the value of the context node. 8876 */ 8877void 8878xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8879 xmlXPathObjectPtr obj = NULL; 8880 xmlChar *source = NULL; 8881 xmlBufferPtr target; 8882 xmlChar blank; 8883 8884 if (ctxt == NULL) return; 8885 if (nargs == 0) { 8886 /* Use current context node */ 8887 valuePush(ctxt, 8888 xmlXPathCacheWrapString(ctxt->context, 8889 xmlXPathCastNodeToString(ctxt->context->node))); 8890 nargs = 1; 8891 } 8892 8893 CHECK_ARITY(1); 8894 CAST_TO_STRING; 8895 CHECK_TYPE(XPATH_STRING); 8896 obj = valuePop(ctxt); 8897 source = obj->stringval; 8898 8899 target = xmlBufferCreate(); 8900 if (target && source) { 8901 8902 /* Skip leading whitespaces */ 8903 while (IS_BLANK_CH(*source)) 8904 source++; 8905 8906 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 8907 blank = 0; 8908 while (*source) { 8909 if (IS_BLANK_CH(*source)) { 8910 blank = 0x20; 8911 } else { 8912 if (blank) { 8913 xmlBufferAdd(target, &blank, 1); 8914 blank = 0; 8915 } 8916 xmlBufferAdd(target, source, 1); 8917 } 8918 source++; 8919 } 8920 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 8921 xmlBufferContent(target))); 8922 xmlBufferFree(target); 8923 } 8924 xmlXPathReleaseObject(ctxt->context, obj); 8925} 8926 8927/** 8928 * xmlXPathTranslateFunction: 8929 * @ctxt: the XPath Parser context 8930 * @nargs: the number of arguments 8931 * 8932 * Implement the translate() XPath function 8933 * string translate(string, string, string) 8934 * The translate function returns the first argument string with 8935 * occurrences of characters in the second argument string replaced 8936 * by the character at the corresponding position in the third argument 8937 * string. For example, translate("bar","abc","ABC") returns the string 8938 * BAr. If there is a character in the second argument string with no 8939 * character at a corresponding position in the third argument string 8940 * (because the second argument string is longer than the third argument 8941 * string), then occurrences of that character in the first argument 8942 * string are removed. For example, translate("--aaa--","abc-","ABC") 8943 * returns "AAA". If a character occurs more than once in second 8944 * argument string, then the first occurrence determines the replacement 8945 * character. If the third argument string is longer than the second 8946 * argument string, then excess characters are ignored. 8947 */ 8948void 8949xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 8950 xmlXPathObjectPtr str; 8951 xmlXPathObjectPtr from; 8952 xmlXPathObjectPtr to; 8953 xmlBufferPtr target; 8954 int offset, max; 8955 xmlChar ch; 8956 const xmlChar *point; 8957 xmlChar *cptr; 8958 8959 CHECK_ARITY(3); 8960 8961 CAST_TO_STRING; 8962 to = valuePop(ctxt); 8963 CAST_TO_STRING; 8964 from = valuePop(ctxt); 8965 CAST_TO_STRING; 8966 str = valuePop(ctxt); 8967 8968 target = xmlBufferCreate(); 8969 if (target) { 8970 max = xmlUTF8Strlen(to->stringval); 8971 for (cptr = str->stringval; (ch=*cptr); ) { 8972 offset = xmlUTF8Strloc(from->stringval, cptr); 8973 if (offset >= 0) { 8974 if (offset < max) { 8975 point = xmlUTF8Strpos(to->stringval, offset); 8976 if (point) 8977 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1)); 8978 } 8979 } else 8980 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 8981 8982 /* Step to next character in input */ 8983 cptr++; 8984 if ( ch & 0x80 ) { 8985 /* if not simple ascii, verify proper format */ 8986 if ( (ch & 0xc0) != 0xc0 ) { 8987 xmlGenericError(xmlGenericErrorContext, 8988 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 8989 break; 8990 } 8991 /* then skip over remaining bytes for this char */ 8992 while ( (ch <<= 1) & 0x80 ) 8993 if ( (*cptr++ & 0xc0) != 0x80 ) { 8994 xmlGenericError(xmlGenericErrorContext, 8995 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 8996 break; 8997 } 8998 if (ch & 0x80) /* must have had error encountered */ 8999 break; 9000 } 9001 } 9002 } 9003 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 9004 xmlBufferContent(target))); 9005 xmlBufferFree(target); 9006 xmlXPathReleaseObject(ctxt->context, str); 9007 xmlXPathReleaseObject(ctxt->context, from); 9008 xmlXPathReleaseObject(ctxt->context, to); 9009} 9010 9011/** 9012 * xmlXPathBooleanFunction: 9013 * @ctxt: the XPath Parser context 9014 * @nargs: the number of arguments 9015 * 9016 * Implement the boolean() XPath function 9017 * boolean boolean(object) 9018 * The boolean function converts its argument to a boolean as follows: 9019 * - a number is true if and only if it is neither positive or 9020 * negative zero nor NaN 9021 * - a node-set is true if and only if it is non-empty 9022 * - a string is true if and only if its length is non-zero 9023 */ 9024void 9025xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9026 xmlXPathObjectPtr cur; 9027 9028 CHECK_ARITY(1); 9029 cur = valuePop(ctxt); 9030 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 9031 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); 9032 valuePush(ctxt, cur); 9033} 9034 9035/** 9036 * xmlXPathNotFunction: 9037 * @ctxt: the XPath Parser context 9038 * @nargs: the number of arguments 9039 * 9040 * Implement the not() XPath function 9041 * boolean not(boolean) 9042 * The not function returns true if its argument is false, 9043 * and false otherwise. 9044 */ 9045void 9046xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9047 CHECK_ARITY(1); 9048 CAST_TO_BOOLEAN; 9049 CHECK_TYPE(XPATH_BOOLEAN); 9050 ctxt->value->boolval = ! ctxt->value->boolval; 9051} 9052 9053/** 9054 * xmlXPathTrueFunction: 9055 * @ctxt: the XPath Parser context 9056 * @nargs: the number of arguments 9057 * 9058 * Implement the true() XPath function 9059 * boolean true() 9060 */ 9061void 9062xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9063 CHECK_ARITY(0); 9064 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); 9065} 9066 9067/** 9068 * xmlXPathFalseFunction: 9069 * @ctxt: the XPath Parser context 9070 * @nargs: the number of arguments 9071 * 9072 * Implement the false() XPath function 9073 * boolean false() 9074 */ 9075void 9076xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9077 CHECK_ARITY(0); 9078 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); 9079} 9080 9081/** 9082 * xmlXPathLangFunction: 9083 * @ctxt: the XPath Parser context 9084 * @nargs: the number of arguments 9085 * 9086 * Implement the lang() XPath function 9087 * boolean lang(string) 9088 * The lang function returns true or false depending on whether the 9089 * language of the context node as specified by xml:lang attributes 9090 * is the same as or is a sublanguage of the language specified by 9091 * the argument string. The language of the context node is determined 9092 * by the value of the xml:lang attribute on the context node, or, if 9093 * the context node has no xml:lang attribute, by the value of the 9094 * xml:lang attribute on the nearest ancestor of the context node that 9095 * has an xml:lang attribute. If there is no such attribute, then lang 9096 * returns false. If there is such an attribute, then lang returns 9097 * true if the attribute value is equal to the argument ignoring case, 9098 * or if there is some suffix starting with - such that the attribute 9099 * value is equal to the argument ignoring that suffix of the attribute 9100 * value and ignoring case. 9101 */ 9102void 9103xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9104 xmlXPathObjectPtr val = NULL; 9105 const xmlChar *theLang = NULL; 9106 const xmlChar *lang; 9107 int ret = 0; 9108 int i; 9109 9110 CHECK_ARITY(1); 9111 CAST_TO_STRING; 9112 CHECK_TYPE(XPATH_STRING); 9113 val = valuePop(ctxt); 9114 lang = val->stringval; 9115 theLang = xmlNodeGetLang(ctxt->context->node); 9116 if ((theLang != NULL) && (lang != NULL)) { 9117 for (i = 0;lang[i] != 0;i++) 9118 if (toupper(lang[i]) != toupper(theLang[i])) 9119 goto not_equal; 9120 if ((theLang[i] == 0) || (theLang[i] == '-')) 9121 ret = 1; 9122 } 9123not_equal: 9124 if (theLang != NULL) 9125 xmlFree((void *)theLang); 9126 9127 xmlXPathReleaseObject(ctxt->context, val); 9128 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 9129} 9130 9131/** 9132 * xmlXPathNumberFunction: 9133 * @ctxt: the XPath Parser context 9134 * @nargs: the number of arguments 9135 * 9136 * Implement the number() XPath function 9137 * number number(object?) 9138 */ 9139void 9140xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9141 xmlXPathObjectPtr cur; 9142 double res; 9143 9144 if (ctxt == NULL) return; 9145 if (nargs == 0) { 9146 if (ctxt->context->node == NULL) { 9147 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); 9148 } else { 9149 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 9150 9151 res = xmlXPathStringEvalNumber(content); 9152 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9153 xmlFree(content); 9154 } 9155 return; 9156 } 9157 9158 CHECK_ARITY(1); 9159 cur = valuePop(ctxt); 9160 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); 9161} 9162 9163/** 9164 * xmlXPathSumFunction: 9165 * @ctxt: the XPath Parser context 9166 * @nargs: the number of arguments 9167 * 9168 * Implement the sum() XPath function 9169 * number sum(node-set) 9170 * The sum function returns the sum of the values of the nodes in 9171 * the argument node-set. 9172 */ 9173void 9174xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9175 xmlXPathObjectPtr cur; 9176 int i; 9177 double res = 0.0; 9178 9179 CHECK_ARITY(1); 9180 if ((ctxt->value == NULL) || 9181 ((ctxt->value->type != XPATH_NODESET) && 9182 (ctxt->value->type != XPATH_XSLT_TREE))) 9183 XP_ERROR(XPATH_INVALID_TYPE); 9184 cur = valuePop(ctxt); 9185 9186 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { 9187 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 9188 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 9189 } 9190 } 9191 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); 9192 xmlXPathReleaseObject(ctxt->context, cur); 9193} 9194 9195/* 9196 * To assure working code on multiple platforms, we want to only depend 9197 * upon the characteristic truncation of converting a floating point value 9198 * to an integer. Unfortunately, because of the different storage sizes 9199 * of our internal floating point value (double) and integer (int), we 9200 * can't directly convert (see bug 301162). This macro is a messy 9201 * 'workaround' 9202 */ 9203#define XTRUNC(f, v) \ 9204 f = fmod((v), INT_MAX); \ 9205 f = (v) - (f) + (double)((int)(f)); 9206 9207/** 9208 * xmlXPathFloorFunction: 9209 * @ctxt: the XPath Parser context 9210 * @nargs: the number of arguments 9211 * 9212 * Implement the floor() XPath function 9213 * number floor(number) 9214 * The floor function returns the largest (closest to positive infinity) 9215 * number that is not greater than the argument and that is an integer. 9216 */ 9217void 9218xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9219 double f; 9220 9221 CHECK_ARITY(1); 9222 CAST_TO_NUMBER; 9223 CHECK_TYPE(XPATH_NUMBER); 9224 9225 XTRUNC(f, ctxt->value->floatval); 9226 if (f != ctxt->value->floatval) { 9227 if (ctxt->value->floatval > 0) 9228 ctxt->value->floatval = f; 9229 else 9230 ctxt->value->floatval = f - 1; 9231 } 9232} 9233 9234/** 9235 * xmlXPathCeilingFunction: 9236 * @ctxt: the XPath Parser context 9237 * @nargs: the number of arguments 9238 * 9239 * Implement the ceiling() XPath function 9240 * number ceiling(number) 9241 * The ceiling function returns the smallest (closest to negative infinity) 9242 * number that is not less than the argument and that is an integer. 9243 */ 9244void 9245xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9246 double f; 9247 9248 CHECK_ARITY(1); 9249 CAST_TO_NUMBER; 9250 CHECK_TYPE(XPATH_NUMBER); 9251 9252#if 0 9253 ctxt->value->floatval = ceil(ctxt->value->floatval); 9254#else 9255 XTRUNC(f, ctxt->value->floatval); 9256 if (f != ctxt->value->floatval) { 9257 if (ctxt->value->floatval > 0) 9258 ctxt->value->floatval = f + 1; 9259 else { 9260 if (ctxt->value->floatval < 0 && f == 0) 9261 ctxt->value->floatval = xmlXPathNZERO; 9262 else 9263 ctxt->value->floatval = f; 9264 } 9265 9266 } 9267#endif 9268} 9269 9270/** 9271 * xmlXPathRoundFunction: 9272 * @ctxt: the XPath Parser context 9273 * @nargs: the number of arguments 9274 * 9275 * Implement the round() XPath function 9276 * number round(number) 9277 * The round function returns the number that is closest to the 9278 * argument and that is an integer. If there are two such numbers, 9279 * then the one that is even is returned. 9280 */ 9281void 9282xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 9283 double f; 9284 9285 CHECK_ARITY(1); 9286 CAST_TO_NUMBER; 9287 CHECK_TYPE(XPATH_NUMBER); 9288 9289 if ((xmlXPathIsNaN(ctxt->value->floatval)) || 9290 (xmlXPathIsInf(ctxt->value->floatval) == 1) || 9291 (xmlXPathIsInf(ctxt->value->floatval) == -1) || 9292 (ctxt->value->floatval == 0.0)) 9293 return; 9294 9295 XTRUNC(f, ctxt->value->floatval); 9296 if (ctxt->value->floatval < 0) { 9297 if (ctxt->value->floatval < f - 0.5) 9298 ctxt->value->floatval = f - 1; 9299 else 9300 ctxt->value->floatval = f; 9301 if (ctxt->value->floatval == 0) 9302 ctxt->value->floatval = xmlXPathNZERO; 9303 } else { 9304 if (ctxt->value->floatval < f + 0.5) 9305 ctxt->value->floatval = f; 9306 else 9307 ctxt->value->floatval = f + 1; 9308 } 9309} 9310 9311/************************************************************************ 9312 * * 9313 * The Parser * 9314 * * 9315 ************************************************************************/ 9316 9317/* 9318 * a few forward declarations since we use a recursive call based 9319 * implementation. 9320 */ 9321static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); 9322static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 9323static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 9324static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 9325static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 9326 int qualified); 9327 9328/** 9329 * xmlXPathCurrentChar: 9330 * @ctxt: the XPath parser context 9331 * @cur: pointer to the beginning of the char 9332 * @len: pointer to the length of the char read 9333 * 9334 * The current char value, if using UTF-8 this may actually span multiple 9335 * bytes in the input buffer. 9336 * 9337 * Returns the current char value and its length 9338 */ 9339 9340static int 9341xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 9342 unsigned char c; 9343 unsigned int val; 9344 const xmlChar *cur; 9345 9346 if (ctxt == NULL) 9347 return(0); 9348 cur = ctxt->cur; 9349 9350 /* 9351 * We are supposed to handle UTF8, check it's valid 9352 * From rfc2044: encoding of the Unicode values on UTF-8: 9353 * 9354 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 9355 * 0000 0000-0000 007F 0xxxxxxx 9356 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 9357 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 9358 * 9359 * Check for the 0x110000 limit too 9360 */ 9361 c = *cur; 9362 if (c & 0x80) { 9363 if ((cur[1] & 0xc0) != 0x80) 9364 goto encoding_error; 9365 if ((c & 0xe0) == 0xe0) { 9366 9367 if ((cur[2] & 0xc0) != 0x80) 9368 goto encoding_error; 9369 if ((c & 0xf0) == 0xf0) { 9370 if (((c & 0xf8) != 0xf0) || 9371 ((cur[3] & 0xc0) != 0x80)) 9372 goto encoding_error; 9373 /* 4-byte code */ 9374 *len = 4; 9375 val = (cur[0] & 0x7) << 18; 9376 val |= (cur[1] & 0x3f) << 12; 9377 val |= (cur[2] & 0x3f) << 6; 9378 val |= cur[3] & 0x3f; 9379 } else { 9380 /* 3-byte code */ 9381 *len = 3; 9382 val = (cur[0] & 0xf) << 12; 9383 val |= (cur[1] & 0x3f) << 6; 9384 val |= cur[2] & 0x3f; 9385 } 9386 } else { 9387 /* 2-byte code */ 9388 *len = 2; 9389 val = (cur[0] & 0x1f) << 6; 9390 val |= cur[1] & 0x3f; 9391 } 9392 if (!IS_CHAR(val)) { 9393 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 9394 } 9395 return(val); 9396 } else { 9397 /* 1-byte code */ 9398 *len = 1; 9399 return((int) *cur); 9400 } 9401encoding_error: 9402 /* 9403 * If we detect an UTF8 error that probably means that the 9404 * input encoding didn't get properly advertised in the 9405 * declaration header. Report the error and switch the encoding 9406 * to ISO-Latin-1 (if you don't like this policy, just declare the 9407 * encoding !) 9408 */ 9409 *len = 0; 9410 XP_ERROR0(XPATH_ENCODING_ERROR); 9411} 9412 9413/** 9414 * xmlXPathParseNCName: 9415 * @ctxt: the XPath Parser context 9416 * 9417 * parse an XML namespace non qualified name. 9418 * 9419 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 9420 * 9421 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 9422 * CombiningChar | Extender 9423 * 9424 * Returns the namespace name or NULL 9425 */ 9426 9427xmlChar * 9428xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 9429 const xmlChar *in; 9430 xmlChar *ret; 9431 int count = 0; 9432 9433 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9434 /* 9435 * Accelerator for simple ASCII names 9436 */ 9437 in = ctxt->cur; 9438 if (((*in >= 0x61) && (*in <= 0x7A)) || 9439 ((*in >= 0x41) && (*in <= 0x5A)) || 9440 (*in == '_')) { 9441 in++; 9442 while (((*in >= 0x61) && (*in <= 0x7A)) || 9443 ((*in >= 0x41) && (*in <= 0x5A)) || 9444 ((*in >= 0x30) && (*in <= 0x39)) || 9445 (*in == '_') || (*in == '.') || 9446 (*in == '-')) 9447 in++; 9448 if ((*in == ' ') || (*in == '>') || (*in == '/') || 9449 (*in == '[') || (*in == ']') || (*in == ':') || 9450 (*in == '@') || (*in == '*')) { 9451 count = in - ctxt->cur; 9452 if (count == 0) 9453 return(NULL); 9454 ret = xmlStrndup(ctxt->cur, count); 9455 ctxt->cur = in; 9456 return(ret); 9457 } 9458 } 9459 return(xmlXPathParseNameComplex(ctxt, 0)); 9460} 9461 9462 9463/** 9464 * xmlXPathParseQName: 9465 * @ctxt: the XPath Parser context 9466 * @prefix: a xmlChar ** 9467 * 9468 * parse an XML qualified name 9469 * 9470 * [NS 5] QName ::= (Prefix ':')? LocalPart 9471 * 9472 * [NS 6] Prefix ::= NCName 9473 * 9474 * [NS 7] LocalPart ::= NCName 9475 * 9476 * Returns the function returns the local part, and prefix is updated 9477 * to get the Prefix if any. 9478 */ 9479 9480static xmlChar * 9481xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 9482 xmlChar *ret = NULL; 9483 9484 *prefix = NULL; 9485 ret = xmlXPathParseNCName(ctxt); 9486 if (CUR == ':') { 9487 *prefix = ret; 9488 NEXT; 9489 ret = xmlXPathParseNCName(ctxt); 9490 } 9491 return(ret); 9492} 9493 9494/** 9495 * xmlXPathParseName: 9496 * @ctxt: the XPath Parser context 9497 * 9498 * parse an XML name 9499 * 9500 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 9501 * CombiningChar | Extender 9502 * 9503 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 9504 * 9505 * Returns the namespace name or NULL 9506 */ 9507 9508xmlChar * 9509xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 9510 const xmlChar *in; 9511 xmlChar *ret; 9512 int count = 0; 9513 9514 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); 9515 /* 9516 * Accelerator for simple ASCII names 9517 */ 9518 in = ctxt->cur; 9519 if (((*in >= 0x61) && (*in <= 0x7A)) || 9520 ((*in >= 0x41) && (*in <= 0x5A)) || 9521 (*in == '_') || (*in == ':')) { 9522 in++; 9523 while (((*in >= 0x61) && (*in <= 0x7A)) || 9524 ((*in >= 0x41) && (*in <= 0x5A)) || 9525 ((*in >= 0x30) && (*in <= 0x39)) || 9526 (*in == '_') || (*in == '-') || 9527 (*in == ':') || (*in == '.')) 9528 in++; 9529 if ((*in > 0) && (*in < 0x80)) { 9530 count = in - ctxt->cur; 9531 ret = xmlStrndup(ctxt->cur, count); 9532 ctxt->cur = in; 9533 return(ret); 9534 } 9535 } 9536 return(xmlXPathParseNameComplex(ctxt, 1)); 9537} 9538 9539static xmlChar * 9540xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 9541 xmlChar buf[XML_MAX_NAMELEN + 5]; 9542 int len = 0, l; 9543 int c; 9544 9545 /* 9546 * Handler for more complex cases 9547 */ 9548 c = CUR_CHAR(l); 9549 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 9550 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 9551 (c == '*') || /* accelerators */ 9552 (!IS_LETTER(c) && (c != '_') && 9553 ((qualified) && (c != ':')))) { 9554 return(NULL); 9555 } 9556 9557 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 9558 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 9559 (c == '.') || (c == '-') || 9560 (c == '_') || ((qualified) && (c == ':')) || 9561 (IS_COMBINING(c)) || 9562 (IS_EXTENDER(c)))) { 9563 COPY_BUF(l,buf,len,c); 9564 NEXTL(l); 9565 c = CUR_CHAR(l); 9566 if (len >= XML_MAX_NAMELEN) { 9567 /* 9568 * Okay someone managed to make a huge name, so he's ready to pay 9569 * for the processing speed. 9570 */ 9571 xmlChar *buffer; 9572 int max = len * 2; 9573 9574 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); 9575 if (buffer == NULL) { 9576 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9577 } 9578 memcpy(buffer, buf, len); 9579 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 9580 (c == '.') || (c == '-') || 9581 (c == '_') || ((qualified) && (c == ':')) || 9582 (IS_COMBINING(c)) || 9583 (IS_EXTENDER(c))) { 9584 if (len + 10 > max) { 9585 max *= 2; 9586 buffer = (xmlChar *) xmlRealloc(buffer, 9587 max * sizeof(xmlChar)); 9588 if (buffer == NULL) { 9589 XP_ERRORNULL(XPATH_MEMORY_ERROR); 9590 } 9591 } 9592 COPY_BUF(l,buffer,len,c); 9593 NEXTL(l); 9594 c = CUR_CHAR(l); 9595 } 9596 buffer[len] = 0; 9597 return(buffer); 9598 } 9599 } 9600 if (len == 0) 9601 return(NULL); 9602 return(xmlStrndup(buf, len)); 9603} 9604 9605#define MAX_FRAC 20 9606 9607/* 9608 * These are used as divisors for the fractional part of a number. 9609 * Since the table includes 1.0 (representing '0' fractional digits), 9610 * it must be dimensioned at MAX_FRAC+1 (bug 133921) 9611 */ 9612static double my_pow10[MAX_FRAC+1] = { 9613 1.0, 10.0, 100.0, 1000.0, 10000.0, 9614 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 9615 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 9616 100000000000000.0, 9617 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 9618 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0 9619}; 9620 9621/** 9622 * xmlXPathStringEvalNumber: 9623 * @str: A string to scan 9624 * 9625 * [30a] Float ::= Number ('e' Digits?)? 9626 * 9627 * [30] Number ::= Digits ('.' Digits?)? 9628 * | '.' Digits 9629 * [31] Digits ::= [0-9]+ 9630 * 9631 * Compile a Number in the string 9632 * In complement of the Number expression, this function also handles 9633 * negative values : '-' Number. 9634 * 9635 * Returns the double value. 9636 */ 9637double 9638xmlXPathStringEvalNumber(const xmlChar *str) { 9639 const xmlChar *cur = str; 9640 double ret; 9641 int ok = 0; 9642 int isneg = 0; 9643 int exponent = 0; 9644 int is_exponent_negative = 0; 9645#ifdef __GNUC__ 9646 unsigned long tmp = 0; 9647 double temp; 9648#endif 9649 if (cur == NULL) return(0); 9650 while (IS_BLANK_CH(*cur)) cur++; 9651 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 9652 return(xmlXPathNAN); 9653 } 9654 if (*cur == '-') { 9655 isneg = 1; 9656 cur++; 9657 } 9658 9659#ifdef __GNUC__ 9660 /* 9661 * tmp/temp is a workaround against a gcc compiler bug 9662 * http://veillard.com/gcc.bug 9663 */ 9664 ret = 0; 9665 while ((*cur >= '0') && (*cur <= '9')) { 9666 ret = ret * 10; 9667 tmp = (*cur - '0'); 9668 ok = 1; 9669 cur++; 9670 temp = (double) tmp; 9671 ret = ret + temp; 9672 } 9673#else 9674 ret = 0; 9675 while ((*cur >= '0') && (*cur <= '9')) { 9676 ret = ret * 10 + (*cur - '0'); 9677 ok = 1; 9678 cur++; 9679 } 9680#endif 9681 9682 if (*cur == '.') { 9683 int v, frac = 0; 9684 double fraction = 0; 9685 9686 cur++; 9687 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 9688 return(xmlXPathNAN); 9689 } 9690 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { 9691 v = (*cur - '0'); 9692 fraction = fraction * 10 + v; 9693 frac = frac + 1; 9694 cur++; 9695 } 9696 fraction /= my_pow10[frac]; 9697 ret = ret + fraction; 9698 while ((*cur >= '0') && (*cur <= '9')) 9699 cur++; 9700 } 9701 if ((*cur == 'e') || (*cur == 'E')) { 9702 cur++; 9703 if (*cur == '-') { 9704 is_exponent_negative = 1; 9705 cur++; 9706 } else if (*cur == '+') { 9707 cur++; 9708 } 9709 while ((*cur >= '0') && (*cur <= '9')) { 9710 exponent = exponent * 10 + (*cur - '0'); 9711 cur++; 9712 } 9713 } 9714 while (IS_BLANK_CH(*cur)) cur++; 9715 if (*cur != 0) return(xmlXPathNAN); 9716 if (isneg) ret = -ret; 9717 if (is_exponent_negative) exponent = -exponent; 9718 ret *= pow(10.0, (double)exponent); 9719 return(ret); 9720} 9721 9722/** 9723 * xmlXPathCompNumber: 9724 * @ctxt: the XPath Parser context 9725 * 9726 * [30] Number ::= Digits ('.' Digits?)? 9727 * | '.' Digits 9728 * [31] Digits ::= [0-9]+ 9729 * 9730 * Compile a Number, then push it on the stack 9731 * 9732 */ 9733static void 9734xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 9735{ 9736 double ret = 0.0; 9737 double mult = 1; 9738 int ok = 0; 9739 int exponent = 0; 9740 int is_exponent_negative = 0; 9741#ifdef __GNUC__ 9742 unsigned long tmp = 0; 9743 double temp; 9744#endif 9745 9746 CHECK_ERROR; 9747 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 9748 XP_ERROR(XPATH_NUMBER_ERROR); 9749 } 9750#ifdef __GNUC__ 9751 /* 9752 * tmp/temp is a workaround against a gcc compiler bug 9753 * http://veillard.com/gcc.bug 9754 */ 9755 ret = 0; 9756 while ((CUR >= '0') && (CUR <= '9')) { 9757 ret = ret * 10; 9758 tmp = (CUR - '0'); 9759 ok = 1; 9760 NEXT; 9761 temp = (double) tmp; 9762 ret = ret + temp; 9763 } 9764#else 9765 ret = 0; 9766 while ((CUR >= '0') && (CUR <= '9')) { 9767 ret = ret * 10 + (CUR - '0'); 9768 ok = 1; 9769 NEXT; 9770 } 9771#endif 9772 if (CUR == '.') { 9773 NEXT; 9774 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 9775 XP_ERROR(XPATH_NUMBER_ERROR); 9776 } 9777 while ((CUR >= '0') && (CUR <= '9')) { 9778 mult /= 10; 9779 ret = ret + (CUR - '0') * mult; 9780 NEXT; 9781 } 9782 } 9783 if ((CUR == 'e') || (CUR == 'E')) { 9784 NEXT; 9785 if (CUR == '-') { 9786 is_exponent_negative = 1; 9787 NEXT; 9788 } else if (CUR == '+') { 9789 NEXT; 9790 } 9791 while ((CUR >= '0') && (CUR <= '9')) { 9792 exponent = exponent * 10 + (CUR - '0'); 9793 NEXT; 9794 } 9795 if (is_exponent_negative) 9796 exponent = -exponent; 9797 ret *= pow(10.0, (double) exponent); 9798 } 9799 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 9800 xmlXPathCacheNewFloat(ctxt->context, ret), NULL); 9801} 9802 9803/** 9804 * xmlXPathParseLiteral: 9805 * @ctxt: the XPath Parser context 9806 * 9807 * Parse a Literal 9808 * 9809 * [29] Literal ::= '"' [^"]* '"' 9810 * | "'" [^']* "'" 9811 * 9812 * Returns the value found or NULL in case of error 9813 */ 9814static xmlChar * 9815xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 9816 const xmlChar *q; 9817 xmlChar *ret = NULL; 9818 9819 if (CUR == '"') { 9820 NEXT; 9821 q = CUR_PTR; 9822 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 9823 NEXT; 9824 if (!IS_CHAR_CH(CUR)) { 9825 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 9826 } else { 9827 ret = xmlStrndup(q, CUR_PTR - q); 9828 NEXT; 9829 } 9830 } else if (CUR == '\'') { 9831 NEXT; 9832 q = CUR_PTR; 9833 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 9834 NEXT; 9835 if (!IS_CHAR_CH(CUR)) { 9836 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); 9837 } else { 9838 ret = xmlStrndup(q, CUR_PTR - q); 9839 NEXT; 9840 } 9841 } else { 9842 XP_ERRORNULL(XPATH_START_LITERAL_ERROR); 9843 } 9844 return(ret); 9845} 9846 9847/** 9848 * xmlXPathCompLiteral: 9849 * @ctxt: the XPath Parser context 9850 * 9851 * Parse a Literal and push it on the stack. 9852 * 9853 * [29] Literal ::= '"' [^"]* '"' 9854 * | "'" [^']* "'" 9855 * 9856 * TODO: xmlXPathCompLiteral memory allocation could be improved. 9857 */ 9858static void 9859xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 9860 const xmlChar *q; 9861 xmlChar *ret = NULL; 9862 9863 if (CUR == '"') { 9864 NEXT; 9865 q = CUR_PTR; 9866 while ((IS_CHAR_CH(CUR)) && (CUR != '"')) 9867 NEXT; 9868 if (!IS_CHAR_CH(CUR)) { 9869 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 9870 } else { 9871 ret = xmlStrndup(q, CUR_PTR - q); 9872 NEXT; 9873 } 9874 } else if (CUR == '\'') { 9875 NEXT; 9876 q = CUR_PTR; 9877 while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) 9878 NEXT; 9879 if (!IS_CHAR_CH(CUR)) { 9880 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 9881 } else { 9882 ret = xmlStrndup(q, CUR_PTR - q); 9883 NEXT; 9884 } 9885 } else { 9886 XP_ERROR(XPATH_START_LITERAL_ERROR); 9887 } 9888 if (ret == NULL) return; 9889 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 9890 xmlXPathCacheNewString(ctxt->context, ret), NULL); 9891 xmlFree(ret); 9892} 9893 9894/** 9895 * xmlXPathCompVariableReference: 9896 * @ctxt: the XPath Parser context 9897 * 9898 * Parse a VariableReference, evaluate it and push it on the stack. 9899 * 9900 * The variable bindings consist of a mapping from variable names 9901 * to variable values. The value of a variable is an object, which can be 9902 * of any of the types that are possible for the value of an expression, 9903 * and may also be of additional types not specified here. 9904 * 9905 * Early evaluation is possible since: 9906 * The variable bindings [...] used to evaluate a subexpression are 9907 * always the same as those used to evaluate the containing expression. 9908 * 9909 * [36] VariableReference ::= '$' QName 9910 */ 9911static void 9912xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 9913 xmlChar *name; 9914 xmlChar *prefix; 9915 9916 SKIP_BLANKS; 9917 if (CUR != '$') { 9918 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 9919 } 9920 NEXT; 9921 name = xmlXPathParseQName(ctxt, &prefix); 9922 if (name == NULL) { 9923 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 9924 } 9925 ctxt->comp->last = -1; 9926 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 9927 name, prefix); 9928 SKIP_BLANKS; 9929 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { 9930 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR); 9931 } 9932} 9933 9934/** 9935 * xmlXPathIsNodeType: 9936 * @name: a name string 9937 * 9938 * Is the name given a NodeType one. 9939 * 9940 * [38] NodeType ::= 'comment' 9941 * | 'text' 9942 * | 'processing-instruction' 9943 * | 'node' 9944 * 9945 * Returns 1 if true 0 otherwise 9946 */ 9947int 9948xmlXPathIsNodeType(const xmlChar *name) { 9949 if (name == NULL) 9950 return(0); 9951 9952 if (xmlStrEqual(name, BAD_CAST "node")) 9953 return(1); 9954 if (xmlStrEqual(name, BAD_CAST "text")) 9955 return(1); 9956 if (xmlStrEqual(name, BAD_CAST "comment")) 9957 return(1); 9958 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 9959 return(1); 9960 return(0); 9961} 9962 9963/** 9964 * xmlXPathCompFunctionCall: 9965 * @ctxt: the XPath Parser context 9966 * 9967 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 9968 * [17] Argument ::= Expr 9969 * 9970 * Compile a function call, the evaluation of all arguments are 9971 * pushed on the stack 9972 */ 9973static void 9974xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 9975 xmlChar *name; 9976 xmlChar *prefix; 9977 int nbargs = 0; 9978 int sort = 1; 9979 9980 name = xmlXPathParseQName(ctxt, &prefix); 9981 if (name == NULL) { 9982 XP_ERROR(XPATH_EXPR_ERROR); 9983 } 9984 SKIP_BLANKS; 9985#ifdef DEBUG_EXPR 9986 if (prefix == NULL) 9987 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 9988 name); 9989 else 9990 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 9991 prefix, name); 9992#endif 9993 9994 if (CUR != '(') { 9995 XP_ERROR(XPATH_EXPR_ERROR); 9996 } 9997 NEXT; 9998 SKIP_BLANKS; 9999 10000 /* 10001 * Optimization for count(): we don't need the node-set to be sorted. 10002 */ 10003 if ((prefix == NULL) && (name[0] == 'c') && 10004 xmlStrEqual(name, BAD_CAST "count")) 10005 { 10006 sort = 0; 10007 } 10008 ctxt->comp->last = -1; 10009 if (CUR != ')') { 10010 while (CUR != 0) { 10011 int op1 = ctxt->comp->last; 10012 ctxt->comp->last = -1; 10013 xmlXPathCompileExpr(ctxt, sort); 10014 CHECK_ERROR; 10015 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 10016 nbargs++; 10017 if (CUR == ')') break; 10018 if (CUR != ',') { 10019 XP_ERROR(XPATH_EXPR_ERROR); 10020 } 10021 NEXT; 10022 SKIP_BLANKS; 10023 } 10024 } 10025 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 10026 name, prefix); 10027 NEXT; 10028 SKIP_BLANKS; 10029} 10030 10031/** 10032 * xmlXPathCompPrimaryExpr: 10033 * @ctxt: the XPath Parser context 10034 * 10035 * [15] PrimaryExpr ::= VariableReference 10036 * | '(' Expr ')' 10037 * | Literal 10038 * | Number 10039 * | FunctionCall 10040 * 10041 * Compile a primary expression. 10042 */ 10043static void 10044xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 10045 SKIP_BLANKS; 10046 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 10047 else if (CUR == '(') { 10048 NEXT; 10049 SKIP_BLANKS; 10050 xmlXPathCompileExpr(ctxt, 1); 10051 CHECK_ERROR; 10052 if (CUR != ')') { 10053 XP_ERROR(XPATH_EXPR_ERROR); 10054 } 10055 NEXT; 10056 SKIP_BLANKS; 10057 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10058 xmlXPathCompNumber(ctxt); 10059 } else if ((CUR == '\'') || (CUR == '"')) { 10060 xmlXPathCompLiteral(ctxt); 10061 } else { 10062 xmlXPathCompFunctionCall(ctxt); 10063 } 10064 SKIP_BLANKS; 10065} 10066 10067/** 10068 * xmlXPathCompFilterExpr: 10069 * @ctxt: the XPath Parser context 10070 * 10071 * [20] FilterExpr ::= PrimaryExpr 10072 * | FilterExpr Predicate 10073 * 10074 * Compile a filter expression. 10075 * Square brackets are used to filter expressions in the same way that 10076 * they are used in location paths. It is an error if the expression to 10077 * be filtered does not evaluate to a node-set. The context node list 10078 * used for evaluating the expression in square brackets is the node-set 10079 * to be filtered listed in document order. 10080 */ 10081 10082static void 10083xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 10084 xmlXPathCompPrimaryExpr(ctxt); 10085 CHECK_ERROR; 10086 SKIP_BLANKS; 10087 10088 while (CUR == '[') { 10089 xmlXPathCompPredicate(ctxt, 1); 10090 SKIP_BLANKS; 10091 } 10092 10093 10094} 10095 10096/** 10097 * xmlXPathScanName: 10098 * @ctxt: the XPath Parser context 10099 * 10100 * Trickery: parse an XML name but without consuming the input flow 10101 * Needed to avoid insanity in the parser state. 10102 * 10103 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 10104 * CombiningChar | Extender 10105 * 10106 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 10107 * 10108 * [6] Names ::= Name (S Name)* 10109 * 10110 * Returns the Name parsed or NULL 10111 */ 10112 10113static xmlChar * 10114xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 10115 int len = 0, l; 10116 int c; 10117 const xmlChar *cur; 10118 xmlChar *ret; 10119 10120 cur = ctxt->cur; 10121 10122 c = CUR_CHAR(l); 10123 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 10124 (!IS_LETTER(c) && (c != '_') && 10125 (c != ':'))) { 10126 return(NULL); 10127 } 10128 10129 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 10130 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 10131 (c == '.') || (c == '-') || 10132 (c == '_') || (c == ':') || 10133 (IS_COMBINING(c)) || 10134 (IS_EXTENDER(c)))) { 10135 len += l; 10136 NEXTL(l); 10137 c = CUR_CHAR(l); 10138 } 10139 ret = xmlStrndup(cur, ctxt->cur - cur); 10140 ctxt->cur = cur; 10141 return(ret); 10142} 10143 10144/** 10145 * xmlXPathCompPathExpr: 10146 * @ctxt: the XPath Parser context 10147 * 10148 * [19] PathExpr ::= LocationPath 10149 * | FilterExpr 10150 * | FilterExpr '/' RelativeLocationPath 10151 * | FilterExpr '//' RelativeLocationPath 10152 * 10153 * Compile a path expression. 10154 * The / operator and // operators combine an arbitrary expression 10155 * and a relative location path. It is an error if the expression 10156 * does not evaluate to a node-set. 10157 * The / operator does composition in the same way as when / is 10158 * used in a location path. As in location paths, // is short for 10159 * /descendant-or-self::node()/. 10160 */ 10161 10162static void 10163xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 10164 int lc = 1; /* Should we branch to LocationPath ? */ 10165 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 10166 10167 SKIP_BLANKS; 10168 if ((CUR == '$') || (CUR == '(') || 10169 (IS_ASCII_DIGIT(CUR)) || 10170 (CUR == '\'') || (CUR == '"') || 10171 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { 10172 lc = 0; 10173 } else if (CUR == '*') { 10174 /* relative or absolute location path */ 10175 lc = 1; 10176 } else if (CUR == '/') { 10177 /* relative or absolute location path */ 10178 lc = 1; 10179 } else if (CUR == '@') { 10180 /* relative abbreviated attribute location path */ 10181 lc = 1; 10182 } else if (CUR == '.') { 10183 /* relative abbreviated attribute location path */ 10184 lc = 1; 10185 } else { 10186 /* 10187 * Problem is finding if we have a name here whether it's: 10188 * - a nodetype 10189 * - a function call in which case it's followed by '(' 10190 * - an axis in which case it's followed by ':' 10191 * - a element name 10192 * We do an a priori analysis here rather than having to 10193 * maintain parsed token content through the recursive function 10194 * calls. This looks uglier but makes the code easier to 10195 * read/write/debug. 10196 */ 10197 SKIP_BLANKS; 10198 name = xmlXPathScanName(ctxt); 10199 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 10200#ifdef DEBUG_STEP 10201 xmlGenericError(xmlGenericErrorContext, 10202 "PathExpr: Axis\n"); 10203#endif 10204 lc = 1; 10205 xmlFree(name); 10206 } else if (name != NULL) { 10207 int len =xmlStrlen(name); 10208 10209 10210 while (NXT(len) != 0) { 10211 if (NXT(len) == '/') { 10212 /* element name */ 10213#ifdef DEBUG_STEP 10214 xmlGenericError(xmlGenericErrorContext, 10215 "PathExpr: AbbrRelLocation\n"); 10216#endif 10217 lc = 1; 10218 break; 10219 } else if (IS_BLANK_CH(NXT(len))) { 10220 /* ignore blanks */ 10221 ; 10222 } else if (NXT(len) == ':') { 10223#ifdef DEBUG_STEP 10224 xmlGenericError(xmlGenericErrorContext, 10225 "PathExpr: AbbrRelLocation\n"); 10226#endif 10227 lc = 1; 10228 break; 10229 } else if ((NXT(len) == '(')) { 10230 /* Note Type or Function */ 10231 if (xmlXPathIsNodeType(name)) { 10232#ifdef DEBUG_STEP 10233 xmlGenericError(xmlGenericErrorContext, 10234 "PathExpr: Type search\n"); 10235#endif 10236 lc = 1; 10237 } else { 10238#ifdef DEBUG_STEP 10239 xmlGenericError(xmlGenericErrorContext, 10240 "PathExpr: function call\n"); 10241#endif 10242 lc = 0; 10243 } 10244 break; 10245 } else if ((NXT(len) == '[')) { 10246 /* element name */ 10247#ifdef DEBUG_STEP 10248 xmlGenericError(xmlGenericErrorContext, 10249 "PathExpr: AbbrRelLocation\n"); 10250#endif 10251 lc = 1; 10252 break; 10253 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 10254 (NXT(len) == '=')) { 10255 lc = 1; 10256 break; 10257 } else { 10258 lc = 1; 10259 break; 10260 } 10261 len++; 10262 } 10263 if (NXT(len) == 0) { 10264#ifdef DEBUG_STEP 10265 xmlGenericError(xmlGenericErrorContext, 10266 "PathExpr: AbbrRelLocation\n"); 10267#endif 10268 /* element name */ 10269 lc = 1; 10270 } 10271 xmlFree(name); 10272 } else { 10273 /* make sure all cases are covered explicitly */ 10274 XP_ERROR(XPATH_EXPR_ERROR); 10275 } 10276 } 10277 10278 if (lc) { 10279 if (CUR == '/') { 10280 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 10281 } else { 10282 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10283 } 10284 xmlXPathCompLocationPath(ctxt); 10285 } else { 10286 xmlXPathCompFilterExpr(ctxt); 10287 CHECK_ERROR; 10288 if ((CUR == '/') && (NXT(1) == '/')) { 10289 SKIP(2); 10290 SKIP_BLANKS; 10291 10292 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 10293 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10294 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 10295 10296 xmlXPathCompRelativeLocationPath(ctxt); 10297 } else if (CUR == '/') { 10298 xmlXPathCompRelativeLocationPath(ctxt); 10299 } 10300 } 10301 SKIP_BLANKS; 10302} 10303 10304/** 10305 * xmlXPathCompUnionExpr: 10306 * @ctxt: the XPath Parser context 10307 * 10308 * [18] UnionExpr ::= PathExpr 10309 * | UnionExpr '|' PathExpr 10310 * 10311 * Compile an union expression. 10312 */ 10313 10314static void 10315xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 10316 xmlXPathCompPathExpr(ctxt); 10317 CHECK_ERROR; 10318 SKIP_BLANKS; 10319 while (CUR == '|') { 10320 int op1 = ctxt->comp->last; 10321 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 10322 10323 NEXT; 10324 SKIP_BLANKS; 10325 xmlXPathCompPathExpr(ctxt); 10326 10327 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 10328 10329 SKIP_BLANKS; 10330 } 10331} 10332 10333/** 10334 * xmlXPathCompUnaryExpr: 10335 * @ctxt: the XPath Parser context 10336 * 10337 * [27] UnaryExpr ::= UnionExpr 10338 * | '-' UnaryExpr 10339 * 10340 * Compile an unary expression. 10341 */ 10342 10343static void 10344xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 10345 int minus = 0; 10346 int found = 0; 10347 10348 SKIP_BLANKS; 10349 while (CUR == '-') { 10350 minus = 1 - minus; 10351 found = 1; 10352 NEXT; 10353 SKIP_BLANKS; 10354 } 10355 10356 xmlXPathCompUnionExpr(ctxt); 10357 CHECK_ERROR; 10358 if (found) { 10359 if (minus) 10360 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 10361 else 10362 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 10363 } 10364} 10365 10366/** 10367 * xmlXPathCompMultiplicativeExpr: 10368 * @ctxt: the XPath Parser context 10369 * 10370 * [26] MultiplicativeExpr ::= UnaryExpr 10371 * | MultiplicativeExpr MultiplyOperator UnaryExpr 10372 * | MultiplicativeExpr 'div' UnaryExpr 10373 * | MultiplicativeExpr 'mod' UnaryExpr 10374 * [34] MultiplyOperator ::= '*' 10375 * 10376 * Compile an Additive expression. 10377 */ 10378 10379static void 10380xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 10381 xmlXPathCompUnaryExpr(ctxt); 10382 CHECK_ERROR; 10383 SKIP_BLANKS; 10384 while ((CUR == '*') || 10385 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 10386 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 10387 int op = -1; 10388 int op1 = ctxt->comp->last; 10389 10390 if (CUR == '*') { 10391 op = 0; 10392 NEXT; 10393 } else if (CUR == 'd') { 10394 op = 1; 10395 SKIP(3); 10396 } else if (CUR == 'm') { 10397 op = 2; 10398 SKIP(3); 10399 } 10400 SKIP_BLANKS; 10401 xmlXPathCompUnaryExpr(ctxt); 10402 CHECK_ERROR; 10403 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 10404 SKIP_BLANKS; 10405 } 10406} 10407 10408/** 10409 * xmlXPathCompAdditiveExpr: 10410 * @ctxt: the XPath Parser context 10411 * 10412 * [25] AdditiveExpr ::= MultiplicativeExpr 10413 * | AdditiveExpr '+' MultiplicativeExpr 10414 * | AdditiveExpr '-' MultiplicativeExpr 10415 * 10416 * Compile an Additive expression. 10417 */ 10418 10419static void 10420xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 10421 10422 xmlXPathCompMultiplicativeExpr(ctxt); 10423 CHECK_ERROR; 10424 SKIP_BLANKS; 10425 while ((CUR == '+') || (CUR == '-')) { 10426 int plus; 10427 int op1 = ctxt->comp->last; 10428 10429 if (CUR == '+') plus = 1; 10430 else plus = 0; 10431 NEXT; 10432 SKIP_BLANKS; 10433 xmlXPathCompMultiplicativeExpr(ctxt); 10434 CHECK_ERROR; 10435 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 10436 SKIP_BLANKS; 10437 } 10438} 10439 10440/** 10441 * xmlXPathCompRelationalExpr: 10442 * @ctxt: the XPath Parser context 10443 * 10444 * [24] RelationalExpr ::= AdditiveExpr 10445 * | RelationalExpr '<' AdditiveExpr 10446 * | RelationalExpr '>' AdditiveExpr 10447 * | RelationalExpr '<=' AdditiveExpr 10448 * | RelationalExpr '>=' AdditiveExpr 10449 * 10450 * A <= B > C is allowed ? Answer from James, yes with 10451 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 10452 * which is basically what got implemented. 10453 * 10454 * Compile a Relational expression, then push the result 10455 * on the stack 10456 */ 10457 10458static void 10459xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 10460 xmlXPathCompAdditiveExpr(ctxt); 10461 CHECK_ERROR; 10462 SKIP_BLANKS; 10463 while ((CUR == '<') || 10464 (CUR == '>') || 10465 ((CUR == '<') && (NXT(1) == '=')) || 10466 ((CUR == '>') && (NXT(1) == '='))) { 10467 int inf, strict; 10468 int op1 = ctxt->comp->last; 10469 10470 if (CUR == '<') inf = 1; 10471 else inf = 0; 10472 if (NXT(1) == '=') strict = 0; 10473 else strict = 1; 10474 NEXT; 10475 if (!strict) NEXT; 10476 SKIP_BLANKS; 10477 xmlXPathCompAdditiveExpr(ctxt); 10478 CHECK_ERROR; 10479 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 10480 SKIP_BLANKS; 10481 } 10482} 10483 10484/** 10485 * xmlXPathCompEqualityExpr: 10486 * @ctxt: the XPath Parser context 10487 * 10488 * [23] EqualityExpr ::= RelationalExpr 10489 * | EqualityExpr '=' RelationalExpr 10490 * | EqualityExpr '!=' RelationalExpr 10491 * 10492 * A != B != C is allowed ? Answer from James, yes with 10493 * (RelationalExpr = RelationalExpr) = RelationalExpr 10494 * (RelationalExpr != RelationalExpr) != RelationalExpr 10495 * which is basically what got implemented. 10496 * 10497 * Compile an Equality expression. 10498 * 10499 */ 10500static void 10501xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 10502 xmlXPathCompRelationalExpr(ctxt); 10503 CHECK_ERROR; 10504 SKIP_BLANKS; 10505 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 10506 int eq; 10507 int op1 = ctxt->comp->last; 10508 10509 if (CUR == '=') eq = 1; 10510 else eq = 0; 10511 NEXT; 10512 if (!eq) NEXT; 10513 SKIP_BLANKS; 10514 xmlXPathCompRelationalExpr(ctxt); 10515 CHECK_ERROR; 10516 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 10517 SKIP_BLANKS; 10518 } 10519} 10520 10521/** 10522 * xmlXPathCompAndExpr: 10523 * @ctxt: the XPath Parser context 10524 * 10525 * [22] AndExpr ::= EqualityExpr 10526 * | AndExpr 'and' EqualityExpr 10527 * 10528 * Compile an AND expression. 10529 * 10530 */ 10531static void 10532xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 10533 xmlXPathCompEqualityExpr(ctxt); 10534 CHECK_ERROR; 10535 SKIP_BLANKS; 10536 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 10537 int op1 = ctxt->comp->last; 10538 SKIP(3); 10539 SKIP_BLANKS; 10540 xmlXPathCompEqualityExpr(ctxt); 10541 CHECK_ERROR; 10542 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 10543 SKIP_BLANKS; 10544 } 10545} 10546 10547/** 10548 * xmlXPathCompileExpr: 10549 * @ctxt: the XPath Parser context 10550 * 10551 * [14] Expr ::= OrExpr 10552 * [21] OrExpr ::= AndExpr 10553 * | OrExpr 'or' AndExpr 10554 * 10555 * Parse and compile an expression 10556 */ 10557static void 10558xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { 10559 xmlXPathCompAndExpr(ctxt); 10560 CHECK_ERROR; 10561 SKIP_BLANKS; 10562 while ((CUR == 'o') && (NXT(1) == 'r')) { 10563 int op1 = ctxt->comp->last; 10564 SKIP(2); 10565 SKIP_BLANKS; 10566 xmlXPathCompAndExpr(ctxt); 10567 CHECK_ERROR; 10568 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 10569 op1 = ctxt->comp->nbStep; 10570 SKIP_BLANKS; 10571 } 10572 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { 10573 /* more ops could be optimized too */ 10574 /* 10575 * This is the main place to eliminate sorting for 10576 * operations which don't require a sorted node-set. 10577 * E.g. count(). 10578 */ 10579 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 10580 } 10581} 10582 10583/** 10584 * xmlXPathCompPredicate: 10585 * @ctxt: the XPath Parser context 10586 * @filter: act as a filter 10587 * 10588 * [8] Predicate ::= '[' PredicateExpr ']' 10589 * [9] PredicateExpr ::= Expr 10590 * 10591 * Compile a predicate expression 10592 */ 10593static void 10594xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 10595 int op1 = ctxt->comp->last; 10596 10597 SKIP_BLANKS; 10598 if (CUR != '[') { 10599 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10600 } 10601 NEXT; 10602 SKIP_BLANKS; 10603 10604 ctxt->comp->last = -1; 10605 xmlXPathCompileExpr(ctxt, 1); 10606 CHECK_ERROR; 10607 10608 if (CUR != ']') { 10609 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 10610 } 10611 10612 if (filter) 10613 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 10614 else 10615 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 10616 10617 NEXT; 10618 SKIP_BLANKS; 10619} 10620 10621/** 10622 * xmlXPathCompNodeTest: 10623 * @ctxt: the XPath Parser context 10624 * @test: pointer to a xmlXPathTestVal 10625 * @type: pointer to a xmlXPathTypeVal 10626 * @prefix: placeholder for a possible name prefix 10627 * 10628 * [7] NodeTest ::= NameTest 10629 * | NodeType '(' ')' 10630 * | 'processing-instruction' '(' Literal ')' 10631 * 10632 * [37] NameTest ::= '*' 10633 * | NCName ':' '*' 10634 * | QName 10635 * [38] NodeType ::= 'comment' 10636 * | 'text' 10637 * | 'processing-instruction' 10638 * | 'node' 10639 * 10640 * Returns the name found and updates @test, @type and @prefix appropriately 10641 */ 10642static xmlChar * 10643xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 10644 xmlXPathTypeVal *type, const xmlChar **prefix, 10645 xmlChar *name) { 10646 int blanks; 10647 10648 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 10649 STRANGE; 10650 return(NULL); 10651 } 10652 *type = (xmlXPathTypeVal) 0; 10653 *test = (xmlXPathTestVal) 0; 10654 *prefix = NULL; 10655 SKIP_BLANKS; 10656 10657 if ((name == NULL) && (CUR == '*')) { 10658 /* 10659 * All elements 10660 */ 10661 NEXT; 10662 *test = NODE_TEST_ALL; 10663 return(NULL); 10664 } 10665 10666 if (name == NULL) 10667 name = xmlXPathParseNCName(ctxt); 10668 if (name == NULL) { 10669 XP_ERRORNULL(XPATH_EXPR_ERROR); 10670 } 10671 10672 blanks = IS_BLANK_CH(CUR); 10673 SKIP_BLANKS; 10674 if (CUR == '(') { 10675 NEXT; 10676 /* 10677 * NodeType or PI search 10678 */ 10679 if (xmlStrEqual(name, BAD_CAST "comment")) 10680 *type = NODE_TYPE_COMMENT; 10681 else if (xmlStrEqual(name, BAD_CAST "node")) 10682 *type = NODE_TYPE_NODE; 10683 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 10684 *type = NODE_TYPE_PI; 10685 else if (xmlStrEqual(name, BAD_CAST "text")) 10686 *type = NODE_TYPE_TEXT; 10687 else { 10688 if (name != NULL) 10689 xmlFree(name); 10690 XP_ERRORNULL(XPATH_EXPR_ERROR); 10691 } 10692 10693 *test = NODE_TEST_TYPE; 10694 10695 SKIP_BLANKS; 10696 if (*type == NODE_TYPE_PI) { 10697 /* 10698 * Specific case: search a PI by name. 10699 */ 10700 if (name != NULL) 10701 xmlFree(name); 10702 name = NULL; 10703 if (CUR != ')') { 10704 name = xmlXPathParseLiteral(ctxt); 10705 CHECK_ERROR NULL; 10706 *test = NODE_TEST_PI; 10707 SKIP_BLANKS; 10708 } 10709 } 10710 if (CUR != ')') { 10711 if (name != NULL) 10712 xmlFree(name); 10713 XP_ERRORNULL(XPATH_UNCLOSED_ERROR); 10714 } 10715 NEXT; 10716 return(name); 10717 } 10718 *test = NODE_TEST_NAME; 10719 if ((!blanks) && (CUR == ':')) { 10720 NEXT; 10721 10722 /* 10723 * Since currently the parser context don't have a 10724 * namespace list associated: 10725 * The namespace name for this prefix can be computed 10726 * only at evaluation time. The compilation is done 10727 * outside of any context. 10728 */ 10729#if 0 10730 *prefix = xmlXPathNsLookup(ctxt->context, name); 10731 if (name != NULL) 10732 xmlFree(name); 10733 if (*prefix == NULL) { 10734 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 10735 } 10736#else 10737 *prefix = name; 10738#endif 10739 10740 if (CUR == '*') { 10741 /* 10742 * All elements 10743 */ 10744 NEXT; 10745 *test = NODE_TEST_ALL; 10746 return(NULL); 10747 } 10748 10749 name = xmlXPathParseNCName(ctxt); 10750 if (name == NULL) { 10751 XP_ERRORNULL(XPATH_EXPR_ERROR); 10752 } 10753 } 10754 return(name); 10755} 10756 10757/** 10758 * xmlXPathIsAxisName: 10759 * @name: a preparsed name token 10760 * 10761 * [6] AxisName ::= 'ancestor' 10762 * | 'ancestor-or-self' 10763 * | 'attribute' 10764 * | 'child' 10765 * | 'descendant' 10766 * | 'descendant-or-self' 10767 * | 'following' 10768 * | 'following-sibling' 10769 * | 'namespace' 10770 * | 'parent' 10771 * | 'preceding' 10772 * | 'preceding-sibling' 10773 * | 'self' 10774 * 10775 * Returns the axis or 0 10776 */ 10777static xmlXPathAxisVal 10778xmlXPathIsAxisName(const xmlChar *name) { 10779 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; 10780 switch (name[0]) { 10781 case 'a': 10782 if (xmlStrEqual(name, BAD_CAST "ancestor")) 10783 ret = AXIS_ANCESTOR; 10784 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 10785 ret = AXIS_ANCESTOR_OR_SELF; 10786 if (xmlStrEqual(name, BAD_CAST "attribute")) 10787 ret = AXIS_ATTRIBUTE; 10788 break; 10789 case 'c': 10790 if (xmlStrEqual(name, BAD_CAST "child")) 10791 ret = AXIS_CHILD; 10792 break; 10793 case 'd': 10794 if (xmlStrEqual(name, BAD_CAST "descendant")) 10795 ret = AXIS_DESCENDANT; 10796 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 10797 ret = AXIS_DESCENDANT_OR_SELF; 10798 break; 10799 case 'f': 10800 if (xmlStrEqual(name, BAD_CAST "following")) 10801 ret = AXIS_FOLLOWING; 10802 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 10803 ret = AXIS_FOLLOWING_SIBLING; 10804 break; 10805 case 'n': 10806 if (xmlStrEqual(name, BAD_CAST "namespace")) 10807 ret = AXIS_NAMESPACE; 10808 break; 10809 case 'p': 10810 if (xmlStrEqual(name, BAD_CAST "parent")) 10811 ret = AXIS_PARENT; 10812 if (xmlStrEqual(name, BAD_CAST "preceding")) 10813 ret = AXIS_PRECEDING; 10814 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 10815 ret = AXIS_PRECEDING_SIBLING; 10816 break; 10817 case 's': 10818 if (xmlStrEqual(name, BAD_CAST "self")) 10819 ret = AXIS_SELF; 10820 break; 10821 } 10822 return(ret); 10823} 10824 10825/** 10826 * xmlXPathCompStep: 10827 * @ctxt: the XPath Parser context 10828 * 10829 * [4] Step ::= AxisSpecifier NodeTest Predicate* 10830 * | AbbreviatedStep 10831 * 10832 * [12] AbbreviatedStep ::= '.' | '..' 10833 * 10834 * [5] AxisSpecifier ::= AxisName '::' 10835 * | AbbreviatedAxisSpecifier 10836 * 10837 * [13] AbbreviatedAxisSpecifier ::= '@'? 10838 * 10839 * Modified for XPtr range support as: 10840 * 10841 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 10842 * | AbbreviatedStep 10843 * | 'range-to' '(' Expr ')' Predicate* 10844 * 10845 * Compile one step in a Location Path 10846 * A location step of . is short for self::node(). This is 10847 * particularly useful in conjunction with //. For example, the 10848 * location path .//para is short for 10849 * self::node()/descendant-or-self::node()/child::para 10850 * and so will select all para descendant elements of the context 10851 * node. 10852 * Similarly, a location step of .. is short for parent::node(). 10853 * For example, ../title is short for parent::node()/child::title 10854 * and so will select the title children of the parent of the context 10855 * node. 10856 */ 10857static void 10858xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 10859#ifdef LIBXML_XPTR_ENABLED 10860 int rangeto = 0; 10861 int op2 = -1; 10862#endif 10863 10864 SKIP_BLANKS; 10865 if ((CUR == '.') && (NXT(1) == '.')) { 10866 SKIP(2); 10867 SKIP_BLANKS; 10868 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 10869 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 10870 } else if (CUR == '.') { 10871 NEXT; 10872 SKIP_BLANKS; 10873 } else { 10874 xmlChar *name = NULL; 10875 const xmlChar *prefix = NULL; 10876 xmlXPathTestVal test = (xmlXPathTestVal) 0; 10877 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; 10878 xmlXPathTypeVal type = (xmlXPathTypeVal) 0; 10879 int op1; 10880 10881 /* 10882 * The modification needed for XPointer change to the production 10883 */ 10884#ifdef LIBXML_XPTR_ENABLED 10885 if (ctxt->xptr) { 10886 name = xmlXPathParseNCName(ctxt); 10887 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 10888 op2 = ctxt->comp->last; 10889 xmlFree(name); 10890 SKIP_BLANKS; 10891 if (CUR != '(') { 10892 XP_ERROR(XPATH_EXPR_ERROR); 10893 } 10894 NEXT; 10895 SKIP_BLANKS; 10896 10897 xmlXPathCompileExpr(ctxt, 1); 10898 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 10899 CHECK_ERROR; 10900 10901 SKIP_BLANKS; 10902 if (CUR != ')') { 10903 XP_ERROR(XPATH_EXPR_ERROR); 10904 } 10905 NEXT; 10906 rangeto = 1; 10907 goto eval_predicates; 10908 } 10909 } 10910#endif 10911 if (CUR == '*') { 10912 axis = AXIS_CHILD; 10913 } else { 10914 if (name == NULL) 10915 name = xmlXPathParseNCName(ctxt); 10916 if (name != NULL) { 10917 axis = xmlXPathIsAxisName(name); 10918 if (axis != 0) { 10919 SKIP_BLANKS; 10920 if ((CUR == ':') && (NXT(1) == ':')) { 10921 SKIP(2); 10922 xmlFree(name); 10923 name = NULL; 10924 } else { 10925 /* an element name can conflict with an axis one :-\ */ 10926 axis = AXIS_CHILD; 10927 } 10928 } else { 10929 axis = AXIS_CHILD; 10930 } 10931 } else if (CUR == '@') { 10932 NEXT; 10933 axis = AXIS_ATTRIBUTE; 10934 } else { 10935 axis = AXIS_CHILD; 10936 } 10937 } 10938 10939 CHECK_ERROR; 10940 10941 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 10942 if (test == 0) 10943 return; 10944 10945 if ((prefix != NULL) && (ctxt->context != NULL) && 10946 (ctxt->context->flags & XML_XPATH_CHECKNS)) { 10947 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { 10948 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); 10949 } 10950 } 10951#ifdef DEBUG_STEP 10952 xmlGenericError(xmlGenericErrorContext, 10953 "Basis : computing new set\n"); 10954#endif 10955 10956#ifdef DEBUG_STEP 10957 xmlGenericError(xmlGenericErrorContext, "Basis : "); 10958 if (ctxt->value == NULL) 10959 xmlGenericError(xmlGenericErrorContext, "no value\n"); 10960 else if (ctxt->value->nodesetval == NULL) 10961 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 10962 else 10963 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 10964#endif 10965 10966#ifdef LIBXML_XPTR_ENABLED 10967eval_predicates: 10968#endif 10969 op1 = ctxt->comp->last; 10970 ctxt->comp->last = -1; 10971 10972 SKIP_BLANKS; 10973 while (CUR == '[') { 10974 xmlXPathCompPredicate(ctxt, 0); 10975 } 10976 10977#ifdef LIBXML_XPTR_ENABLED 10978 if (rangeto) { 10979 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 10980 } else 10981#endif 10982 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 10983 test, type, (void *)prefix, (void *)name); 10984 10985 } 10986#ifdef DEBUG_STEP 10987 xmlGenericError(xmlGenericErrorContext, "Step : "); 10988 if (ctxt->value == NULL) 10989 xmlGenericError(xmlGenericErrorContext, "no value\n"); 10990 else if (ctxt->value->nodesetval == NULL) 10991 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 10992 else 10993 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 10994 ctxt->value->nodesetval); 10995#endif 10996} 10997 10998/** 10999 * xmlXPathCompRelativeLocationPath: 11000 * @ctxt: the XPath Parser context 11001 * 11002 * [3] RelativeLocationPath ::= Step 11003 * | RelativeLocationPath '/' Step 11004 * | AbbreviatedRelativeLocationPath 11005 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 11006 * 11007 * Compile a relative location path. 11008 */ 11009static void 11010xmlXPathCompRelativeLocationPath 11011(xmlXPathParserContextPtr ctxt) { 11012 SKIP_BLANKS; 11013 if ((CUR == '/') && (NXT(1) == '/')) { 11014 SKIP(2); 11015 SKIP_BLANKS; 11016 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11017 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11018 } else if (CUR == '/') { 11019 NEXT; 11020 SKIP_BLANKS; 11021 } 11022 xmlXPathCompStep(ctxt); 11023 SKIP_BLANKS; 11024 while (CUR == '/') { 11025 if ((CUR == '/') && (NXT(1) == '/')) { 11026 SKIP(2); 11027 SKIP_BLANKS; 11028 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11029 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11030 xmlXPathCompStep(ctxt); 11031 } else if (CUR == '/') { 11032 NEXT; 11033 SKIP_BLANKS; 11034 xmlXPathCompStep(ctxt); 11035 } 11036 SKIP_BLANKS; 11037 } 11038} 11039 11040/** 11041 * xmlXPathCompLocationPath: 11042 * @ctxt: the XPath Parser context 11043 * 11044 * [1] LocationPath ::= RelativeLocationPath 11045 * | AbsoluteLocationPath 11046 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 11047 * | AbbreviatedAbsoluteLocationPath 11048 * [10] AbbreviatedAbsoluteLocationPath ::= 11049 * '//' RelativeLocationPath 11050 * 11051 * Compile a location path 11052 * 11053 * // is short for /descendant-or-self::node()/. For example, 11054 * //para is short for /descendant-or-self::node()/child::para and 11055 * so will select any para element in the document (even a para element 11056 * that is a document element will be selected by //para since the 11057 * document element node is a child of the root node); div//para is 11058 * short for div/descendant-or-self::node()/child::para and so will 11059 * select all para descendants of div children. 11060 */ 11061static void 11062xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 11063 SKIP_BLANKS; 11064 if (CUR != '/') { 11065 xmlXPathCompRelativeLocationPath(ctxt); 11066 } else { 11067 while (CUR == '/') { 11068 if ((CUR == '/') && (NXT(1) == '/')) { 11069 SKIP(2); 11070 SKIP_BLANKS; 11071 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 11072 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 11073 xmlXPathCompRelativeLocationPath(ctxt); 11074 } else if (CUR == '/') { 11075 NEXT; 11076 SKIP_BLANKS; 11077 if ((CUR != 0 ) && 11078 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 11079 (CUR == '@') || (CUR == '*'))) 11080 xmlXPathCompRelativeLocationPath(ctxt); 11081 } 11082 } 11083 } 11084} 11085 11086/************************************************************************ 11087 * * 11088 * XPath precompiled expression evaluation * 11089 * * 11090 ************************************************************************/ 11091 11092static int 11093xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 11094 11095/** 11096 * xmlXPathNodeCollectAndTest: 11097 * @ctxt: the XPath Parser context 11098 * @op: the XPath precompiled step operation 11099 * @first: pointer to the first element in document order 11100 * @last: pointer to the last element in document order 11101 * 11102 * This is the function implementing a step: based on the current list 11103 * of nodes, it builds up a new list, looking at all nodes under that 11104 * axis and selecting them. It also does the predicate filtering 11105 * 11106 * Pushes the new NodeSet resulting from the search. 11107 * 11108 * Returns the number of nodes traversed 11109 */ 11110static int 11111xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 11112 xmlXPathStepOpPtr op, 11113 xmlNodePtr * first, xmlNodePtr * last) 11114{ 11115 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 11116 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 11117 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 11118 const xmlChar *prefix = op->value4; 11119 const xmlChar *name = op->value5; 11120 const xmlChar *URI = NULL; 11121 11122#ifdef DEBUG_STEP 11123 int nbMatches = 0; 11124#endif 11125 int inputIdx, total = 0, specialNodeInSet = 0; 11126 xmlNodeSetPtr inputList, resultList, list; 11127 xmlXPathTraversalFunction next = NULL; 11128 xmlXPathTraversalFunctionExt compoundNext = NULL; 11129 void (*addNode) (xmlNodeSetPtr, xmlNodePtr); 11130 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr); 11131 xmlNodePtr oldContextNode, contextNode, cur, compoundContextNode; 11132 xmlXPathObjectPtr obj; 11133 xmlXPathContextPtr xpctxt = ctxt->context; 11134 11135 CHECK_TYPE0(XPATH_NODESET); 11136 obj = valuePop(ctxt); 11137 11138 /* 11139 * Setup wrt namespaces. 11140 */ 11141 if (prefix != NULL) { 11142 URI = xmlXPathNsLookup(xpctxt, prefix); 11143 if (URI == NULL) { 11144 xmlXPathFreeObject(obj); 11145 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11146 } 11147 } 11148 11149#ifdef DEBUG_STEP 11150 xmlGenericError(xmlGenericErrorContext, "new step : "); 11151#endif 11152 11153 /* 11154 * Setup wrt the axis. 11155 */ 11156 addNode = xmlXPathNodeSetAdd; 11157 mergeNodeSet = xmlXPathNodeSetMerge; 11158 switch (axis) { 11159 case AXIS_ANCESTOR: 11160#ifdef DEBUG_STEP 11161 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11162#endif 11163 first = NULL; 11164 next = xmlXPathNextAncestor; 11165 break; 11166 case AXIS_ANCESTOR_OR_SELF: 11167#ifdef DEBUG_STEP 11168 xmlGenericError(xmlGenericErrorContext, 11169 "axis 'ancestors-or-self' "); 11170#endif 11171 first = NULL; 11172 next = xmlXPathNextAncestorOrSelf; 11173 break; 11174 case AXIS_ATTRIBUTE: 11175#ifdef DEBUG_STEP 11176 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11177#endif 11178 first = NULL; 11179 last = NULL; 11180 next = xmlXPathNextAttribute; 11181 mergeNodeSet = xmlXPathNodeSetMergeUnique; 11182 break; 11183 case AXIS_CHILD: 11184#ifdef DEBUG_STEP 11185 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11186#endif 11187 last = NULL; 11188 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) { 11189 /* 11190 * This iterator will give us only nodes which can 11191 * hold element nodes. 11192 */ 11193 compoundNext = xmlXPathNextDescendantOrSelfElemParent; 11194 } 11195 if ((test == NODE_TEST_NAME) && (type == NODE_TYPE_NODE)) { 11196 /* 11197 * Optimization if an element node type is 'element'. 11198 */ 11199 next = xmlXPathNextChildElement; 11200 } else 11201 next = xmlXPathNextChild; 11202 mergeNodeSet = xmlXPathNodeSetMergeUnique; 11203 break; 11204 case AXIS_DESCENDANT: 11205#ifdef DEBUG_STEP 11206 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11207#endif 11208 last = NULL; 11209 next = xmlXPathNextDescendant; 11210 break; 11211 case AXIS_DESCENDANT_OR_SELF: 11212#ifdef DEBUG_STEP 11213 xmlGenericError(xmlGenericErrorContext, 11214 "axis 'descendant-or-self' "); 11215#endif 11216 last = NULL; 11217 next = xmlXPathNextDescendantOrSelf; 11218 break; 11219 case AXIS_FOLLOWING: 11220#ifdef DEBUG_STEP 11221 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11222#endif 11223 last = NULL; 11224 next = xmlXPathNextFollowing; 11225 break; 11226 case AXIS_FOLLOWING_SIBLING: 11227#ifdef DEBUG_STEP 11228 xmlGenericError(xmlGenericErrorContext, 11229 "axis 'following-siblings' "); 11230#endif 11231 last = NULL; 11232 next = xmlXPathNextFollowingSibling; 11233 break; 11234 case AXIS_NAMESPACE: 11235#ifdef DEBUG_STEP 11236 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11237#endif 11238 first = NULL; 11239 last = NULL; 11240 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 11241 mergeNodeSet = xmlXPathNodeSetMergeUnique; 11242 break; 11243 case AXIS_PARENT: 11244#ifdef DEBUG_STEP 11245 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11246#endif 11247 first = NULL; 11248 next = xmlXPathNextParent; 11249 break; 11250 case AXIS_PRECEDING: 11251#ifdef DEBUG_STEP 11252 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11253#endif 11254 first = NULL; 11255 next = xmlXPathNextPrecedingInternal; 11256 break; 11257 case AXIS_PRECEDING_SIBLING: 11258#ifdef DEBUG_STEP 11259 xmlGenericError(xmlGenericErrorContext, 11260 "axis 'preceding-sibling' "); 11261#endif 11262 first = NULL; 11263 next = xmlXPathNextPrecedingSibling; 11264 break; 11265 case AXIS_SELF: 11266#ifdef DEBUG_STEP 11267 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11268#endif 11269 first = NULL; 11270 last = NULL; 11271 next = xmlXPathNextSelf; 11272 mergeNodeSet = xmlXPathNodeSetMergeUnique; 11273 break; 11274 } 11275 if (next == NULL) { 11276 xmlXPathReleaseObject(xpctxt, obj); 11277 return(0); 11278 } 11279 11280 inputList = obj->nodesetval; 11281 if ((inputList == NULL) || (inputList->nodeNr <= 0)) { 11282 xmlXPathReleaseObject(xpctxt, obj); 11283 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 11284 return(0); 11285 } 11286 11287#ifdef DEBUG_STEP 11288 xmlGenericError(xmlGenericErrorContext, 11289 " context contains %d nodes\n", nodelist->nodeNr); 11290 switch (test) { 11291 case NODE_TEST_NONE: 11292 xmlGenericError(xmlGenericErrorContext, 11293 " searching for none !!!\n"); 11294 break; 11295 case NODE_TEST_TYPE: 11296 xmlGenericError(xmlGenericErrorContext, 11297 " searching for type %d\n", type); 11298 break; 11299 case NODE_TEST_PI: 11300 xmlGenericError(xmlGenericErrorContext, 11301 " searching for PI !!!\n"); 11302 break; 11303 case NODE_TEST_ALL: 11304 xmlGenericError(xmlGenericErrorContext, 11305 " searching for *\n"); 11306 break; 11307 case NODE_TEST_NS: 11308 xmlGenericError(xmlGenericErrorContext, 11309 " searching for namespace %s\n", 11310 prefix); 11311 break; 11312 case NODE_TEST_NAME: 11313 xmlGenericError(xmlGenericErrorContext, 11314 " searching for name %s\n", name); 11315 if (prefix != NULL) 11316 xmlGenericError(xmlGenericErrorContext, 11317 " with namespace %s\n", prefix); 11318 break; 11319 } 11320 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11321#endif 11322 /* 11323 * 2.3 Node Tests 11324 * - For the attribute axis, the principal node type is attribute. 11325 * - For the namespace axis, the principal node type is namespace. 11326 * - For other axes, the principal node type is element. 11327 * 11328 * A node test * is true for any node of the 11329 * principal node type. For example, child::* will 11330 * select all element children of the context node 11331 */ 11332 oldContextNode = xpctxt->node; 11333 addNode = xmlXPathNodeSetAddUnique; 11334 resultList = NULL; 11335 list = NULL; 11336 compoundContextNode = NULL; 11337 contextNode = NULL; 11338 inputIdx = 0; 11339 11340 while ((inputIdx < inputList->nodeNr) || (contextNode != NULL)) { 11341 if (compoundNext != NULL) { 11342 /* 11343 * This is a compound traversal. 11344 */ 11345 if (contextNode == NULL) { 11346 /* 11347 * Set the context for the initial traversal. 11348 */ 11349 compoundContextNode = inputList->nodeTab[inputIdx++]; 11350 contextNode = compoundNext(NULL, compoundContextNode); 11351 } else 11352 contextNode = compoundNext(contextNode, compoundContextNode); 11353 if (contextNode == NULL) 11354 continue; 11355 /* 11356 * Set the context for the main traversal. 11357 */ 11358 xpctxt->node = contextNode; 11359 } else 11360 xpctxt->node = inputList->nodeTab[inputIdx++]; 11361 11362 if (list == NULL) { 11363 list = xmlXPathNodeSetCreate(NULL); 11364 if (list == NULL) { 11365 total = 0; 11366 goto error; 11367 } 11368 } 11369 cur = NULL; 11370 specialNodeInSet = 0; 11371 do { 11372 cur = next(ctxt, cur); 11373 if (cur == NULL) 11374 break; 11375 11376 if (first != NULL) { 11377 if (*first == cur) 11378 break; 11379 if ((*first != NULL) && 11380 ((total % 256) == 0) && 11381#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 11382 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 11383#else 11384 (xmlXPathCmpNodes(*first, cur) >= 0)) 11385#endif 11386 { 11387 break; 11388 } 11389 } 11390 if (last != NULL) { 11391 if (*last == cur) 11392 break; 11393 if ((*last != NULL) && 11394 ((total % 256) == 0) && 11395#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 11396 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 11397#else 11398 (xmlXPathCmpNodes(cur, *last) >= 0)) 11399#endif 11400 { 11401 break; 11402 } 11403 } 11404 11405 total++; 11406#ifdef DEBUG_STEP 11407 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 11408#endif 11409 switch (test) { 11410 case NODE_TEST_NONE: 11411 STRANGE 11412 goto error; 11413 case NODE_TEST_TYPE: 11414 if ((cur->type == type) || 11415 ((type == NODE_TYPE_NODE) && 11416 ((cur->type == XML_DOCUMENT_NODE) || 11417 (cur->type == XML_HTML_DOCUMENT_NODE) || 11418 (cur->type == XML_ELEMENT_NODE) || 11419 (cur->type == XML_NAMESPACE_DECL) || 11420 (cur->type == XML_ATTRIBUTE_NODE) || 11421 (cur->type == XML_PI_NODE) || 11422 (cur->type == XML_COMMENT_NODE) || 11423 (cur->type == XML_CDATA_SECTION_NODE) || 11424 (cur->type == XML_TEXT_NODE))) || 11425 ((type == NODE_TYPE_TEXT) && 11426 (cur->type == XML_CDATA_SECTION_NODE))) 11427 { 11428#ifdef DEBUG_STEP 11429 nbMatches++; 11430#endif 11431 if (cur->type == XML_NAMESPACE_DECL) 11432 specialNodeInSet = 1; 11433 /* 11434 * TODO: Don't we need to use xmlXPathNodeSetAddNs() 11435 * for namespace nodes here ? 11436 */ 11437 addNode(list, cur); 11438 } 11439 break; 11440 case NODE_TEST_PI: 11441 if ((cur->type == XML_PI_NODE) && 11442 ((name == NULL) || xmlStrEqual(name, cur->name))) 11443 { 11444#ifdef DEBUG_STEP 11445 nbMatches++; 11446#endif 11447 addNode(list, cur); 11448 } 11449 break; 11450 case NODE_TEST_ALL: 11451 if (axis == AXIS_ATTRIBUTE) { 11452 if (cur->type == XML_ATTRIBUTE_NODE) { 11453#ifdef DEBUG_STEP 11454 nbMatches++; 11455#endif 11456 addNode(list, cur); 11457 } 11458 } else if (axis == AXIS_NAMESPACE) { 11459 if (cur->type == XML_NAMESPACE_DECL) { 11460#ifdef DEBUG_STEP 11461 nbMatches++; 11462#endif 11463 specialNodeInSet = 1; 11464 xmlXPathNodeSetAddNs(list, xpctxt->node, 11465 (xmlNsPtr) cur); 11466 } 11467 } else { 11468 if (cur->type == XML_ELEMENT_NODE) { 11469 if (prefix == NULL) { 11470#ifdef DEBUG_STEP 11471 nbMatches++; 11472#endif 11473 addNode(list, cur); 11474 } else if ((cur->ns != NULL) && 11475 (xmlStrEqual(URI, cur->ns->href))) 11476 { 11477#ifdef DEBUG_STEP 11478 nbMatches++; 11479#endif 11480 addNode(list, cur); 11481 } 11482 } 11483 } 11484 break; 11485 case NODE_TEST_NS:{ 11486 TODO; 11487 break; 11488 } 11489 case NODE_TEST_NAME: 11490 switch (cur->type) { 11491 case XML_ELEMENT_NODE: 11492 if (xmlStrEqual(name, cur->name)) { 11493 if (prefix == NULL) { 11494 if (cur->ns == NULL) { 11495#ifdef DEBUG_STEP 11496 nbMatches++; 11497#endif 11498 addNode(list, cur); 11499 } 11500 } else { 11501 if ((cur->ns != NULL) && 11502 (xmlStrEqual(URI, 11503 cur->ns->href))) 11504 { 11505#ifdef DEBUG_STEP 11506 nbMatches++; 11507#endif 11508 addNode(list, cur); 11509 } 11510 } 11511 } 11512 break; 11513 case XML_ATTRIBUTE_NODE:{ 11514 xmlAttrPtr attr = (xmlAttrPtr) cur; 11515 11516 if (xmlStrEqual(name, attr->name)) { 11517 if (prefix == NULL) { 11518 if ((attr->ns == NULL) || 11519 (attr->ns->prefix == NULL)) { 11520#ifdef DEBUG_STEP 11521 nbMatches++; 11522#endif 11523 addNode(list, 11524 (xmlNodePtr) attr); 11525 } 11526 } else { 11527 if ((attr->ns != NULL) && 11528 (xmlStrEqual(URI, 11529 attr->ns-> 11530 href))) 11531 { 11532#ifdef DEBUG_STEP 11533 nbMatches++; 11534#endif 11535 addNode(list, 11536 (xmlNodePtr) attr); 11537 } 11538 } 11539 } 11540 break; 11541 } 11542 case XML_NAMESPACE_DECL: 11543 if (cur->type == XML_NAMESPACE_DECL) { 11544 xmlNsPtr ns = (xmlNsPtr) cur; 11545 11546 if ((ns->prefix != NULL) && (name != NULL) 11547 && (xmlStrEqual(ns->prefix, name))) 11548 { 11549#ifdef DEBUG_STEP 11550 nbMatches++; 11551#endif 11552 specialNodeInSet = 1; 11553 xmlXPathNodeSetAddNs(list, 11554 xpctxt->node, (xmlNsPtr) cur); 11555 } 11556 } 11557 break; 11558 default: 11559 break; 11560 } /* switch (cur->type) */ 11561 break; /* case NODE_TEST_NAME: */ 11562 } /* switch (test) */ 11563 } while (cur != NULL); 11564 11565 /* 11566 * If there is some predicate filtering do it now 11567 */ 11568 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) { 11569 xmlXPathObjectPtr obj2; 11570 11571 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, list)); 11572 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]); 11573 CHECK_TYPE0(XPATH_NODESET); 11574 obj2 = valuePop(ctxt); 11575 list = obj2->nodesetval; 11576 obj2->nodesetval = NULL; 11577 xmlXPathReleaseObject(xpctxt, obj2); 11578 11579 if (ctxt->error != XPATH_EXPRESSION_OK) { 11580 total = 0; 11581 goto error; 11582 } 11583 } 11584 if (resultList == NULL) { 11585 resultList = list; 11586 list = NULL; 11587 } else if ((list != NULL) && (list->nodeNr > 0)) { 11588 resultList = mergeNodeSet(resultList, list); 11589 /* 11590 * This is the list containing the current matching nodes. 11591 * Avoid massive creation/freeing and preserve it for the 11592 * next iterations. 11593 */ 11594 /* If a namespace node was put it, then we need a more 11595 * time consuming cleanup. 11596 */ 11597 if (specialNodeInSet) 11598 xmlXPathNodeSetClear(list); 11599 else 11600 list->nodeNr = 0; 11601 } 11602 } 11603 11604 xpctxt->node = oldContextNode; 11605 /* 11606 * Cleanup the temporary list of current node-test matches. 11607 */ 11608 if ((list != NULL) && (list != resultList)) { 11609 xmlXPathFreeNodeSet(list); 11610 list = NULL; 11611 } 11612 11613#ifdef DEBUG_STEP 11614 xmlGenericError(xmlGenericErrorContext, 11615 "\nExamined %d nodes, found %d nodes at that step\n", 11616 total, nbMatches); 11617#endif 11618 11619 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, resultList)); 11620 11621 if ((obj->boolval) && (obj->user != NULL)) { 11622 /* 11623 * QUESTION TODO: What does this do and why? 11624 */ 11625 ctxt->value->boolval = 1; 11626 ctxt->value->user = obj->user; 11627 obj->user = NULL; 11628 obj->boolval = 0; 11629 } 11630 xmlXPathReleaseObject(xpctxt, obj); 11631 return(total); 11632 11633error: 11634 xpctxt->node = oldContextNode; 11635 xmlXPathReleaseObject(xpctxt, obj); 11636 if ((list != NULL) && (list != resultList)) { 11637 xmlXPathFreeNodeSet(list); 11638 } 11639 if (resultList != NULL) 11640 xmlXPathFreeNodeSet(resultList); 11641 return(total); 11642} 11643 11644/** 11645 * xmlXPathNodeCollectAndTestNth: 11646 * @ctxt: the XPath Parser context 11647 * @op: the XPath precompiled step operation 11648 * @reqpos: the requested position wrt to the axis 11649 * @first: pointer to the first element in document order 11650 * @last: pointer to the last element in document order 11651 * 11652 * This is the function implementing a step: based on the current list 11653 * of nodes, it builds up a new list, looking at all nodes under that 11654 * axis and selecting them. It also does the predicate filtering 11655 * 11656 * Pushes the new NodeSet resulting from the search. 11657 * Returns the number of node traversed 11658 */ 11659static int 11660xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt, 11661 xmlXPathStepOpPtr op, int reqpos, 11662 xmlNodePtr * first, xmlNodePtr * last) 11663{ 11664 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; 11665 xmlXPathTestVal test = (xmlXPathTestVal) op->value2; 11666 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; 11667 const xmlChar *prefix = op->value4; 11668 const xmlChar *name = op->value5; 11669 const xmlChar *URI = NULL; 11670 int pos; /* The current context position */ 11671 11672 int inputIdx, total = 0; 11673 xmlNodeSetPtr inputList, list; 11674 xmlXPathTraversalFunction next = NULL; 11675 xmlXPathTraversalFunctionExt compoundNext = NULL; 11676 void (*addNode) (xmlNodeSetPtr, xmlNodePtr); 11677 xmlNodePtr oldContextNode, contextNode, cur, compoundContextNode; 11678 xmlXPathObjectPtr obj; 11679 xmlXPathContextPtr xpctxt = ctxt->context; 11680 11681 11682 CHECK_TYPE0(XPATH_NODESET); 11683 obj = valuePop(ctxt); 11684 addNode = xmlXPathNodeSetAdd; 11685 11686 if (prefix != NULL) { 11687 URI = xmlXPathNsLookup(xpctxt, prefix); 11688 if (URI == NULL) { 11689 xmlXPathFreeObject(obj); 11690 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 11691 } 11692 } 11693 11694#ifdef DEBUG_STEP_NTH 11695 xmlGenericError(xmlGenericErrorContext, "new step : "); 11696 if (first != NULL) { 11697 if (*first != NULL) 11698 xmlGenericError(xmlGenericErrorContext, "first = %s ", 11699 (*first)->name); 11700 else 11701 xmlGenericError(xmlGenericErrorContext, "first = NULL "); 11702 } 11703 if (last != NULL) { 11704 if (*last != NULL) 11705 xmlGenericError(xmlGenericErrorContext, "last = %s ", 11706 (*last)->name); 11707 else 11708 xmlGenericError(xmlGenericErrorContext, "last = NULL "); 11709 } 11710#endif 11711 switch (axis) { 11712 case AXIS_ANCESTOR: 11713#ifdef DEBUG_STEP_NTH 11714 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 11715#endif 11716 first = NULL; 11717 next = xmlXPathNextAncestor; 11718 break; 11719 case AXIS_ANCESTOR_OR_SELF: 11720#ifdef DEBUG_STEP_NTH 11721 xmlGenericError(xmlGenericErrorContext, 11722 "axis 'ancestors-or-self' "); 11723#endif 11724 first = NULL; 11725 next = xmlXPathNextAncestorOrSelf; 11726 break; 11727 case AXIS_ATTRIBUTE: 11728#ifdef DEBUG_STEP_NTH 11729 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 11730#endif 11731 first = NULL; 11732 last = NULL; 11733 next = xmlXPathNextAttribute; 11734 break; 11735 case AXIS_CHILD: 11736#ifdef DEBUG_STEP_NTH 11737 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 11738#endif 11739 last = NULL; 11740 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) { 11741 /* 11742 * This iterator will give us only nodes which can 11743 * hold element nodes. 11744 */ 11745 compoundNext = xmlXPathNextDescendantOrSelfElemParent; 11746 } 11747 if ((test == NODE_TEST_NAME) && (type == NODE_TYPE_NODE)) { 11748 /* 11749 * Optimization if an element node type is 'element'. 11750 */ 11751 next = xmlXPathNextChildElement; 11752 } else 11753 next = xmlXPathNextChild; 11754 break; 11755 case AXIS_DESCENDANT: 11756#ifdef DEBUG_STEP_NTH 11757 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 11758#endif 11759 last = NULL; 11760 next = xmlXPathNextDescendant; 11761 break; 11762 case AXIS_DESCENDANT_OR_SELF: 11763#ifdef DEBUG_STEP_NTH 11764 xmlGenericError(xmlGenericErrorContext, 11765 "axis 'descendant-or-self' "); 11766#endif 11767 last = NULL; 11768 next = xmlXPathNextDescendantOrSelf; 11769 break; 11770 case AXIS_FOLLOWING: 11771#ifdef DEBUG_STEP_NTH 11772 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 11773#endif 11774 last = NULL; 11775 next = xmlXPathNextFollowing; 11776 break; 11777 case AXIS_FOLLOWING_SIBLING: 11778#ifdef DEBUG_STEP_NTH 11779 xmlGenericError(xmlGenericErrorContext, 11780 "axis 'following-siblings' "); 11781#endif 11782 last = NULL; 11783 next = xmlXPathNextFollowingSibling; 11784 break; 11785 case AXIS_NAMESPACE: 11786#ifdef DEBUG_STEP_NTH 11787 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 11788#endif 11789 last = NULL; 11790 first = NULL; 11791 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 11792 break; 11793 case AXIS_PARENT: 11794#ifdef DEBUG_STEP_NTH 11795 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 11796#endif 11797 first = NULL; 11798 next = xmlXPathNextParent; 11799 break; 11800 case AXIS_PRECEDING: 11801#ifdef DEBUG_STEP_NTH 11802 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 11803#endif 11804 first = NULL; 11805 next = xmlXPathNextPrecedingInternal; 11806 break; 11807 case AXIS_PRECEDING_SIBLING: 11808#ifdef DEBUG_STEP_NTH 11809 xmlGenericError(xmlGenericErrorContext, 11810 "axis 'preceding-sibling' "); 11811#endif 11812 first = NULL; 11813 next = xmlXPathNextPrecedingSibling; 11814 break; 11815 case AXIS_SELF: 11816#ifdef DEBUG_STEP_NTH 11817 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 11818#endif 11819 first = NULL; 11820 last = NULL; 11821 next = xmlXPathNextSelf; 11822 break; 11823 } 11824 if (next == NULL) { 11825 xmlXPathReleaseObject(xpctxt, obj); 11826 return(0); 11827 } 11828 11829 inputList = obj->nodesetval; 11830 if ((inputList == NULL) || (inputList->nodeNr <= 0)) { 11831 xmlXPathReleaseObject(xpctxt, obj); 11832 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); 11833 return(0); 11834 } 11835 11836#ifdef DEBUG_STEP_NTH 11837 xmlGenericError(xmlGenericErrorContext, 11838 " context contains %d nodes\n", nodelist->nodeNr); 11839 switch (test) { 11840 case NODE_TEST_NONE: 11841 xmlGenericError(xmlGenericErrorContext, 11842 " searching for none !!!\n"); 11843 break; 11844 case NODE_TEST_TYPE: 11845 xmlGenericError(xmlGenericErrorContext, 11846 " searching for type %d\n", type); 11847 break; 11848 case NODE_TEST_PI: 11849 xmlGenericError(xmlGenericErrorContext, 11850 " searching for PI !!!\n"); 11851 break; 11852 case NODE_TEST_ALL: 11853 xmlGenericError(xmlGenericErrorContext, 11854 " searching for *\n"); 11855 break; 11856 case NODE_TEST_NS: 11857 xmlGenericError(xmlGenericErrorContext, 11858 " searching for namespace %s\n", 11859 prefix); 11860 break; 11861 case NODE_TEST_NAME: 11862 xmlGenericError(xmlGenericErrorContext, 11863 " searching for name %s\n", name); 11864 if (prefix != NULL) 11865 xmlGenericError(xmlGenericErrorContext, 11866 " with namespace %s\n", prefix); 11867 break; 11868 } 11869 xmlGenericError(xmlGenericErrorContext, "Testing : "); 11870#endif 11871 /* 11872 * 2.3 Node Tests 11873 * - For the attribute axis, the principal node type is attribute. 11874 * - For the namespace axis, the principal node type is namespace. 11875 * - For other axes, the principal node type is element. 11876 * 11877 * A node test * is true for any node of the 11878 * principal node type. For example, child::* will 11879 * select all element children of the context node 11880 */ 11881 oldContextNode = xpctxt->node; 11882 addNode = xmlXPathNodeSetAddUnique; 11883 list = NULL; 11884 compoundContextNode = NULL; 11885 contextNode = NULL; 11886 inputIdx = 0; 11887 list = xmlXPathNodeSetCreate(NULL); 11888 11889 while ((inputIdx < inputList->nodeNr) || (contextNode != NULL)) { 11890 if (compoundNext != NULL) { 11891 /* 11892 * This is a compound traversal. 11893 */ 11894 if (contextNode == NULL) { 11895 /* 11896 * Set the context for the initial traversal. 11897 */ 11898 compoundContextNode = inputList->nodeTab[inputIdx++]; 11899 contextNode = compoundNext(NULL, compoundContextNode); 11900 } else 11901 contextNode = compoundNext(contextNode, compoundContextNode); 11902 if (contextNode == NULL) 11903 continue; 11904 /* 11905 * Set the context for the main traversal. 11906 */ 11907 xpctxt->node = contextNode; 11908 } else 11909 xpctxt->node = inputList->nodeTab[inputIdx++]; 11910 11911 cur = NULL; 11912 pos = 0; 11913 do { 11914 cur = next(ctxt, cur); 11915 if (cur == NULL) 11916 break; 11917 11918 if (first != NULL) { 11919 if (*first == cur) 11920 break; 11921 if ((*first != NULL) && 11922 ((total % 256) == 0) && 11923#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 11924 (xmlXPathCmpNodesExt(*first, cur) >= 0)) 11925#else 11926 (xmlXPathCmpNodes(*first, cur) >= 0)) 11927#endif 11928 { 11929 break; 11930 } 11931 } 11932 if (last != NULL) { 11933 if (*last == cur) 11934 break; 11935 if ((*last != NULL) && 11936 ((total % 256) == 0) && 11937#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 11938 (xmlXPathCmpNodesExt(cur, *last) >= 0)) 11939#else 11940 (xmlXPathCmpNodes(cur, *last) >= 0)) 11941#endif 11942 { 11943 break; 11944 } 11945 } 11946 11947 total++; 11948 switch (test) { 11949 case NODE_TEST_NONE: 11950 total = 0; 11951 STRANGE 11952 goto error; 11953 case NODE_TEST_TYPE: 11954 if ((cur->type == type) || 11955 ((type == NODE_TYPE_NODE) && 11956 ((cur->type == XML_DOCUMENT_NODE) || 11957 (cur->type == XML_HTML_DOCUMENT_NODE) || 11958 (cur->type == XML_ELEMENT_NODE) || 11959 (cur->type == XML_PI_NODE) || 11960 (cur->type == XML_COMMENT_NODE) || 11961 (cur->type == XML_CDATA_SECTION_NODE) || 11962 (cur->type == XML_TEXT_NODE))) || 11963 ((type == NODE_TYPE_TEXT) && 11964 (cur->type == XML_CDATA_SECTION_NODE))) { 11965 pos++; 11966 if (pos == reqpos) 11967 addNode(list, cur); 11968 } 11969 break; 11970 case NODE_TEST_PI: 11971 if (cur->type == XML_PI_NODE) { 11972 if ((name != NULL) && 11973 (!xmlStrEqual(name, cur->name))) 11974 break; 11975 pos++; 11976 if (pos == reqpos) 11977 addNode(list, cur); 11978 } 11979 break; 11980 case NODE_TEST_ALL: 11981 if (axis == AXIS_ATTRIBUTE) { 11982 if (cur->type == XML_ATTRIBUTE_NODE) { 11983 pos++; 11984 if (pos == reqpos) 11985 addNode(list, cur); 11986 } 11987 } else if (axis == AXIS_NAMESPACE) { 11988 if (cur->type == XML_NAMESPACE_DECL) { 11989 pos++; 11990 if (pos == reqpos) 11991 xmlXPathNodeSetAddNs(list, xpctxt->node, 11992 (xmlNsPtr) cur); 11993 } 11994 } else { 11995 if (cur->type == XML_ELEMENT_NODE) { 11996 if (prefix == NULL) { 11997 pos++; 11998 if (pos == reqpos) 11999 addNode(list, cur); 12000 } else if ((cur->ns != NULL) && 12001 (xmlStrEqual(URI, cur->ns->href))) { 12002 pos++; 12003 if (pos == reqpos) 12004 addNode(list, cur); 12005 } 12006 } 12007 } 12008 break; 12009 case NODE_TEST_NS:{ 12010 TODO; 12011 break; 12012 } 12013 case NODE_TEST_NAME: 12014 switch (cur->type) { 12015 case XML_ELEMENT_NODE: 12016 if (xmlStrEqual(name, cur->name)) { 12017 if (prefix == NULL) { 12018 if (cur->ns == NULL) { 12019 pos++; 12020 if (pos == reqpos) 12021 addNode(list, cur); 12022 } 12023 } else { 12024 if ((cur->ns != NULL) && 12025 (xmlStrEqual(URI, 12026 cur->ns->href))) 12027 { 12028 pos++; 12029 if (pos == reqpos) 12030 addNode(list, cur); 12031 } 12032 } 12033 } 12034 break; 12035 case XML_ATTRIBUTE_NODE:{ 12036 xmlAttrPtr attr = (xmlAttrPtr) cur; 12037 12038 if (xmlStrEqual(name, attr->name)) { 12039 if (prefix == NULL) { 12040 if ((attr->ns == NULL) || 12041 (attr->ns->prefix == NULL)) 12042 { 12043 pos++; 12044 if (pos == reqpos) 12045 addNode(list, cur); 12046 } 12047 } else { 12048 if ((attr->ns != NULL) && 12049 (xmlStrEqual(URI, 12050 attr->ns->href))) 12051 { 12052 pos++; 12053 if (pos == reqpos) 12054 addNode(list, cur); 12055 } 12056 } 12057 } 12058 break; 12059 } 12060 case XML_NAMESPACE_DECL: 12061 if (cur->type == XML_NAMESPACE_DECL) { 12062 xmlNsPtr ns = (xmlNsPtr) cur; 12063 12064 if ((ns->prefix != NULL) && (name != NULL) 12065 && (xmlStrEqual(ns->prefix, name))) { 12066 pos++; 12067 if (pos == reqpos) 12068 xmlXPathNodeSetAddNs(list, 12069 xpctxt->node, (xmlNsPtr) cur); 12070 } 12071 } 12072 break; 12073 default: 12074 break; 12075 } 12076 break; 12077 } 12078 } while (pos < reqpos); 12079 } 12080 xpctxt->node = oldContextNode; 12081 12082#ifdef DEBUG_STEP_NTH 12083 xmlGenericError(xmlGenericErrorContext, 12084 "\nExamined %d nodes, found %d nodes at that step\n", 12085 total, list->nodeNr); 12086#endif 12087 12088 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, list)); 12089 12090 if ((obj->boolval) && (obj->user != NULL)) { 12091 ctxt->value->boolval = 1; 12092 ctxt->value->user = obj->user; 12093 obj->user = NULL; 12094 obj->boolval = 0; 12095 } 12096 xmlXPathReleaseObject(xpctxt, obj); 12097 return(total); 12098 12099error: 12100 xpctxt->node = oldContextNode; 12101 xmlXPathReleaseObject(xpctxt, obj); 12102 if (list != NULL) 12103 xmlXPathFreeNodeSet(list); 12104 return(total); 12105} 12106 12107static int 12108xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12109 xmlXPathStepOpPtr op, xmlNodePtr * first); 12110 12111/** 12112 * xmlXPathCompOpEvalFirst: 12113 * @ctxt: the XPath parser context with the compiled expression 12114 * @op: an XPath compiled operation 12115 * @first: the first elem found so far 12116 * 12117 * Evaluate the Precompiled XPath operation searching only the first 12118 * element in document order 12119 * 12120 * Returns the number of examined objects. 12121 */ 12122static int 12123xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 12124 xmlXPathStepOpPtr op, xmlNodePtr * first) 12125{ 12126 int total = 0, cur; 12127 xmlXPathCompExprPtr comp; 12128 xmlXPathObjectPtr arg1, arg2; 12129 12130 CHECK_ERROR0; 12131 comp = ctxt->comp; 12132 switch (op->op) { 12133 case XPATH_OP_END: 12134 return (0); 12135 case XPATH_OP_UNION: 12136 total = 12137 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12138 first); 12139 CHECK_ERROR0; 12140 if ((ctxt->value != NULL) 12141 && (ctxt->value->type == XPATH_NODESET) 12142 && (ctxt->value->nodesetval != NULL) 12143 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12144 /* 12145 * limit tree traversing to first node in the result 12146 */ 12147 /* 12148 * OPTIMIZE TODO: This implicitely sorts 12149 * the result, even if not needed. E.g. if the argument 12150 * of the count() function, no sorting is needed. 12151 * OPTIMIZE TODO: How do we know if the node-list wasn't 12152 * aready sorted? 12153 */ 12154 if (ctxt->value->nodesetval->nodeNr > 1) 12155 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12156 *first = ctxt->value->nodesetval->nodeTab[0]; 12157 } 12158 cur = 12159 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 12160 first); 12161 CHECK_ERROR0; 12162 CHECK_TYPE0(XPATH_NODESET); 12163 arg2 = valuePop(ctxt); 12164 12165 CHECK_TYPE0(XPATH_NODESET); 12166 arg1 = valuePop(ctxt); 12167 12168 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12169 arg2->nodesetval); 12170 valuePush(ctxt, arg1); 12171 xmlXPathReleaseObject(ctxt->context, arg2); 12172 /* optimizer */ 12173 if (total > cur) 12174 xmlXPathCompSwap(op); 12175 return (total + cur); 12176 case XPATH_OP_ROOT: 12177 xmlXPathRoot(ctxt); 12178 return (0); 12179 case XPATH_OP_NODE: 12180 if (op->ch1 != -1) 12181 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12182 CHECK_ERROR0; 12183 if (op->ch2 != -1) 12184 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12185 CHECK_ERROR0; 12186 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12187 ctxt->context->node)); 12188 return (total); 12189 case XPATH_OP_RESET: 12190 if (op->ch1 != -1) 12191 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12192 CHECK_ERROR0; 12193 if (op->ch2 != -1) 12194 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12195 CHECK_ERROR0; 12196 ctxt->context->node = NULL; 12197 return (total); 12198 case XPATH_OP_COLLECT:{ 12199 if (op->ch1 == -1) 12200 return (total); 12201 12202 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12203 CHECK_ERROR0; 12204 12205 /* 12206 * Optimization for [n] selection where n is a number 12207 */ 12208 if ((op->ch2 != -1) && 12209 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && 12210 (comp->steps[op->ch2].ch1 == -1) && 12211 (comp->steps[op->ch2].ch2 != -1) && 12212 (comp->steps[comp->steps[op->ch2].ch2].op == 12213 XPATH_OP_VALUE)) { 12214 xmlXPathObjectPtr val; 12215 12216 val = comp->steps[comp->steps[op->ch2].ch2].value4; 12217 if ((val != NULL) && (val->type == XPATH_NUMBER)) { 12218 int indx = (int) val->floatval; 12219 12220 if (val->floatval == (float) indx) { 12221 xmlXPathNodeCollectAndTestNth(ctxt, op, indx, 12222 first, NULL); 12223 return (total); 12224 } 12225 } 12226 } 12227 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL); 12228 return (total); 12229 } 12230 case XPATH_OP_VALUE: 12231 valuePush(ctxt, 12232 xmlXPathCacheObjectCopy(ctxt->context, 12233 (xmlXPathObjectPtr) op->value4)); 12234 return (0); 12235 case XPATH_OP_SORT: 12236 if (op->ch1 != -1) 12237 total += 12238 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 12239 first); 12240 CHECK_ERROR0; 12241 if ((ctxt->value != NULL) 12242 && (ctxt->value->type == XPATH_NODESET) 12243 && (ctxt->value->nodesetval != NULL) 12244 && (ctxt->value->nodesetval->nodeNr > 1)) 12245 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12246 return (total); 12247#ifdef XP_OPTIMIZED_FILTER_FIRST 12248 case XPATH_OP_FILTER: 12249 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first); 12250 return (total); 12251#endif 12252 default: 12253 return (xmlXPathCompOpEval(ctxt, op)); 12254 } 12255} 12256 12257/** 12258 * xmlXPathCompOpEvalLast: 12259 * @ctxt: the XPath parser context with the compiled expression 12260 * @op: an XPath compiled operation 12261 * @last: the last elem found so far 12262 * 12263 * Evaluate the Precompiled XPath operation searching only the last 12264 * element in document order 12265 * 12266 * Returns the number of nodes traversed 12267 */ 12268static int 12269xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 12270 xmlNodePtr * last) 12271{ 12272 int total = 0, cur; 12273 xmlXPathCompExprPtr comp; 12274 xmlXPathObjectPtr arg1, arg2; 12275 xmlNodePtr bak; 12276 xmlDocPtr bakd; 12277 int pp; 12278 int cs; 12279 12280 CHECK_ERROR0; 12281 comp = ctxt->comp; 12282 switch (op->op) { 12283 case XPATH_OP_END: 12284 return (0); 12285 case XPATH_OP_UNION: 12286 bakd = ctxt->context->doc; 12287 bak = ctxt->context->node; 12288 pp = ctxt->context->proximityPosition; 12289 cs = ctxt->context->contextSize; 12290 total = 12291 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 12292 CHECK_ERROR0; 12293 if ((ctxt->value != NULL) 12294 && (ctxt->value->type == XPATH_NODESET) 12295 && (ctxt->value->nodesetval != NULL) 12296 && (ctxt->value->nodesetval->nodeNr >= 1)) { 12297 /* 12298 * limit tree traversing to first node in the result 12299 */ 12300 if (ctxt->value->nodesetval->nodeNr > 1) 12301 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12302 *last = 12303 ctxt->value->nodesetval->nodeTab[ctxt->value-> 12304 nodesetval->nodeNr - 12305 1]; 12306 } 12307 ctxt->context->doc = bakd; 12308 ctxt->context->node = bak; 12309 ctxt->context->proximityPosition = pp; 12310 ctxt->context->contextSize = cs; 12311 cur = 12312 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 12313 CHECK_ERROR0; 12314 if ((ctxt->value != NULL) 12315 && (ctxt->value->type == XPATH_NODESET) 12316 && (ctxt->value->nodesetval != NULL) 12317 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ 12318 } 12319 CHECK_TYPE0(XPATH_NODESET); 12320 arg2 = valuePop(ctxt); 12321 12322 CHECK_TYPE0(XPATH_NODESET); 12323 arg1 = valuePop(ctxt); 12324 12325 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12326 arg2->nodesetval); 12327 valuePush(ctxt, arg1); 12328 xmlXPathReleaseObject(ctxt->context, arg2); 12329 /* optimizer */ 12330 if (total > cur) 12331 xmlXPathCompSwap(op); 12332 return (total + cur); 12333 case XPATH_OP_ROOT: 12334 xmlXPathRoot(ctxt); 12335 return (0); 12336 case XPATH_OP_NODE: 12337 if (op->ch1 != -1) 12338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12339 CHECK_ERROR0; 12340 if (op->ch2 != -1) 12341 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12342 CHECK_ERROR0; 12343 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12344 ctxt->context->node)); 12345 return (total); 12346 case XPATH_OP_RESET: 12347 if (op->ch1 != -1) 12348 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12349 CHECK_ERROR0; 12350 if (op->ch2 != -1) 12351 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12352 CHECK_ERROR0; 12353 ctxt->context->node = NULL; 12354 return (total); 12355 case XPATH_OP_COLLECT:{ 12356 if (op->ch1 == -1) 12357 return (0); 12358 12359 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12360 CHECK_ERROR0; 12361 12362 /* 12363 * Optimization for [n] selection where n is a number 12364 */ 12365 if ((op->ch2 != -1) && 12366 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && 12367 (comp->steps[op->ch2].ch1 == -1) && 12368 (comp->steps[op->ch2].ch2 != -1) && 12369 (comp->steps[comp->steps[op->ch2].ch2].op == 12370 XPATH_OP_VALUE)) { 12371 xmlXPathObjectPtr val; 12372 12373 val = comp->steps[comp->steps[op->ch2].ch2].value4; 12374 if ((val != NULL) && (val->type == XPATH_NUMBER)) { 12375 int indx = (int) val->floatval; 12376 12377 if (val->floatval == (float) indx) { 12378 total += 12379 xmlXPathNodeCollectAndTestNth(ctxt, op, 12380 indx, NULL, 12381 last); 12382 return (total); 12383 } 12384 } 12385 } 12386 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last); 12387 return (total); 12388 } 12389 case XPATH_OP_VALUE: 12390 valuePush(ctxt, 12391 xmlXPathCacheObjectCopy(ctxt->context, 12392 (xmlXPathObjectPtr) op->value4)); 12393 return (0); 12394 case XPATH_OP_SORT: 12395 if (op->ch1 != -1) 12396 total += 12397 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 12398 last); 12399 CHECK_ERROR0; 12400 if ((ctxt->value != NULL) 12401 && (ctxt->value->type == XPATH_NODESET) 12402 && (ctxt->value->nodesetval != NULL) 12403 && (ctxt->value->nodesetval->nodeNr > 1)) 12404 xmlXPathNodeSetSort(ctxt->value->nodesetval); 12405 return (total); 12406 default: 12407 return (xmlXPathCompOpEval(ctxt, op)); 12408 } 12409} 12410 12411#ifdef XP_OPTIMIZED_FILTER_FIRST 12412static int 12413xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, 12414 xmlXPathStepOpPtr op, xmlNodePtr * first) 12415{ 12416 int total = 0; 12417 xmlXPathCompExprPtr comp; 12418 xmlXPathObjectPtr res; 12419 xmlXPathObjectPtr obj; 12420 xmlNodeSetPtr oldset; 12421 xmlNodePtr oldnode; 12422 xmlDocPtr oldDoc; 12423 int i; 12424 12425 CHECK_ERROR0; 12426 comp = ctxt->comp; 12427 /* 12428 * Optimization for ()[last()] selection i.e. the last elem 12429 */ 12430 if ((op->ch1 != -1) && (op->ch2 != -1) && 12431 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 12432 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 12433 int f = comp->steps[op->ch2].ch1; 12434 12435 if ((f != -1) && 12436 (comp->steps[f].op == XPATH_OP_FUNCTION) && 12437 (comp->steps[f].value5 == NULL) && 12438 (comp->steps[f].value == 0) && 12439 (comp->steps[f].value4 != NULL) && 12440 (xmlStrEqual 12441 (comp->steps[f].value4, BAD_CAST "last"))) { 12442 xmlNodePtr last = NULL; 12443 12444 total += 12445 xmlXPathCompOpEvalLast(ctxt, 12446 &comp->steps[op->ch1], 12447 &last); 12448 CHECK_ERROR0; 12449 /* 12450 * The nodeset should be in document order, 12451 * Keep only the last value 12452 */ 12453 if ((ctxt->value != NULL) && 12454 (ctxt->value->type == XPATH_NODESET) && 12455 (ctxt->value->nodesetval != NULL) && 12456 (ctxt->value->nodesetval->nodeTab != NULL) && 12457 (ctxt->value->nodesetval->nodeNr > 1)) { 12458 ctxt->value->nodesetval->nodeTab[0] = 12459 ctxt->value->nodesetval->nodeTab[ctxt-> 12460 value-> 12461 nodesetval-> 12462 nodeNr - 12463 1]; 12464 ctxt->value->nodesetval->nodeNr = 1; 12465 *first = *(ctxt->value->nodesetval->nodeTab); 12466 } 12467 return (total); 12468 } 12469 } 12470 12471 if (op->ch1 != -1) 12472 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12473 CHECK_ERROR0; 12474 if (op->ch2 == -1) 12475 return (total); 12476 if (ctxt->value == NULL) 12477 return (total); 12478 12479#ifdef LIBXML_XPTR_ENABLED 12480 oldnode = ctxt->context->node; 12481 /* 12482 * Hum are we filtering the result of an XPointer expression 12483 */ 12484 if (ctxt->value->type == XPATH_LOCATIONSET) { 12485 xmlXPathObjectPtr tmp = NULL; 12486 xmlLocationSetPtr newlocset = NULL; 12487 xmlLocationSetPtr oldlocset; 12488 12489 /* 12490 * Extract the old locset, and then evaluate the result of the 12491 * expression for all the element in the locset. use it to grow 12492 * up a new locset. 12493 */ 12494 CHECK_TYPE0(XPATH_LOCATIONSET); 12495 obj = valuePop(ctxt); 12496 oldlocset = obj->user; 12497 ctxt->context->node = NULL; 12498 12499 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 12500 ctxt->context->contextSize = 0; 12501 ctxt->context->proximityPosition = 0; 12502 if (op->ch2 != -1) 12503 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12504 res = valuePop(ctxt); 12505 if (res != NULL) { 12506 xmlXPathReleaseObject(ctxt->context, res); 12507 } 12508 valuePush(ctxt, obj); 12509 CHECK_ERROR0; 12510 return (total); 12511 } 12512 newlocset = xmlXPtrLocationSetCreate(NULL); 12513 12514 for (i = 0; i < oldlocset->locNr; i++) { 12515 /* 12516 * Run the evaluation with a node list made of a 12517 * single item in the nodelocset. 12518 */ 12519 ctxt->context->node = oldlocset->locTab[i]->user; 12520 ctxt->context->contextSize = oldlocset->locNr; 12521 ctxt->context->proximityPosition = i + 1; 12522 if (tmp == NULL) { 12523 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 12524 ctxt->context->node); 12525 } else { 12526 xmlXPathNodeSetAddUnique(tmp->nodesetval, 12527 ctxt->context->node); 12528 } 12529 valuePush(ctxt, tmp); 12530 if (op->ch2 != -1) 12531 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12532 if (ctxt->error != XPATH_EXPRESSION_OK) { 12533 xmlXPathFreeObject(obj); 12534 return(0); 12535 } 12536 /* 12537 * The result of the evaluation need to be tested to 12538 * decided whether the filter succeeded or not 12539 */ 12540 res = valuePop(ctxt); 12541 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 12542 xmlXPtrLocationSetAdd(newlocset, 12543 xmlXPathCacheObjectCopy(ctxt->context, 12544 oldlocset->locTab[i])); 12545 } 12546 /* 12547 * Cleanup 12548 */ 12549 if (res != NULL) { 12550 xmlXPathReleaseObject(ctxt->context, res); 12551 } 12552 if (ctxt->value == tmp) { 12553 valuePop(ctxt); 12554 xmlXPathNodeSetClear(tmp->nodesetval); 12555 /* 12556 * REVISIT TODO: Don't create a temporary nodeset 12557 * for everly iteration. 12558 */ 12559 /* OLD: xmlXPathFreeObject(res); */ 12560 } else 12561 tmp = NULL; 12562 ctxt->context->node = NULL; 12563 /* 12564 * Only put the first node in the result, then leave. 12565 */ 12566 if (newlocset->locNr > 0) { 12567 *first = (xmlNodePtr) oldlocset->locTab[i]->user; 12568 break; 12569 } 12570 } 12571 if (tmp != NULL) { 12572 xmlXPathReleaseObject(ctxt->context, tmp); 12573 } 12574 /* 12575 * The result is used as the new evaluation locset. 12576 */ 12577 xmlXPathReleaseObject(ctxt->context, obj); 12578 ctxt->context->node = NULL; 12579 ctxt->context->contextSize = -1; 12580 ctxt->context->proximityPosition = -1; 12581 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 12582 ctxt->context->node = oldnode; 12583 return (total); 12584 } 12585#endif /* LIBXML_XPTR_ENABLED */ 12586 12587 /* 12588 * Extract the old set, and then evaluate the result of the 12589 * expression for all the element in the set. use it to grow 12590 * up a new set. 12591 */ 12592 CHECK_TYPE0(XPATH_NODESET); 12593 obj = valuePop(ctxt); 12594 oldset = obj->nodesetval; 12595 12596 oldnode = ctxt->context->node; 12597 oldDoc = ctxt->context->doc; 12598 ctxt->context->node = NULL; 12599 12600 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 12601 ctxt->context->contextSize = 0; 12602 ctxt->context->proximityPosition = 0; 12603 /* QUESTION TODO: Why was this code commented out? 12604 if (op->ch2 != -1) 12605 total += 12606 xmlXPathCompOpEval(ctxt, 12607 &comp->steps[op->ch2]); 12608 CHECK_ERROR0; 12609 res = valuePop(ctxt); 12610 if (res != NULL) 12611 xmlXPathFreeObject(res); 12612 */ 12613 valuePush(ctxt, obj); 12614 ctxt->context->node = oldnode; 12615 CHECK_ERROR0; 12616 } else { 12617 xmlNodeSetPtr newset; 12618 xmlXPathObjectPtr tmp = NULL; 12619 /* 12620 * Initialize the new set. 12621 * Also set the xpath document in case things like 12622 * key() evaluation are attempted on the predicate 12623 */ 12624 newset = xmlXPathNodeSetCreate(NULL); 12625 12626 for (i = 0; i < oldset->nodeNr; i++) { 12627 /* 12628 * Run the evaluation with a node list made of 12629 * a single item in the nodeset. 12630 */ 12631 ctxt->context->node = oldset->nodeTab[i]; 12632 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 12633 (oldset->nodeTab[i]->doc != NULL)) 12634 ctxt->context->doc = oldset->nodeTab[i]->doc; 12635 if (tmp == NULL) { 12636 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 12637 ctxt->context->node); 12638 } else { 12639 xmlXPathNodeSetAddUnique(tmp->nodesetval, 12640 ctxt->context->node); 12641 } 12642 valuePush(ctxt, tmp); 12643 ctxt->context->contextSize = oldset->nodeNr; 12644 ctxt->context->proximityPosition = i + 1; 12645 if (op->ch2 != -1) 12646 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12647 if (ctxt->error != XPATH_EXPRESSION_OK) { 12648 xmlXPathFreeNodeSet(newset); 12649 xmlXPathFreeObject(obj); 12650 return(0); 12651 } 12652 /* 12653 * The result of the evaluation needs to be tested to 12654 * decide whether the filter succeeded or not 12655 */ 12656 res = valuePop(ctxt); 12657 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 12658 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 12659 } 12660 /* 12661 * Cleanup 12662 */ 12663 if (res != NULL) { 12664 xmlXPathReleaseObject(ctxt->context, res); 12665 } 12666 if (ctxt->value == tmp) { 12667 valuePop(ctxt); 12668 /* 12669 * Don't free the temporary nodeset 12670 * in order to avoid massive recreation inside this 12671 * loop. 12672 */ 12673 xmlXPathNodeSetClear(tmp->nodesetval); 12674 } else 12675 tmp = NULL; 12676 ctxt->context->node = NULL; 12677 /* 12678 * Only put the first node in the result, then leave. 12679 */ 12680 if (newset->nodeNr > 0) { 12681 *first = *(newset->nodeTab); 12682 break; 12683 } 12684 } 12685 if (tmp != NULL) { 12686 xmlXPathReleaseObject(ctxt->context, tmp); 12687 } 12688 /* 12689 * The result is used as the new evaluation set. 12690 */ 12691 xmlXPathReleaseObject(ctxt->context, obj); 12692 ctxt->context->node = NULL; 12693 ctxt->context->contextSize = -1; 12694 ctxt->context->proximityPosition = -1; 12695 /* may want to move this past the '}' later */ 12696 ctxt->context->doc = oldDoc; 12697 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 12698 } 12699 ctxt->context->node = oldnode; 12700 return(total); 12701} 12702#endif /* XP_OPTIMIZED_FILTER_FIRST */ 12703 12704/** 12705 * xmlXPathCompOpEval: 12706 * @ctxt: the XPath parser context with the compiled expression 12707 * @op: an XPath compiled operation 12708 * 12709 * Evaluate the Precompiled XPath operation 12710 * Returns the number of nodes traversed 12711 */ 12712static int 12713xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 12714{ 12715 int total = 0; 12716 int equal, ret; 12717 xmlXPathCompExprPtr comp; 12718 xmlXPathObjectPtr arg1, arg2; 12719 xmlNodePtr bak; 12720 xmlDocPtr bakd; 12721 int pp; 12722 int cs; 12723 12724 CHECK_ERROR0; 12725 comp = ctxt->comp; 12726 switch (op->op) { 12727 case XPATH_OP_END: 12728 return (0); 12729 case XPATH_OP_AND: 12730 bakd = ctxt->context->doc; 12731 bak = ctxt->context->node; 12732 pp = ctxt->context->proximityPosition; 12733 cs = ctxt->context->contextSize; 12734 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12735 CHECK_ERROR0; 12736 xmlXPathBooleanFunction(ctxt, 1); 12737 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 12738 return (total); 12739 arg2 = valuePop(ctxt); 12740 ctxt->context->doc = bakd; 12741 ctxt->context->node = bak; 12742 ctxt->context->proximityPosition = pp; 12743 ctxt->context->contextSize = cs; 12744 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12745 if (ctxt->error) { 12746 xmlXPathFreeObject(arg2); 12747 return(0); 12748 } 12749 xmlXPathBooleanFunction(ctxt, 1); 12750 arg1 = valuePop(ctxt); 12751 arg1->boolval &= arg2->boolval; 12752 valuePush(ctxt, arg1); 12753 xmlXPathReleaseObject(ctxt->context, arg2); 12754 return (total); 12755 case XPATH_OP_OR: 12756 bakd = ctxt->context->doc; 12757 bak = ctxt->context->node; 12758 pp = ctxt->context->proximityPosition; 12759 cs = ctxt->context->contextSize; 12760 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12761 CHECK_ERROR0; 12762 xmlXPathBooleanFunction(ctxt, 1); 12763 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 12764 return (total); 12765 arg2 = valuePop(ctxt); 12766 ctxt->context->doc = bakd; 12767 ctxt->context->node = bak; 12768 ctxt->context->proximityPosition = pp; 12769 ctxt->context->contextSize = cs; 12770 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12771 if (ctxt->error) { 12772 xmlXPathFreeObject(arg2); 12773 return(0); 12774 } 12775 xmlXPathBooleanFunction(ctxt, 1); 12776 arg1 = valuePop(ctxt); 12777 arg1->boolval |= arg2->boolval; 12778 valuePush(ctxt, arg1); 12779 xmlXPathReleaseObject(ctxt->context, arg2); 12780 return (total); 12781 case XPATH_OP_EQUAL: 12782 bakd = ctxt->context->doc; 12783 bak = ctxt->context->node; 12784 pp = ctxt->context->proximityPosition; 12785 cs = ctxt->context->contextSize; 12786 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12787 CHECK_ERROR0; 12788 ctxt->context->doc = bakd; 12789 ctxt->context->node = bak; 12790 ctxt->context->proximityPosition = pp; 12791 ctxt->context->contextSize = cs; 12792 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12793 CHECK_ERROR0; 12794 if (op->value) 12795 equal = xmlXPathEqualValues(ctxt); 12796 else 12797 equal = xmlXPathNotEqualValues(ctxt); 12798 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); 12799 return (total); 12800 case XPATH_OP_CMP: 12801 bakd = ctxt->context->doc; 12802 bak = ctxt->context->node; 12803 pp = ctxt->context->proximityPosition; 12804 cs = ctxt->context->contextSize; 12805 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12806 CHECK_ERROR0; 12807 ctxt->context->doc = bakd; 12808 ctxt->context->node = bak; 12809 ctxt->context->proximityPosition = pp; 12810 ctxt->context->contextSize = cs; 12811 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12812 CHECK_ERROR0; 12813 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 12814 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); 12815 return (total); 12816 case XPATH_OP_PLUS: 12817 bakd = ctxt->context->doc; 12818 bak = ctxt->context->node; 12819 pp = ctxt->context->proximityPosition; 12820 cs = ctxt->context->contextSize; 12821 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12822 CHECK_ERROR0; 12823 if (op->ch2 != -1) { 12824 ctxt->context->doc = bakd; 12825 ctxt->context->node = bak; 12826 ctxt->context->proximityPosition = pp; 12827 ctxt->context->contextSize = cs; 12828 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12829 } 12830 CHECK_ERROR0; 12831 if (op->value == 0) 12832 xmlXPathSubValues(ctxt); 12833 else if (op->value == 1) 12834 xmlXPathAddValues(ctxt); 12835 else if (op->value == 2) 12836 xmlXPathValueFlipSign(ctxt); 12837 else if (op->value == 3) { 12838 CAST_TO_NUMBER; 12839 CHECK_TYPE0(XPATH_NUMBER); 12840 } 12841 return (total); 12842 case XPATH_OP_MULT: 12843 bakd = ctxt->context->doc; 12844 bak = ctxt->context->node; 12845 pp = ctxt->context->proximityPosition; 12846 cs = ctxt->context->contextSize; 12847 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12848 CHECK_ERROR0; 12849 ctxt->context->doc = bakd; 12850 ctxt->context->node = bak; 12851 ctxt->context->proximityPosition = pp; 12852 ctxt->context->contextSize = cs; 12853 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12854 CHECK_ERROR0; 12855 if (op->value == 0) 12856 xmlXPathMultValues(ctxt); 12857 else if (op->value == 1) 12858 xmlXPathDivValues(ctxt); 12859 else if (op->value == 2) 12860 xmlXPathModValues(ctxt); 12861 return (total); 12862 case XPATH_OP_UNION: 12863 bakd = ctxt->context->doc; 12864 bak = ctxt->context->node; 12865 pp = ctxt->context->proximityPosition; 12866 cs = ctxt->context->contextSize; 12867 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12868 CHECK_ERROR0; 12869 ctxt->context->doc = bakd; 12870 ctxt->context->node = bak; 12871 ctxt->context->proximityPosition = pp; 12872 ctxt->context->contextSize = cs; 12873 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12874 CHECK_ERROR0; 12875 CHECK_TYPE0(XPATH_NODESET); 12876 arg2 = valuePop(ctxt); 12877 12878 CHECK_TYPE0(XPATH_NODESET); 12879 arg1 = valuePop(ctxt); 12880 12881 if ((arg1->nodesetval == NULL) || 12882 ((arg2->nodesetval != NULL) && 12883 (arg2->nodesetval->nodeNr != 0))) 12884 { 12885 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 12886 arg2->nodesetval); 12887 } 12888 12889 valuePush(ctxt, arg1); 12890 xmlXPathReleaseObject(ctxt->context, arg2); 12891 return (total); 12892 case XPATH_OP_ROOT: 12893 xmlXPathRoot(ctxt); 12894 return (total); 12895 case XPATH_OP_NODE: 12896 if (op->ch1 != -1) 12897 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12898 CHECK_ERROR0; 12899 if (op->ch2 != -1) 12900 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12901 CHECK_ERROR0; 12902 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, 12903 ctxt->context->node)); 12904 return (total); 12905 case XPATH_OP_RESET: 12906 if (op->ch1 != -1) 12907 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12908 CHECK_ERROR0; 12909 if (op->ch2 != -1) 12910 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 12911 CHECK_ERROR0; 12912 ctxt->context->node = NULL; 12913 return (total); 12914 case XPATH_OP_COLLECT:{ 12915 if (op->ch1 == -1) 12916 return (total); 12917 12918 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12919 CHECK_ERROR0; 12920 12921 if ((op->ch2 != -1) && 12922 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && 12923 (comp->steps[op->ch2].ch1 == -1) && 12924 (comp->steps[op->ch2].ch2 != -1) && 12925 (comp->steps[comp->steps[op->ch2].ch2].op == 12926 XPATH_OP_VALUE)) 12927 { 12928 xmlXPathObjectPtr val; 12929 /* 12930 * Optimization for [n] selection where n is a number 12931 */ 12932 val = comp->steps[comp->steps[op->ch2].ch2].value4; 12933 if ((val != NULL) && (val->type == XPATH_NUMBER)) { 12934 int indx = (int) val->floatval; 12935 12936 if (val->floatval == (float) indx) { 12937 total += 12938 xmlXPathNodeCollectAndTestNth(ctxt, op, 12939 indx, NULL, 12940 NULL); 12941 return (total); 12942 } 12943 } 12944 } 12945 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL); 12946 return (total); 12947 } 12948 case XPATH_OP_VALUE: 12949 valuePush(ctxt, 12950 xmlXPathCacheObjectCopy(ctxt->context, 12951 (xmlXPathObjectPtr) op->value4)); 12952 return (total); 12953 case XPATH_OP_VARIABLE:{ 12954 xmlXPathObjectPtr val; 12955 12956 if (op->ch1 != -1) 12957 total += 12958 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12959 if (op->value5 == NULL) { 12960 val = xmlXPathVariableLookup(ctxt->context, op->value4); 12961 if (val == NULL) { 12962 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 12963 return(0); 12964 } 12965 valuePush(ctxt, val); 12966 } else { 12967 const xmlChar *URI; 12968 12969 URI = xmlXPathNsLookup(ctxt->context, op->value5); 12970 if (URI == NULL) { 12971 xmlGenericError(xmlGenericErrorContext, 12972 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 12973 op->value4, op->value5); 12974 return (total); 12975 } 12976 val = xmlXPathVariableLookupNS(ctxt->context, 12977 op->value4, URI); 12978 if (val == NULL) { 12979 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 12980 return(0); 12981 } 12982 valuePush(ctxt, val); 12983 } 12984 return (total); 12985 } 12986 case XPATH_OP_FUNCTION:{ 12987 xmlXPathFunction func; 12988 const xmlChar *oldFunc, *oldFuncURI; 12989 int i; 12990 12991 if (op->ch1 != -1) 12992 total += 12993 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 12994 if (ctxt->valueNr < op->value) { 12995 xmlGenericError(xmlGenericErrorContext, 12996 "xmlXPathCompOpEval: parameter error\n"); 12997 ctxt->error = XPATH_INVALID_OPERAND; 12998 return (total); 12999 } 13000 for (i = 0; i < op->value; i++) 13001 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 13002 xmlGenericError(xmlGenericErrorContext, 13003 "xmlXPathCompOpEval: parameter error\n"); 13004 ctxt->error = XPATH_INVALID_OPERAND; 13005 return (total); 13006 } 13007 if (op->cache != NULL) 13008 XML_CAST_FPTR(func) = op->cache; 13009 else { 13010 const xmlChar *URI = NULL; 13011 13012 if (op->value5 == NULL) 13013 func = 13014 xmlXPathFunctionLookup(ctxt->context, 13015 op->value4); 13016 else { 13017 URI = xmlXPathNsLookup(ctxt->context, op->value5); 13018 if (URI == NULL) { 13019 xmlGenericError(xmlGenericErrorContext, 13020 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 13021 op->value4, op->value5); 13022 return (total); 13023 } 13024 func = xmlXPathFunctionLookupNS(ctxt->context, 13025 op->value4, URI); 13026 } 13027 if (func == NULL) { 13028 xmlGenericError(xmlGenericErrorContext, 13029 "xmlXPathCompOpEval: function %s not found\n", 13030 op->value4); 13031 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 13032 } 13033 op->cache = XML_CAST_FPTR(func); 13034 op->cacheURI = (void *) URI; 13035 } 13036 oldFunc = ctxt->context->function; 13037 oldFuncURI = ctxt->context->functionURI; 13038 ctxt->context->function = op->value4; 13039 ctxt->context->functionURI = op->cacheURI; 13040 func(ctxt, op->value); 13041 ctxt->context->function = oldFunc; 13042 ctxt->context->functionURI = oldFuncURI; 13043 return (total); 13044 } 13045 case XPATH_OP_ARG: 13046 bakd = ctxt->context->doc; 13047 bak = ctxt->context->node; 13048 pp = ctxt->context->proximityPosition; 13049 cs = ctxt->context->contextSize; 13050 if (op->ch1 != -1) 13051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13052 ctxt->context->contextSize = cs; 13053 ctxt->context->proximityPosition = pp; 13054 ctxt->context->node = bak; 13055 ctxt->context->doc = bakd; 13056 CHECK_ERROR0; 13057 if (op->ch2 != -1) { 13058 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 13059 ctxt->context->doc = bakd; 13060 ctxt->context->node = bak; 13061 CHECK_ERROR0; 13062 } 13063 return (total); 13064 case XPATH_OP_PREDICATE: 13065 case XPATH_OP_FILTER:{ 13066 xmlXPathObjectPtr res; 13067 xmlXPathObjectPtr obj, tmp; 13068 xmlNodeSetPtr newset = NULL; 13069 xmlNodeSetPtr oldset; 13070 xmlNodePtr oldnode; 13071 xmlDocPtr oldDoc; 13072 int i; 13073 13074 /* 13075 * Optimization for ()[1] selection i.e. the first elem 13076 */ 13077 if ((op->ch1 != -1) && (op->ch2 != -1) && 13078#ifdef XP_OPTIMIZED_FILTER_FIRST 13079 /* 13080 * FILTER TODO: Can we assume that the inner processing 13081 * will result in an ordered list if we have an 13082 * XPATH_OP_FILTER? 13083 * What about an additional field or flag on 13084 * xmlXPathObject like @sorted ? This way we wouln'd need 13085 * to assume anything, so it would be more robust and 13086 * easier to optimize. 13087 */ 13088 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ 13089 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ 13090#else 13091 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13092#endif 13093 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ 13094 xmlXPathObjectPtr val; 13095 13096 val = comp->steps[op->ch2].value4; 13097 if ((val != NULL) && (val->type == XPATH_NUMBER) && 13098 (val->floatval == 1.0)) { 13099 xmlNodePtr first = NULL; 13100 13101 total += 13102 xmlXPathCompOpEvalFirst(ctxt, 13103 &comp->steps[op->ch1], 13104 &first); 13105 CHECK_ERROR0; 13106 /* 13107 * The nodeset should be in document order, 13108 * Keep only the first value 13109 */ 13110 if ((ctxt->value != NULL) && 13111 (ctxt->value->type == XPATH_NODESET) && 13112 (ctxt->value->nodesetval != NULL) && 13113 (ctxt->value->nodesetval->nodeNr > 1)) 13114 ctxt->value->nodesetval->nodeNr = 1; 13115 return (total); 13116 } 13117 } 13118 /* 13119 * Optimization for ()[last()] selection i.e. the last elem 13120 */ 13121 if ((op->ch1 != -1) && (op->ch2 != -1) && 13122 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 13123 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 13124 int f = comp->steps[op->ch2].ch1; 13125 13126 if ((f != -1) && 13127 (comp->steps[f].op == XPATH_OP_FUNCTION) && 13128 (comp->steps[f].value5 == NULL) && 13129 (comp->steps[f].value == 0) && 13130 (comp->steps[f].value4 != NULL) && 13131 (xmlStrEqual 13132 (comp->steps[f].value4, BAD_CAST "last"))) { 13133 xmlNodePtr last = NULL; 13134 13135 total += 13136 xmlXPathCompOpEvalLast(ctxt, 13137 &comp->steps[op->ch1], 13138 &last); 13139 CHECK_ERROR0; 13140 /* 13141 * The nodeset should be in document order, 13142 * Keep only the last value 13143 */ 13144 if ((ctxt->value != NULL) && 13145 (ctxt->value->type == XPATH_NODESET) && 13146 (ctxt->value->nodesetval != NULL) && 13147 (ctxt->value->nodesetval->nodeTab != NULL) && 13148 (ctxt->value->nodesetval->nodeNr > 1)) { 13149 ctxt->value->nodesetval->nodeTab[0] = 13150 ctxt->value->nodesetval->nodeTab[ctxt-> 13151 value-> 13152 nodesetval-> 13153 nodeNr - 13154 1]; 13155 ctxt->value->nodesetval->nodeNr = 1; 13156 } 13157 return (total); 13158 } 13159 } 13160 /* 13161 * Process inner predicates first. 13162 * Example "index[parent::book][1]": 13163 * ... 13164 * PREDICATE <-- we are here "[1]" 13165 * PREDICATE <-- process "[parent::book]" first 13166 * SORT 13167 * COLLECT 'parent' 'name' 'node' book 13168 * NODE 13169 * ELEM Object is a number : 1 13170 */ 13171 if (op->ch1 != -1) 13172 total += 13173 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13174 CHECK_ERROR0; 13175 if (op->ch2 == -1) 13176 return (total); 13177 if (ctxt->value == NULL) 13178 return (total); 13179 13180 oldnode = ctxt->context->node; 13181 13182#ifdef LIBXML_XPTR_ENABLED 13183 /* 13184 * Hum are we filtering the result of an XPointer expression 13185 */ 13186 if (ctxt->value->type == XPATH_LOCATIONSET) { 13187 xmlLocationSetPtr newlocset = NULL; 13188 xmlLocationSetPtr oldlocset; 13189 13190 /* 13191 * Extract the old locset, and then evaluate the result of the 13192 * expression for all the element in the locset. use it to grow 13193 * up a new locset. 13194 */ 13195 CHECK_TYPE0(XPATH_LOCATIONSET); 13196 obj = valuePop(ctxt); 13197 oldlocset = obj->user; 13198 ctxt->context->node = NULL; 13199 13200 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13201 ctxt->context->contextSize = 0; 13202 ctxt->context->proximityPosition = 0; 13203 if (op->ch2 != -1) 13204 total += 13205 xmlXPathCompOpEval(ctxt, 13206 &comp->steps[op->ch2]); 13207 res = valuePop(ctxt); 13208 if (res != NULL) { 13209 xmlXPathReleaseObject(ctxt->context, res); 13210 } 13211 valuePush(ctxt, obj); 13212 CHECK_ERROR0; 13213 return (total); 13214 } 13215 newlocset = xmlXPtrLocationSetCreate(NULL); 13216 13217 for (i = 0; i < oldlocset->locNr; i++) { 13218 /* 13219 * Run the evaluation with a node list made of a 13220 * single item in the nodelocset. 13221 */ 13222 ctxt->context->node = oldlocset->locTab[i]->user; 13223 ctxt->context->contextSize = oldlocset->locNr; 13224 ctxt->context->proximityPosition = i + 1; 13225 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13226 ctxt->context->node); 13227 valuePush(ctxt, tmp); 13228 13229 if (op->ch2 != -1) 13230 total += 13231 xmlXPathCompOpEval(ctxt, 13232 &comp->steps[op->ch2]); 13233 if (ctxt->error != XPATH_EXPRESSION_OK) { 13234 xmlXPathFreeObject(obj); 13235 return(0); 13236 } 13237 13238 /* 13239 * The result of the evaluation need to be tested to 13240 * decided whether the filter succeeded or not 13241 */ 13242 res = valuePop(ctxt); 13243 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13244 xmlXPtrLocationSetAdd(newlocset, 13245 xmlXPathObjectCopy 13246 (oldlocset->locTab[i])); 13247 } 13248 13249 /* 13250 * Cleanup 13251 */ 13252 if (res != NULL) { 13253 xmlXPathReleaseObject(ctxt->context, res); 13254 } 13255 if (ctxt->value == tmp) { 13256 res = valuePop(ctxt); 13257 xmlXPathReleaseObject(ctxt->context, res); 13258 } 13259 13260 ctxt->context->node = NULL; 13261 } 13262 13263 /* 13264 * The result is used as the new evaluation locset. 13265 */ 13266 xmlXPathReleaseObject(ctxt->context, obj); 13267 ctxt->context->node = NULL; 13268 ctxt->context->contextSize = -1; 13269 ctxt->context->proximityPosition = -1; 13270 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13271 ctxt->context->node = oldnode; 13272 return (total); 13273 } 13274#endif /* LIBXML_XPTR_ENABLED */ 13275 13276 /* 13277 * Extract the old set, and then evaluate the result of the 13278 * expression for all the element in the set. use it to grow 13279 * up a new set. 13280 */ 13281 CHECK_TYPE0(XPATH_NODESET); 13282 obj = valuePop(ctxt); 13283 oldset = obj->nodesetval; 13284 13285 oldnode = ctxt->context->node; 13286 oldDoc = ctxt->context->doc; 13287 ctxt->context->node = NULL; 13288 13289 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 13290 ctxt->context->contextSize = 0; 13291 ctxt->context->proximityPosition = 0; 13292/* 13293 if (op->ch2 != -1) 13294 total += 13295 xmlXPathCompOpEval(ctxt, 13296 &comp->steps[op->ch2]); 13297 CHECK_ERROR0; 13298 res = valuePop(ctxt); 13299 if (res != NULL) 13300 xmlXPathFreeObject(res); 13301*/ 13302 valuePush(ctxt, obj); 13303 ctxt->context->node = oldnode; 13304 CHECK_ERROR0; 13305 } else { 13306 tmp = NULL; 13307 /* 13308 * Initialize the new set. 13309 * Also set the xpath document in case things like 13310 * key() evaluation are attempted on the predicate 13311 */ 13312 newset = xmlXPathNodeSetCreate(NULL); 13313 /* 13314 * SPEC XPath 1.0: 13315 * "For each node in the node-set to be filtered, the 13316 * PredicateExpr is evaluated with that node as the 13317 * context node, with the number of nodes in the 13318 * node-set as the context size, and with the proximity 13319 * position of the node in the node-set with respect to 13320 * the axis as the context position;" 13321 * @oldset is the node-set" to be filtered. 13322 * 13323 * SPEC XPath 1.0: 13324 * "only predicates change the context position and 13325 * context size (see [2.4 Predicates])." 13326 * Example: 13327 * node-set context pos 13328 * nA 1 13329 * nB 2 13330 * nC 3 13331 * After applying predicate [position() > 1] : 13332 * node-set context pos 13333 * nB 1 13334 * nC 2 13335 * 13336 * removed the first node in the node-set, then 13337 * the context position of the 13338 */ 13339 for (i = 0; i < oldset->nodeNr; i++) { 13340 /* 13341 * Run the evaluation with a node list made of 13342 * a single item in the nodeset. 13343 */ 13344 ctxt->context->node = oldset->nodeTab[i]; 13345 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && 13346 (oldset->nodeTab[i]->doc != NULL)) 13347 ctxt->context->doc = oldset->nodeTab[i]->doc; 13348 if (tmp == NULL) { 13349 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13350 ctxt->context->node); 13351 } else { 13352 xmlXPathNodeSetAddUnique(tmp->nodesetval, 13353 ctxt->context->node); 13354 } 13355 valuePush(ctxt, tmp); 13356 ctxt->context->contextSize = oldset->nodeNr; 13357 ctxt->context->proximityPosition = i + 1; 13358 /* 13359 * Evaluate the predicate against the context node. 13360 * Can/should we optimize position() predicates 13361 * here (e.g. "[1]")? 13362 */ 13363 if (op->ch2 != -1) 13364 total += 13365 xmlXPathCompOpEval(ctxt, 13366 &comp->steps[op->ch2]); 13367 if (ctxt->error != XPATH_EXPRESSION_OK) { 13368 xmlXPathFreeNodeSet(newset); 13369 xmlXPathFreeObject(obj); 13370 return(0); 13371 } 13372 13373 /* 13374 * The result of the evaluation needs to be tested to 13375 * decide whether the filter succeeded or not 13376 */ 13377 /* 13378 * OPTIMIZE TODO: Can we use 13379 * xmlXPathNodeSetAdd*Unique()* instead? 13380 */ 13381 res = valuePop(ctxt); 13382 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 13383 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 13384 } 13385 13386 /* 13387 * Cleanup 13388 */ 13389 if (res != NULL) { 13390 xmlXPathReleaseObject(ctxt->context, res); 13391 } 13392 if (ctxt->value == tmp) { 13393 valuePop(ctxt); 13394 xmlXPathNodeSetClear(tmp->nodesetval); 13395 /* 13396 * Don't free the temporary nodeset 13397 * in order to avoid massive recreation inside this 13398 * loop. 13399 */ 13400 } else 13401 tmp = NULL; 13402 ctxt->context->node = NULL; 13403 } 13404 if (tmp != NULL) 13405 xmlXPathReleaseObject(ctxt->context, tmp); 13406 /* 13407 * The result is used as the new evaluation set. 13408 */ 13409 xmlXPathReleaseObject(ctxt->context, obj); 13410 ctxt->context->node = NULL; 13411 ctxt->context->contextSize = -1; 13412 ctxt->context->proximityPosition = -1; 13413 /* may want to move this past the '}' later */ 13414 ctxt->context->doc = oldDoc; 13415 valuePush(ctxt, 13416 xmlXPathCacheWrapNodeSet(ctxt->context, newset)); 13417 } 13418 ctxt->context->node = oldnode; 13419 return (total); 13420 } 13421 case XPATH_OP_SORT: 13422 if (op->ch1 != -1) 13423 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13424 CHECK_ERROR0; 13425 if ((ctxt->value != NULL) && 13426 (ctxt->value->type == XPATH_NODESET) && 13427 (ctxt->value->nodesetval != NULL) && 13428 (ctxt->value->nodesetval->nodeNr > 1)) 13429 { 13430 xmlXPathNodeSetSort(ctxt->value->nodesetval); 13431 } 13432 return (total); 13433#ifdef LIBXML_XPTR_ENABLED 13434 case XPATH_OP_RANGETO:{ 13435 xmlXPathObjectPtr range; 13436 xmlXPathObjectPtr res, obj; 13437 xmlXPathObjectPtr tmp; 13438 xmlLocationSetPtr newlocset = NULL; 13439 xmlLocationSetPtr oldlocset; 13440 xmlNodeSetPtr oldset; 13441 int i, j; 13442 13443 if (op->ch1 != -1) 13444 total += 13445 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 13446 if (op->ch2 == -1) 13447 return (total); 13448 13449 if (ctxt->value->type == XPATH_LOCATIONSET) { 13450 /* 13451 * Extract the old locset, and then evaluate the result of the 13452 * expression for all the element in the locset. use it to grow 13453 * up a new locset. 13454 */ 13455 CHECK_TYPE0(XPATH_LOCATIONSET); 13456 obj = valuePop(ctxt); 13457 oldlocset = obj->user; 13458 13459 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 13460 ctxt->context->node = NULL; 13461 ctxt->context->contextSize = 0; 13462 ctxt->context->proximityPosition = 0; 13463 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); 13464 res = valuePop(ctxt); 13465 if (res != NULL) { 13466 xmlXPathReleaseObject(ctxt->context, res); 13467 } 13468 valuePush(ctxt, obj); 13469 CHECK_ERROR0; 13470 return (total); 13471 } 13472 newlocset = xmlXPtrLocationSetCreate(NULL); 13473 13474 for (i = 0; i < oldlocset->locNr; i++) { 13475 /* 13476 * Run the evaluation with a node list made of a 13477 * single item in the nodelocset. 13478 */ 13479 ctxt->context->node = oldlocset->locTab[i]->user; 13480 ctxt->context->contextSize = oldlocset->locNr; 13481 ctxt->context->proximityPosition = i + 1; 13482 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13483 ctxt->context->node); 13484 valuePush(ctxt, tmp); 13485 13486 if (op->ch2 != -1) 13487 total += 13488 xmlXPathCompOpEval(ctxt, 13489 &comp->steps[op->ch2]); 13490 if (ctxt->error != XPATH_EXPRESSION_OK) { 13491 xmlXPathFreeObject(obj); 13492 return(0); 13493 } 13494 13495 res = valuePop(ctxt); 13496 if (res->type == XPATH_LOCATIONSET) { 13497 xmlLocationSetPtr rloc = 13498 (xmlLocationSetPtr)res->user; 13499 for (j=0; j<rloc->locNr; j++) { 13500 range = xmlXPtrNewRange( 13501 oldlocset->locTab[i]->user, 13502 oldlocset->locTab[i]->index, 13503 rloc->locTab[j]->user2, 13504 rloc->locTab[j]->index2); 13505 if (range != NULL) { 13506 xmlXPtrLocationSetAdd(newlocset, range); 13507 } 13508 } 13509 } else { 13510 range = xmlXPtrNewRangeNodeObject( 13511 (xmlNodePtr)oldlocset->locTab[i]->user, res); 13512 if (range != NULL) { 13513 xmlXPtrLocationSetAdd(newlocset,range); 13514 } 13515 } 13516 13517 /* 13518 * Cleanup 13519 */ 13520 if (res != NULL) { 13521 xmlXPathReleaseObject(ctxt->context, res); 13522 } 13523 if (ctxt->value == tmp) { 13524 res = valuePop(ctxt); 13525 xmlXPathReleaseObject(ctxt->context, res); 13526 } 13527 13528 ctxt->context->node = NULL; 13529 } 13530 } else { /* Not a location set */ 13531 CHECK_TYPE0(XPATH_NODESET); 13532 obj = valuePop(ctxt); 13533 oldset = obj->nodesetval; 13534 ctxt->context->node = NULL; 13535 13536 newlocset = xmlXPtrLocationSetCreate(NULL); 13537 13538 if (oldset != NULL) { 13539 for (i = 0; i < oldset->nodeNr; i++) { 13540 /* 13541 * Run the evaluation with a node list made of a single item 13542 * in the nodeset. 13543 */ 13544 ctxt->context->node = oldset->nodeTab[i]; 13545 /* 13546 * OPTIMIZE TODO: Avoid recreation for every iteration. 13547 */ 13548 tmp = xmlXPathCacheNewNodeSet(ctxt->context, 13549 ctxt->context->node); 13550 valuePush(ctxt, tmp); 13551 13552 if (op->ch2 != -1) 13553 total += 13554 xmlXPathCompOpEval(ctxt, 13555 &comp->steps[op->ch2]); 13556 if (ctxt->error != XPATH_EXPRESSION_OK) { 13557 xmlXPathFreeObject(obj); 13558 return(0); 13559 } 13560 13561 res = valuePop(ctxt); 13562 range = 13563 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 13564 res); 13565 if (range != NULL) { 13566 xmlXPtrLocationSetAdd(newlocset, range); 13567 } 13568 13569 /* 13570 * Cleanup 13571 */ 13572 if (res != NULL) { 13573 xmlXPathReleaseObject(ctxt->context, res); 13574 } 13575 if (ctxt->value == tmp) { 13576 res = valuePop(ctxt); 13577 xmlXPathReleaseObject(ctxt->context, res); 13578 } 13579 13580 ctxt->context->node = NULL; 13581 } 13582 } 13583 } 13584 13585 /* 13586 * The result is used as the new evaluation set. 13587 */ 13588 xmlXPathReleaseObject(ctxt->context, obj); 13589 ctxt->context->node = NULL; 13590 ctxt->context->contextSize = -1; 13591 ctxt->context->proximityPosition = -1; 13592 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 13593 return (total); 13594 } 13595#endif /* LIBXML_XPTR_ENABLED */ 13596 } 13597 xmlGenericError(xmlGenericErrorContext, 13598 "XPath: unknown precompiled operation %d\n", op->op); 13599 return (total); 13600} 13601 13602#ifdef XPATH_STREAMING 13603/** 13604 * xmlXPathRunStreamEval: 13605 * @ctxt: the XPath parser context with the compiled expression 13606 * 13607 * Evaluate the Precompiled Streamable XPath expression in the given context. 13608 */ 13609static xmlXPathObjectPtr 13610xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) { 13611 int max_depth, min_depth; 13612 int from_root; 13613 int ret, depth; 13614#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED 13615 int eval_all_nodes; 13616#endif 13617 xmlNodePtr cur = NULL, limit = NULL; 13618 xmlXPathObjectPtr retval; 13619 xmlStreamCtxtPtr patstream; 13620 13621 int nb_nodes = 0; 13622 13623 if ((ctxt == NULL) || (comp == NULL)) 13624 return(NULL); 13625 max_depth = xmlPatternMaxDepth(comp); 13626 if (max_depth == -1) 13627 return(NULL); 13628 if (max_depth == -2) 13629 max_depth = 10000; 13630 min_depth = xmlPatternMinDepth(comp); 13631 if (min_depth == -1) 13632 return(NULL); 13633 from_root = xmlPatternFromRoot(comp); 13634 if (from_root < 0) 13635 return(NULL); 13636#if 0 13637 printf("stream eval: depth %d from root %d\n", max_depth, from_root); 13638#endif 13639 13640 retval = xmlXPathCacheNewNodeSet(ctxt, NULL); 13641 if (retval == NULL) 13642 return(NULL); 13643 13644 /* 13645 * handle the special cases of / amd . being matched 13646 */ 13647 if (min_depth == 0) { 13648 if (from_root) { 13649 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc); 13650 } else { 13651 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node); 13652 } 13653 } 13654 if (max_depth == 0) { 13655 return(retval); 13656 } 13657 13658 if (from_root) { 13659 cur = (xmlNodePtr)ctxt->doc; 13660 } else if (ctxt->node != NULL) { 13661 switch (ctxt->node->type) { 13662 case XML_ELEMENT_NODE: 13663 case XML_DOCUMENT_NODE: 13664 case XML_DOCUMENT_FRAG_NODE: 13665 case XML_HTML_DOCUMENT_NODE: 13666#ifdef LIBXML_DOCB_ENABLED 13667 case XML_DOCB_DOCUMENT_NODE: 13668#endif 13669 cur = ctxt->node; 13670 break; 13671 case XML_ATTRIBUTE_NODE: 13672 case XML_TEXT_NODE: 13673 case XML_CDATA_SECTION_NODE: 13674 case XML_ENTITY_REF_NODE: 13675 case XML_ENTITY_NODE: 13676 case XML_PI_NODE: 13677 case XML_COMMENT_NODE: 13678 case XML_NOTATION_NODE: 13679 case XML_DTD_NODE: 13680 case XML_DOCUMENT_TYPE_NODE: 13681 case XML_ELEMENT_DECL: 13682 case XML_ATTRIBUTE_DECL: 13683 case XML_ENTITY_DECL: 13684 case XML_NAMESPACE_DECL: 13685 case XML_XINCLUDE_START: 13686 case XML_XINCLUDE_END: 13687 break; 13688 } 13689 limit = cur; 13690 } 13691 if (cur == NULL) 13692 return(retval); 13693 13694 patstream = xmlPatternGetStreamCtxt(comp); 13695 if (patstream == NULL) { 13696 return(retval); 13697 } 13698 13699#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED 13700 eval_all_nodes = xmlStreamWantsAnyNode(patstream); 13701#endif 13702 13703 if (from_root) { 13704 ret = xmlStreamPush(patstream, NULL, NULL); 13705 if (ret < 0) { 13706 } else if (ret == 1) { 13707 xmlXPathNodeSetAddUnique(retval->nodesetval, cur); 13708 } 13709 } 13710 depth = 0; 13711 goto scan_children; 13712next_node: 13713 do { 13714 nb_nodes++; 13715 13716 switch (cur->type) { 13717 case XML_ELEMENT_NODE: 13718#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED 13719 case XML_TEXT_NODE: 13720 case XML_CDATA_SECTION_NODE: 13721 case XML_COMMENT_NODE: 13722 case XML_PI_NODE: 13723#endif 13724 if (cur->type == XML_ELEMENT_NODE) { 13725 ret = xmlStreamPush(patstream, cur->name, 13726 (cur->ns ? cur->ns->href : NULL)); 13727 } 13728#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED 13729 else if (eval_all_nodes) 13730 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); 13731 else 13732 break; 13733#endif 13734 13735 if (ret < 0) { 13736 /* NOP. */ 13737 } else if (ret == 1) { 13738 xmlXPathNodeSetAddUnique(retval->nodesetval, cur); 13739 } 13740 if ((cur->children == NULL) || (depth >= max_depth)) { 13741 ret = xmlStreamPop(patstream); 13742 while (cur->next != NULL) { 13743 cur = cur->next; 13744 if ((cur->type != XML_ENTITY_DECL) && 13745 (cur->type != XML_DTD_NODE)) 13746 goto next_node; 13747 } 13748 } 13749 default: 13750 break; 13751 } 13752 13753scan_children: 13754 if ((cur->children != NULL) && (depth < max_depth)) { 13755 /* 13756 * Do not descend on entities declarations 13757 */ 13758 if (cur->children->type != XML_ENTITY_DECL) { 13759 cur = cur->children; 13760 depth++; 13761 /* 13762 * Skip DTDs 13763 */ 13764 if (cur->type != XML_DTD_NODE) 13765 continue; 13766 } 13767 } 13768 13769 if (cur == limit) 13770 break; 13771 13772 while (cur->next != NULL) { 13773 cur = cur->next; 13774 if ((cur->type != XML_ENTITY_DECL) && 13775 (cur->type != XML_DTD_NODE)) 13776 goto next_node; 13777 } 13778 13779 do { 13780 cur = cur->parent; 13781 depth--; 13782 if ((cur == NULL) || (cur == limit)) 13783 goto done; 13784 if (cur->type == XML_ELEMENT_NODE) { 13785 ret = xmlStreamPop(patstream); 13786 } 13787#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED 13788 else if ((eval_all_nodes) && 13789 ((cur->type == XML_TEXT_NODE) || 13790 (cur->type == XML_CDATA_SECTION_NODE) || 13791 (cur->type == XML_COMMENT_NODE) || 13792 (cur->type == XML_PI_NODE))) 13793 { 13794 ret = xmlStreamPop(patstream); 13795 } 13796#endif 13797 if (cur->next != NULL) { 13798 cur = cur->next; 13799 break; 13800 } 13801 } while (cur != NULL); 13802 13803 } while ((cur != NULL) && (depth >= 0)); 13804done: 13805#if 0 13806 printf("stream eval: checked %d nodes selected %d\n", 13807 nb_nodes, retval->nodesetval->nodeNr); 13808#endif 13809 xmlFreeStreamCtxt(patstream); 13810 return(retval); 13811} 13812#endif /* XPATH_STREAMING */ 13813 13814/** 13815 * xmlXPathRunEval: 13816 * @ctxt: the XPath parser context with the compiled expression 13817 * 13818 * Evaluate the Precompiled XPath expression in the given context. 13819 */ 13820static void 13821xmlXPathRunEval(xmlXPathParserContextPtr ctxt) { 13822 xmlXPathCompExprPtr comp; 13823 13824 if ((ctxt == NULL) || (ctxt->comp == NULL)) 13825 return; 13826 13827 if (ctxt->valueTab == NULL) { 13828 /* Allocate the value stack */ 13829 ctxt->valueTab = (xmlXPathObjectPtr *) 13830 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 13831 if (ctxt->valueTab == NULL) { 13832 xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); 13833 xmlFree(ctxt); 13834 } 13835 ctxt->valueNr = 0; 13836 ctxt->valueMax = 10; 13837 ctxt->value = NULL; 13838 } 13839#ifdef XPATH_STREAMING 13840 if (ctxt->comp->stream) { 13841 xmlXPathObjectPtr ret; 13842 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream); 13843 if (ret != NULL) { 13844 valuePush(ctxt, ret); 13845 return; 13846 } 13847 } 13848#endif 13849 comp = ctxt->comp; 13850 if(comp->last < 0) { 13851 xmlGenericError(xmlGenericErrorContext, 13852 "xmlXPathRunEval: last is less than zero\n"); 13853 return; 13854 } 13855 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 13856} 13857 13858/************************************************************************ 13859 * * 13860 * Public interfaces * 13861 * * 13862 ************************************************************************/ 13863 13864/** 13865 * xmlXPathEvalPredicate: 13866 * @ctxt: the XPath context 13867 * @res: the Predicate Expression evaluation result 13868 * 13869 * Evaluate a predicate result for the current node. 13870 * A PredicateExpr is evaluated by evaluating the Expr and converting 13871 * the result to a boolean. If the result is a number, the result will 13872 * be converted to true if the number is equal to the position of the 13873 * context node in the context node list (as returned by the position 13874 * function) and will be converted to false otherwise; if the result 13875 * is not a number, then the result will be converted as if by a call 13876 * to the boolean function. 13877 * 13878 * Returns 1 if predicate is true, 0 otherwise 13879 */ 13880int 13881xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 13882 if ((ctxt == NULL) || (res == NULL)) return(0); 13883 switch (res->type) { 13884 case XPATH_BOOLEAN: 13885 return(res->boolval); 13886 case XPATH_NUMBER: 13887 return(res->floatval == ctxt->proximityPosition); 13888 case XPATH_NODESET: 13889 case XPATH_XSLT_TREE: 13890 if (res->nodesetval == NULL) 13891 return(0); 13892 return(res->nodesetval->nodeNr != 0); 13893 case XPATH_STRING: 13894 return((res->stringval != NULL) && 13895 (xmlStrlen(res->stringval) != 0)); 13896 default: 13897 STRANGE 13898 } 13899 return(0); 13900} 13901 13902/** 13903 * xmlXPathEvaluatePredicateResult: 13904 * @ctxt: the XPath Parser context 13905 * @res: the Predicate Expression evaluation result 13906 * 13907 * Evaluate a predicate result for the current node. 13908 * A PredicateExpr is evaluated by evaluating the Expr and converting 13909 * the result to a boolean. If the result is a number, the result will 13910 * be converted to true if the number is equal to the position of the 13911 * context node in the context node list (as returned by the position 13912 * function) and will be converted to false otherwise; if the result 13913 * is not a number, then the result will be converted as if by a call 13914 * to the boolean function. 13915 * 13916 * Returns 1 if predicate is true, 0 otherwise 13917 */ 13918int 13919xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 13920 xmlXPathObjectPtr res) { 13921 if ((ctxt == NULL) || (res == NULL)) return(0); 13922 switch (res->type) { 13923 case XPATH_BOOLEAN: 13924 return(res->boolval); 13925 case XPATH_NUMBER: 13926#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) 13927 return((res->floatval == ctxt->context->proximityPosition) && 13928 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ 13929#else 13930 return(res->floatval == ctxt->context->proximityPosition); 13931#endif 13932 case XPATH_NODESET: 13933 case XPATH_XSLT_TREE: 13934 if (res->nodesetval == NULL) 13935 return(0); 13936 return(res->nodesetval->nodeNr != 0); 13937 case XPATH_STRING: 13938 return((res->stringval != NULL) && 13939 (xmlStrlen(res->stringval) != 0)); 13940#ifdef LIBXML_XPTR_ENABLED 13941 case XPATH_LOCATIONSET:{ 13942 xmlLocationSetPtr ptr = res->user; 13943 if (ptr == NULL) 13944 return(0); 13945 return (ptr->locNr != 0); 13946 } 13947#endif 13948 default: 13949 STRANGE 13950 } 13951 return(0); 13952} 13953 13954#ifdef XPATH_STREAMING 13955/** 13956 * xmlXPathTryStreamCompile: 13957 * @ctxt: an XPath context 13958 * @str: the XPath expression 13959 * 13960 * Try to compile the XPath expression as a streamable subset. 13961 * 13962 * Returns the compiled expression or NULL if failed to compile. 13963 */ 13964static xmlXPathCompExprPtr 13965xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 13966 /* 13967 * Optimization: use streaming patterns when the XPath expression can 13968 * be compiled to a stream lookup 13969 */ 13970 xmlPatternPtr stream; 13971 xmlXPathCompExprPtr comp; 13972 xmlDictPtr dict = NULL; 13973 const xmlChar **namespaces = NULL; 13974 xmlNsPtr ns; 13975 int i, j; 13976 13977 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && 13978 (!xmlStrchr(str, '@'))) { 13979 const xmlChar *tmp; 13980 13981 /* 13982 * We don't try to handle expressions using the verbose axis 13983 * specifiers ("::"), just the simplied form at this point. 13984 * Additionally, if there is no list of namespaces available and 13985 * there's a ":" in the expression, indicating a prefixed QName, 13986 * then we won't try to compile either. xmlPatterncompile() needs 13987 * to have a list of namespaces at compilation time in order to 13988 * compile prefixed name tests. 13989 */ 13990 tmp = xmlStrchr(str, ':'); 13991 if ((tmp != NULL) && 13992 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) 13993 return(NULL); 13994 13995 if (ctxt != NULL) { 13996 dict = ctxt->dict; 13997 if (ctxt->nsNr > 0) { 13998 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); 13999 if (namespaces == NULL) { 14000 xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); 14001 return(NULL); 14002 } 14003 for (i = 0, j = 0; (j < ctxt->nsNr); j++) { 14004 ns = ctxt->namespaces[j]; 14005 namespaces[i++] = ns->href; 14006 namespaces[i++] = ns->prefix; 14007 } 14008 namespaces[i++] = NULL; 14009 namespaces[i++] = NULL; 14010 } 14011 } 14012 14013 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, 14014 &namespaces[0]); 14015 if (namespaces != NULL) { 14016 xmlFree((xmlChar **)namespaces); 14017 } 14018 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { 14019 comp = xmlXPathNewCompExpr(); 14020 if (comp == NULL) { 14021 xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); 14022 return(NULL); 14023 } 14024 comp->stream = stream; 14025 comp->dict = dict; 14026 if (comp->dict) 14027 xmlDictReference(comp->dict); 14028 return(comp); 14029 } 14030 xmlFreePattern(stream); 14031 } 14032 return(NULL); 14033} 14034#endif /* XPATH_STREAMING */ 14035 14036static int 14037xmlXPathCanRewriteDosExpression(xmlChar *expr) 14038{ 14039 if (expr == NULL) 14040 return(0); 14041 do { 14042 if ((*expr == '/') && (*(++expr) == '/')) 14043 return(1); 14044 } while (*expr++); 14045 return(0); 14046} 14047static void 14048xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) 14049{ 14050 /* 14051 * Try to rewrite "descendant-or-self::node()/foo" to an optimized 14052 * internal representation. 14053 */ 14054 if (op->ch1 != -1) { 14055 if ((op->op == XPATH_OP_COLLECT /* 11 */) && 14056 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) && 14057 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) && 14058 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */)) 14059 { 14060 /* 14061 * This is an "foo" 14062 */ 14063 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; 14064 14065 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && 14066 (prevop->ch1 != -1) && 14067 ((xmlXPathAxisVal) prevop->value == 14068 AXIS_DESCENDANT_OR_SELF) && 14069 (prevop->ch2 == -1) && 14070 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && 14071 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) && 14072 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT)) 14073 { 14074 /* 14075 * This is a "descendant-or-self::node()" without predicates. 14076 * Eliminate it. 14077 */ 14078 op->ch1 = prevop->ch1; 14079 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM; 14080 } 14081 } 14082 if (op->ch1 != -1) 14083 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]); 14084 } 14085 if (op->ch2 != -1) 14086 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]); 14087} 14088 14089/** 14090 * xmlXPathCtxtCompile: 14091 * @ctxt: an XPath context 14092 * @str: the XPath expression 14093 * 14094 * Compile an XPath expression 14095 * 14096 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14097 * the caller has to free the object. 14098 */ 14099xmlXPathCompExprPtr 14100xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { 14101 xmlXPathParserContextPtr pctxt; 14102 xmlXPathCompExprPtr comp; 14103 14104#ifdef XPATH_STREAMING 14105 comp = xmlXPathTryStreamCompile(ctxt, str); 14106 if (comp != NULL) 14107 return(comp); 14108#endif 14109 14110 xmlXPathInit(); 14111 14112 pctxt = xmlXPathNewParserContext(str, ctxt); 14113 xmlXPathCompileExpr(pctxt, 1); 14114 14115 if( pctxt->error != XPATH_EXPRESSION_OK ) 14116 { 14117 xmlXPathFreeParserContext(pctxt); 14118 return(NULL); 14119 } 14120 14121 if (*pctxt->cur != 0) { 14122 /* 14123 * aleksey: in some cases this line prints *second* error message 14124 * (see bug #78858) and probably this should be fixed. 14125 * However, we are not sure that all error messages are printed 14126 * out in other places. It's not critical so we leave it as-is for now 14127 */ 14128 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14129 comp = NULL; 14130 } else { 14131 comp = pctxt->comp; 14132 pctxt->comp = NULL; 14133 } 14134 xmlXPathFreeParserContext(pctxt); 14135 if (comp != NULL) { 14136 comp->expr = xmlStrdup(str); 14137#ifdef DEBUG_EVAL_COUNTS 14138 comp->string = xmlStrdup(str); 14139 comp->nb = 0; 14140#endif 14141 if ((comp->nbStep > 2) && 14142 (xmlXPathCanRewriteDosExpression(comp->expr) == 1)) 14143 { 14144 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]); 14145 } 14146 } 14147 return(comp); 14148} 14149 14150/** 14151 * xmlXPathCompile: 14152 * @str: the XPath expression 14153 * 14154 * Compile an XPath expression 14155 * 14156 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. 14157 * the caller has to free the object. 14158 */ 14159xmlXPathCompExprPtr 14160xmlXPathCompile(const xmlChar *str) { 14161 return(xmlXPathCtxtCompile(NULL, str)); 14162} 14163 14164/** 14165 * xmlXPathCompiledEval: 14166 * @comp: the compiled XPath expression 14167 * @ctx: the XPath context 14168 * 14169 * Evaluate the Precompiled XPath expression in the given context. 14170 * 14171 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14172 * the caller has to free the object. 14173 */ 14174xmlXPathObjectPtr 14175xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) { 14176 xmlXPathParserContextPtr ctxt; 14177 xmlXPathObjectPtr res, tmp, init = NULL; 14178 int stack = 0; 14179#ifndef LIBXML_THREAD_ENABLED 14180 static int reentance = 0; 14181#endif 14182 14183 CHECK_CTXT(ctx) 14184 14185 if (comp == NULL) 14186 return(NULL); 14187 xmlXPathInit(); 14188 14189#ifndef LIBXML_THREAD_ENABLED 14190 reentance++; 14191 if (reentance > 1) 14192 xmlXPathDisableOptimizer = 1; 14193#endif 14194 14195#ifdef DEBUG_EVAL_COUNTS 14196 comp->nb++; 14197 if ((comp->string != NULL) && (comp->nb > 100)) { 14198 fprintf(stderr, "100 x %s\n", comp->string); 14199 comp->nb = 0; 14200 } 14201#endif 14202 ctxt = xmlXPathCompParserContext(comp, ctx); 14203 xmlXPathRunEval(ctxt); 14204 14205 if (ctxt->value == NULL) { 14206 xmlGenericError(xmlGenericErrorContext, 14207 "xmlXPathCompiledEval: evaluation failed\n"); 14208 res = NULL; 14209 } else { 14210 res = valuePop(ctxt); 14211 } 14212 14213 14214 do { 14215 tmp = valuePop(ctxt); 14216 if (tmp != NULL) { 14217 if (tmp != init) 14218 stack++; 14219 xmlXPathReleaseObject(ctx, tmp); 14220 } 14221 } while (tmp != NULL); 14222 if ((stack != 0) && (res != NULL)) { 14223 xmlGenericError(xmlGenericErrorContext, 14224 "xmlXPathCompiledEval: %d object left on the stack\n", 14225 stack); 14226 } 14227 if (ctxt->error != XPATH_EXPRESSION_OK) { 14228 xmlXPathFreeObject(res); 14229 res = NULL; 14230 } 14231 ctxt->comp = NULL; 14232 xmlXPathFreeParserContext(ctxt); 14233#ifndef LIBXML_THREAD_ENABLED 14234 reentance--; 14235#endif 14236 return(res); 14237} 14238 14239/** 14240 * xmlXPathEvalExpr: 14241 * @ctxt: the XPath Parser context 14242 * 14243 * Parse and evaluate an XPath expression in the given context, 14244 * then push the result on the context stack 14245 */ 14246void 14247xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 14248#ifdef XPATH_STREAMING 14249 xmlXPathCompExprPtr comp; 14250#endif 14251 14252 if (ctxt == NULL) return; 14253 14254#ifdef XPATH_STREAMING 14255 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); 14256 if (comp != NULL) { 14257 if (ctxt->comp != NULL) 14258 xmlXPathFreeCompExpr(ctxt->comp); 14259 ctxt->comp = comp; 14260 if (ctxt->cur != NULL) 14261 while (*ctxt->cur != 0) ctxt->cur++; 14262 } else 14263#endif 14264 { 14265 xmlXPathCompileExpr(ctxt, 1); 14266 if ((ctxt->comp != NULL) && 14267 (ctxt->comp->nbStep > 2) && 14268 (xmlXPathCanRewriteDosExpression(ctxt->comp->expr) == 1)) 14269 { 14270 xmlXPathRewriteDOSExpression(ctxt->comp, 14271 &ctxt->comp->steps[comp->last]); 14272 } 14273 } 14274 CHECK_ERROR; 14275 xmlXPathRunEval(ctxt); 14276} 14277 14278/** 14279 * xmlXPathEval: 14280 * @str: the XPath expression 14281 * @ctx: the XPath context 14282 * 14283 * Evaluate the XPath Location Path in the given context. 14284 * 14285 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14286 * the caller has to free the object. 14287 */ 14288xmlXPathObjectPtr 14289xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 14290 xmlXPathParserContextPtr ctxt; 14291 xmlXPathObjectPtr res, tmp, init = NULL; 14292 int stack = 0; 14293 14294 CHECK_CTXT(ctx) 14295 14296 xmlXPathInit(); 14297 14298 ctxt = xmlXPathNewParserContext(str, ctx); 14299 xmlXPathEvalExpr(ctxt); 14300 14301 if (ctxt->value == NULL) { 14302 xmlGenericError(xmlGenericErrorContext, 14303 "xmlXPathEval: evaluation failed\n"); 14304 res = NULL; 14305 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL) 14306#ifdef XPATH_STREAMING 14307 && (ctxt->comp->stream == NULL) 14308#endif 14309 ) { 14310 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14311 res = NULL; 14312 } else { 14313 res = valuePop(ctxt); 14314 } 14315 14316 do { 14317 tmp = valuePop(ctxt); 14318 if (tmp != NULL) { 14319 if (tmp != init) 14320 stack++; 14321 xmlXPathReleaseObject(ctx, tmp); 14322 } 14323 } while (tmp != NULL); 14324 if ((stack != 0) && (res != NULL)) { 14325 xmlGenericError(xmlGenericErrorContext, 14326 "xmlXPathEval: %d object left on the stack\n", 14327 stack); 14328 } 14329 if (ctxt->error != XPATH_EXPRESSION_OK) { 14330 xmlXPathFreeObject(res); 14331 res = NULL; 14332 } 14333 14334 xmlXPathFreeParserContext(ctxt); 14335 return(res); 14336} 14337 14338/** 14339 * xmlXPathEvalExpression: 14340 * @str: the XPath expression 14341 * @ctxt: the XPath context 14342 * 14343 * Evaluate the XPath expression in the given context. 14344 * 14345 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 14346 * the caller has to free the object. 14347 */ 14348xmlXPathObjectPtr 14349xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 14350 xmlXPathParserContextPtr pctxt; 14351 xmlXPathObjectPtr res, tmp; 14352 int stack = 0; 14353 14354 CHECK_CTXT(ctxt) 14355 14356 xmlXPathInit(); 14357 14358 pctxt = xmlXPathNewParserContext(str, ctxt); 14359 xmlXPathEvalExpr(pctxt); 14360 14361 if (*pctxt->cur != 0) { 14362 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 14363 res = NULL; 14364 } else { 14365 res = valuePop(pctxt); 14366 } 14367 do { 14368 tmp = valuePop(pctxt); 14369 if (tmp != NULL) { 14370 xmlXPathReleaseObject(ctxt, tmp); 14371 stack++; 14372 } 14373 } while (tmp != NULL); 14374 if ((stack != 0) && (res != NULL)) { 14375 xmlGenericError(xmlGenericErrorContext, 14376 "xmlXPathEvalExpression: %d object left on the stack\n", 14377 stack); 14378 } 14379 xmlXPathFreeParserContext(pctxt); 14380 return(res); 14381} 14382 14383/************************************************************************ 14384 * * 14385 * Extra functions not pertaining to the XPath spec * 14386 * * 14387 ************************************************************************/ 14388/** 14389 * xmlXPathEscapeUriFunction: 14390 * @ctxt: the XPath Parser context 14391 * @nargs: the number of arguments 14392 * 14393 * Implement the escape-uri() XPath function 14394 * string escape-uri(string $str, bool $escape-reserved) 14395 * 14396 * This function applies the URI escaping rules defined in section 2 of [RFC 14397 * 2396] to the string supplied as $uri-part, which typically represents all 14398 * or part of a URI. The effect of the function is to replace any special 14399 * character in the string by an escape sequence of the form %xx%yy..., 14400 * where xxyy... is the hexadecimal representation of the octets used to 14401 * represent the character in UTF-8. 14402 * 14403 * The set of characters that are escaped depends on the setting of the 14404 * boolean argument $escape-reserved. 14405 * 14406 * If $escape-reserved is true, all characters are escaped other than lower 14407 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters 14408 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" 14409 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only 14410 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and 14411 * A-F). 14412 * 14413 * If $escape-reserved is false, the behavior differs in that characters 14414 * referred to in [RFC 2396] as reserved characters are not escaped. These 14415 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 14416 * 14417 * [RFC 2396] does not define whether escaped URIs should use lower case or 14418 * upper case for hexadecimal digits. To ensure that escaped URIs can be 14419 * compared using string comparison functions, this function must always use 14420 * the upper-case letters A-F. 14421 * 14422 * Generally, $escape-reserved should be set to true when escaping a string 14423 * that is to form a single part of a URI, and to false when escaping an 14424 * entire URI or URI reference. 14425 * 14426 * In the case of non-ascii characters, the string is encoded according to 14427 * utf-8 and then converted according to RFC 2396. 14428 * 14429 * Examples 14430 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) 14431 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" 14432 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) 14433 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" 14434 * 14435 */ 14436static void 14437xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { 14438 xmlXPathObjectPtr str; 14439 int escape_reserved; 14440 xmlBufferPtr target; 14441 xmlChar *cptr; 14442 xmlChar escape[4]; 14443 14444 CHECK_ARITY(2); 14445 14446 escape_reserved = xmlXPathPopBoolean(ctxt); 14447 14448 CAST_TO_STRING; 14449 str = valuePop(ctxt); 14450 14451 target = xmlBufferCreate(); 14452 14453 escape[0] = '%'; 14454 escape[3] = 0; 14455 14456 if (target) { 14457 for (cptr = str->stringval; *cptr; cptr++) { 14458 if ((*cptr >= 'A' && *cptr <= 'Z') || 14459 (*cptr >= 'a' && *cptr <= 'z') || 14460 (*cptr >= '0' && *cptr <= '9') || 14461 *cptr == '-' || *cptr == '_' || *cptr == '.' || 14462 *cptr == '!' || *cptr == '~' || *cptr == '*' || 14463 *cptr == '\''|| *cptr == '(' || *cptr == ')' || 14464 (*cptr == '%' && 14465 ((cptr[1] >= 'A' && cptr[1] <= 'F') || 14466 (cptr[1] >= 'a' && cptr[1] <= 'f') || 14467 (cptr[1] >= '0' && cptr[1] <= '9')) && 14468 ((cptr[2] >= 'A' && cptr[2] <= 'F') || 14469 (cptr[2] >= 'a' && cptr[2] <= 'f') || 14470 (cptr[2] >= '0' && cptr[2] <= '9'))) || 14471 (!escape_reserved && 14472 (*cptr == ';' || *cptr == '/' || *cptr == '?' || 14473 *cptr == ':' || *cptr == '@' || *cptr == '&' || 14474 *cptr == '=' || *cptr == '+' || *cptr == '$' || 14475 *cptr == ','))) { 14476 xmlBufferAdd(target, cptr, 1); 14477 } else { 14478 if ((*cptr >> 4) < 10) 14479 escape[1] = '0' + (*cptr >> 4); 14480 else 14481 escape[1] = 'A' - 10 + (*cptr >> 4); 14482 if ((*cptr & 0xF) < 10) 14483 escape[2] = '0' + (*cptr & 0xF); 14484 else 14485 escape[2] = 'A' - 10 + (*cptr & 0xF); 14486 14487 xmlBufferAdd(target, &escape[0], 3); 14488 } 14489 } 14490 } 14491 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, 14492 xmlBufferContent(target))); 14493 xmlBufferFree(target); 14494 xmlXPathReleaseObject(ctxt->context, str); 14495} 14496 14497/** 14498 * xmlXPathRegisterAllFunctions: 14499 * @ctxt: the XPath context 14500 * 14501 * Registers all default XPath functions in this context 14502 */ 14503void 14504xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 14505{ 14506 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 14507 xmlXPathBooleanFunction); 14508 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 14509 xmlXPathCeilingFunction); 14510 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 14511 xmlXPathCountFunction); 14512 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 14513 xmlXPathConcatFunction); 14514 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 14515 xmlXPathContainsFunction); 14516 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 14517 xmlXPathIdFunction); 14518 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 14519 xmlXPathFalseFunction); 14520 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 14521 xmlXPathFloorFunction); 14522 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 14523 xmlXPathLastFunction); 14524 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 14525 xmlXPathLangFunction); 14526 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 14527 xmlXPathLocalNameFunction); 14528 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 14529 xmlXPathNotFunction); 14530 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 14531 xmlXPathNameFunction); 14532 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 14533 xmlXPathNamespaceURIFunction); 14534 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 14535 xmlXPathNormalizeFunction); 14536 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 14537 xmlXPathNumberFunction); 14538 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 14539 xmlXPathPositionFunction); 14540 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 14541 xmlXPathRoundFunction); 14542 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 14543 xmlXPathStringFunction); 14544 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 14545 xmlXPathStringLengthFunction); 14546 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 14547 xmlXPathStartsWithFunction); 14548 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 14549 xmlXPathSubstringFunction); 14550 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 14551 xmlXPathSubstringBeforeFunction); 14552 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 14553 xmlXPathSubstringAfterFunction); 14554 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 14555 xmlXPathSumFunction); 14556 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 14557 xmlXPathTrueFunction); 14558 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 14559 xmlXPathTranslateFunction); 14560 14561 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", 14562 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", 14563 xmlXPathEscapeUriFunction); 14564} 14565 14566#endif /* LIBXML_XPATH_ENABLED */ 14567#define bottom_xpath 14568#include "elfgcchack.h" 14569