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 (at) veillard.com 14 * 15 */ 16 17 #define IN_LIBXML 18 #include "libxml.h" 19 20 #include <string.h> 21 22 #ifdef HAVE_SYS_TYPES_H 23 #include <sys/types.h> 24 #endif 25 #ifdef HAVE_MATH_H 26 #include <math.h> 27 #endif 28 #ifdef HAVE_FLOAT_H 29 #include <float.h> 30 #endif 31 #ifdef HAVE_CTYPE_H 32 #include <ctype.h> 33 #endif 34 #ifdef HAVE_SIGNAL_H 35 #include <signal.h> 36 #endif 37 38 #include <libxml/xmlmemory.h> 39 #include <libxml/tree.h> 40 #include <libxml/valid.h> 41 #include <libxml/xpath.h> 42 #include <libxml/xpathInternals.h> 43 #include <libxml/parserInternals.h> 44 #include <libxml/hash.h> 45 #ifdef LIBXML_XPTR_ENABLED 46 #include <libxml/xpointer.h> 47 #endif 48 #ifdef LIBXML_DEBUG_ENABLED 49 #include <libxml/debugXML.h> 50 #endif 51 #include <libxml/xmlerror.h> 52 #include <libxml/threads.h> 53 #include <libxml/globals.h> 54 #ifdef LIBXML_PATTERN_ENABLED 55 #include <libxml/pattern.h> 56 #endif 57 58 #ifdef LIBXML_PATTERN_ENABLED 59 #define XPATH_STREAMING 60 #endif 61 62 #define TODO \ 63 xmlGenericError(xmlGenericErrorContext, \ 64 "Unimplemented block at %s:%d\n", \ 65 __FILE__, __LINE__); 66 67 /* 68 * XP_OPTIMIZED_NON_ELEM_COMPARISON: 69 * If defined, this will use xmlXPathCmpNodesExt() instead of 70 * xmlXPathCmpNodes(). The new function is optimized comparison of 71 * non-element nodes; actually it will speed up comparison only if 72 * xmlXPathOrderDocElems() was called in order to index the elements of 73 * a tree in document order; Libxslt does such an indexing, thus it will 74 * benefit from this optimization. 75 */ 76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON 77 78 /* 79 * XP_OPTIMIZED_FILTER_FIRST: 80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]" 81 * in a way, that it stop evaluation at the first node. 82 */ 83 #define XP_OPTIMIZED_FILTER_FIRST 84 85 /* 86 * XP_DEBUG_OBJ_USAGE: 87 * Internal flag to enable tracking of how much XPath objects have been 88 * created. 89 */ 90 /* #define XP_DEBUG_OBJ_USAGE */ 91 92 /* 93 * TODO: 94 * There are a few spots where some tests are done which depend upon ascii 95 * data. These should be enhanced for full UTF8 support (see particularly 96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) 97 */ 98 99 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 100 101 /************************************************************************ 102 * * 103 * Floating point stuff * 104 * * 105 ************************************************************************/ 106 107 #ifndef TRIO_REPLACE_STDIO 108 #define TRIO_PUBLIC static 109 #endif 110 #include "trionan.c" 111 112 /* 113 * The lack of portability of this section of the libc is annoying ! 114 */ 115 double xmlXPathNAN = 0; 116 double xmlXPathPINF = 1; 117 double xmlXPathNINF = -1; 118 static double xmlXPathNZERO = 0; /* not exported from headers */ 119 static int xmlXPathInitialized = 0; 120 121 /** 122 * xmlXPathInit: 123 * 124 * Initialize the XPath environment 125 */ 126 void 127 xmlXPathInit(void) { 128 if (xmlXPathInitialized) return; 129 130 xmlXPathPINF = trio_pinf(); 131 xmlXPathNINF = trio_ninf(); 132 xmlXPathNAN = trio_nan(); 133 xmlXPathNZERO = trio_nzero(); 134 135 xmlXPathInitialized = 1; 136 } 137 138 /** 139 * xmlXPathIsNaN: 140 * @val: a double value 141 * 142 * Provides a portable isnan() function to detect whether a double 143 * is a NotaNumber. Based on trio code 144 * http://sourceforge.net/projects/ctrio/ 145 * 146 * Returns 1 if the value is a NaN, 0 otherwise 147 */ 148 int 149 xmlXPathIsNaN(double val) { 150 return(trio_isnan(val)); 151 } 152 153 /** 154 * xmlXPathIsInf: 155 * @val: a double value 156 * 157 * Provides a portable isinf() function to detect whether a double 158 * is a +Infinite or -Infinite. Based on trio code 159 * http://sourceforge.net/projects/ctrio/ 160 * 161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise 162 */ 163 int 164 xmlXPathIsInf(double val) { 165 return(trio_isinf(val)); 166 } 167 168 #endif /* SCHEMAS or XPATH */ 169 #ifdef LIBXML_XPATH_ENABLED 170 /** 171 * xmlXPathGetSign: 172 * @val: a double value 173 * 174 * Provides a portable function to detect the sign of a double 175 * Modified from trio code 176 * http://sourceforge.net/projects/ctrio/ 177 * 178 * Returns 1 if the value is Negative, 0 if positive 179 */ 180 static int 181 xmlXPathGetSign(double val) { 182 return(trio_signbit(val)); 183 } 184 185 186 /* 187 * TODO: when compatibility allows remove all "fake node libxslt" strings 188 * the test should just be name[0] = ' ' 189 */ 190 #ifdef DEBUG_XPATH_EXPRESSION 191 #define DEBUG_STEP 192 #define DEBUG_EXPR 193 #define DEBUG_EVAL_COUNTS 194 #endif 195 196 static xmlNs xmlXPathXMLNamespaceStruct = { 197 NULL, 198 XML_NAMESPACE_DECL, 199 XML_XML_NAMESPACE, 200 BAD_CAST "xml", 201 NULL, 202 NULL 203 }; 204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 205 #ifndef LIBXML_THREAD_ENABLED 206 /* 207 * Optimizer is disabled only when threaded apps are detected while 208 * the library ain't compiled for thread safety. 209 */ 210 static int xmlXPathDisableOptimizer = 0; 211 #endif 212 213 /************************************************************************ 214 * * 215 * Error handling routines * 216 * * 217 ************************************************************************/ 218 219 /** 220 * XP_ERRORNULL: 221 * @X: the error code 222 * 223 * Macro to raise an XPath error and return NULL. 224 */ 225 #define XP_ERRORNULL(X) \ 226 { xmlXPathErr(ctxt, X); return(NULL); } 227 228 /* 229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError 230 */ 231 static const char *xmlXPathErrorMessages[] = { 232 "Ok\n", 233 "Number encoding\n", 234 "Unfinished literal\n", 235 "Start of literal\n", 236 "Expected $ for variable reference\n", 237 "Undefined variable\n", 238 "Invalid predicate\n", 239 "Invalid expression\n", 240 "Missing closing curly brace\n", 241 "Unregistered function\n", 242 "Invalid operand\n", 243 "Invalid type\n", 244 "Invalid number of arguments\n", 245 "Invalid context size\n", 246 "Invalid context position\n", 247 "Memory allocation error\n", 248 "Syntax error\n", 249 "Resource error\n", 250 "Sub resource error\n", 251 "Undefined namespace prefix\n", 252 "Encoding error\n", 253 "Char out of XML range\n", 254 "Invalid or incomplete context\n", 255 "Stack usage errror\n", 256 "?? Unknown error ??\n" /* Must be last in the list! */ 257 }; 258 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ 259 sizeof(xmlXPathErrorMessages[0])) - 1) 260 /** 261 * xmlXPathErrMemory: 262 * @ctxt: an XPath context 263 * @extra: extra informations 264 * 265 * Handle a redefinition of attribute error 266 */ 267 static void 268 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) 269 { 270 if (ctxt != NULL) { 271 if (extra) { 272 xmlChar buf[200]; 273 274 xmlStrPrintf(buf, 200, 275 BAD_CAST "Memory allocation failed : %s\n", 276 extra); 277 ctxt->lastError.message = (char *) xmlStrdup(buf); 278 } else { 279 ctxt->lastError.message = (char *) 280 xmlStrdup(BAD_CAST "Memory allocation failed\n"); 281 } 282 ctxt->lastError.domain = XML_FROM_XPATH; 283 ctxt->lastError.code = XML_ERR_NO_MEMORY; 284 if (ctxt->error != NULL) 285 ctxt->error(ctxt->userData, &ctxt->lastError); 286 } else { 287 if (extra) 288 __xmlRaiseError(NULL, NULL, NULL, 289 NULL, NULL, XML_FROM_XPATH, 290 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 291 extra, NULL, NULL, 0, 0, 292 "Memory allocation failed : %s\n", extra); 293 else 294 __xmlRaiseError(NULL, NULL, NULL, 295 NULL, NULL, XML_FROM_XPATH, 296 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, 297 NULL, NULL, NULL, 0, 0, 298 "Memory allocation failed\n"); 299 } 300 } 301 302 /** 303 * xmlXPathPErrMemory: 304 * @ctxt: an XPath parser context 305 * @extra: extra informations 306 * 307 * Handle a redefinition of attribute error 308 */ 309 static void 310 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) 311 { 312 if (ctxt == NULL) 313 xmlXPathErrMemory(NULL, extra); 314 else { 315 ctxt->error = XPATH_MEMORY_ERROR; 316 xmlXPathErrMemory(ctxt->context, extra); 317 } 318 } 319 320 /** 321 * xmlXPathErr: 322 * @ctxt: a XPath parser context 323 * @error: the error code 324 * 325 * Handle an XPath error 326 */ 327 void 328 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) 329 { 330 if ((error < 0) || (error > MAXERRNO)) 331 error = MAXERRNO; 332 if (ctxt == NULL) { 333 __xmlRaiseError(NULL, NULL, NULL, 334 NULL, NULL, XML_FROM_XPATH, 335 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 336 XML_ERR_ERROR, NULL, 0, 337 NULL, NULL, NULL, 0, 0, 338 "%s", xmlXPathErrorMessages[error]); 339 return; 340 } 341 ctxt->error = error; 342 if (ctxt->context == NULL) { 343 __xmlRaiseError(NULL, NULL, NULL, 344 NULL, NULL, XML_FROM_XPATH, 345 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 346 XML_ERR_ERROR, NULL, 0, 347 (const char *) ctxt->base, NULL, NULL, 348 ctxt->cur - ctxt->base, 0, 349 "%s", xmlXPathErrorMessages[error]); 350 return; 351 } 352 353 /* cleanup current last error */ 354 xmlResetError(&ctxt->context->lastError); 355 356 ctxt->context->lastError.domain = XML_FROM_XPATH; 357 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - 358 XPATH_EXPRESSION_OK; 359 ctxt->context->lastError.level = XML_ERR_ERROR; 360 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); 361 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; 362 ctxt->context->lastError.node = ctxt->context->debugNode; 363 if (ctxt->context->error != NULL) { 364 ctxt->context->error(ctxt->context->userData, 365 &ctxt->context->lastError); 366 } else { 367 __xmlRaiseError(NULL, NULL, NULL, 368 NULL, ctxt->context->debugNode, XML_FROM_XPATH, 369 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, 370 XML_ERR_ERROR, NULL, 0, 371 (const char *) ctxt->base, NULL, NULL, 372 ctxt->cur - ctxt->base, 0, 373 "%s", xmlXPathErrorMessages[error]); 374 } 375 376 } 377 378 /** 379 * xmlXPatherror: 380 * @ctxt: the XPath Parser context 381 * @file: the file name 382 * @line: the line number 383 * @no: the error number 384 * 385 * Formats an error message. 386 */ 387 void 388 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, 389 int line ATTRIBUTE_UNUSED, int no) { 390 xmlXPathErr(ctxt, no); 391 } 392 393 /************************************************************************ 394 * * 395 * Utilities * 396 * * 397 ************************************************************************/ 398 399 /** 400 * xsltPointerList: 401 * 402 * Pointer-list for various purposes. 403 */ 404 typedef struct _xmlPointerList xmlPointerList; 405 typedef xmlPointerList *xmlPointerListPtr; 406 struct _xmlPointerList { 407 void **items; 408 int number; 409 int size; 410 }; 411 /* 412 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt 413 * and here, we should make the functions public. 414 */ 415 static int 416 xmlPointerListAddSize(xmlPointerListPtr list, 417 void *item, 418 int initialSize) 419 { 420 if (list->items == NULL) { 421 if (initialSize <= 0) 422 initialSize = 1; 423 list->items = (void **) xmlMalloc( 424 initialSize * sizeof(void *)); 425 if (list->items == NULL) { 426 xmlXPathErrMemory(NULL, 427 "xmlPointerListCreate: allocating item\n"); 428 return(-1); 429 } 430 list->number = 0; 431 list->size = initialSize; 432 } else if (list->size <= list->number) { 433 list->size *= 2; 434 list->items = (void **) xmlRealloc(list->items, 435 list->size * sizeof(void *)); 436 if (list->items == NULL) { 437 xmlXPathErrMemory(NULL, 438 "xmlPointerListCreate: re-allocating item\n"); 439 list->size = 0; 440 return(-1); 441 } 442 } 443 list->items[list->number++] = item; 444 return(0); 445 } 446 447 /** 448 * xsltPointerListCreate: 449 * 450 * Creates an xsltPointerList structure. 451 * 452 * Returns a xsltPointerList structure or NULL in case of an error. 453 */ 454 static xmlPointerListPtr 455 xmlPointerListCreate(int initialSize) 456 { 457 xmlPointerListPtr ret; 458 459 ret = xmlMalloc(sizeof(xmlPointerList)); 460 if (ret == NULL) { 461 xmlXPathErrMemory(NULL, 462 "xmlPointerListCreate: allocating item\n"); 463 return (NULL); 464 } 465 memset(ret, 0, sizeof(xmlPointerList)); 466 if (initialSize > 0) { 467 xmlPointerListAddSize(ret, NULL, initialSize); 468 ret->number = 0; 469 } 470 return (ret); 471 } 472 473 /** 474 * xsltPointerListFree: 475 * 476 * Frees the xsltPointerList structure. This does not free 477 * the content of the list. 478 */ 479 static void 480 xmlPointerListFree(xmlPointerListPtr list) 481 { 482 if (list == NULL) 483 return; 484 if (list->items != NULL) 485 xmlFree(list->items); 486 xmlFree(list); 487 } 488 489 /************************************************************************ 490 * * 491 * Parser Types * 492 * * 493 ************************************************************************/ 494 495 /* 496 * Types are private: 497 */ 498 499 typedef enum { 500 XPATH_OP_END=0, 501 XPATH_OP_AND, 502 XPATH_OP_OR, 503 XPATH_OP_EQUAL, 504 XPATH_OP_CMP, 505 XPATH_OP_PLUS, 506 XPATH_OP_MULT, 507 XPATH_OP_UNION, 508 XPATH_OP_ROOT, 509 XPATH_OP_NODE, 510 XPATH_OP_RESET, /* 10 */ 511 XPATH_OP_COLLECT, 512 XPATH_OP_VALUE, /* 12 */ 513 XPATH_OP_VARIABLE, 514 XPATH_OP_FUNCTION, 515 XPATH_OP_ARG, 516 XPATH_OP_PREDICATE, 517 XPATH_OP_FILTER, /* 17 */ 518 XPATH_OP_SORT /* 18 */ 519 #ifdef LIBXML_XPTR_ENABLED 520 ,XPATH_OP_RANGETO 521 #endif 522 } xmlXPathOp; 523 524 typedef enum { 525 AXIS_ANCESTOR = 1, 526 AXIS_ANCESTOR_OR_SELF, 527 AXIS_ATTRIBUTE, 528 AXIS_CHILD, 529 AXIS_DESCENDANT, 530 AXIS_DESCENDANT_OR_SELF, 531 AXIS_FOLLOWING, 532 AXIS_FOLLOWING_SIBLING, 533 AXIS_NAMESPACE, 534 AXIS_PARENT, 535 AXIS_PRECEDING, 536 AXIS_PRECEDING_SIBLING, 537 AXIS_SELF 538 } xmlXPathAxisVal; 539 540 typedef enum { 541 NODE_TEST_NONE = 0, 542 NODE_TEST_TYPE = 1, 543 NODE_TEST_PI = 2, 544 NODE_TEST_ALL = 3, 545 NODE_TEST_NS = 4, 546 NODE_TEST_NAME = 5 547 } xmlXPathTestVal; 548 549 typedef enum { 550 NODE_TYPE_NODE = 0, 551 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 552 NODE_TYPE_TEXT = XML_TEXT_NODE, 553 NODE_TYPE_PI = XML_PI_NODE 554 } xmlXPathTypeVal; 555 556 #define XP_REWRITE_DOS_CHILD_ELEM 1 557 558 typedef struct _xmlXPathStepOp xmlXPathStepOp; 559 typedef xmlXPathStepOp *xmlXPathStepOpPtr; 560 struct _xmlXPathStepOp { 561 xmlXPathOp op; /* The identifier of the operation */ 562 int ch1; /* First child */ 563 int ch2; /* Second child */ 564 int value; 565 int value2; 566 int value3; 567 void *value4; 568 void *value5; 569 void *cache; 570 void *cacheURI; 571 int rewriteType; 572 }; 573 574 struct _xmlXPathCompExpr { 575 int nbStep; /* Number of steps in this expression */ 576 int maxStep; /* Maximum number of steps allocated */ 577 xmlXPathStepOp *steps; /* ops for computation of this expression */ 578 int last; /* index of last step in expression */ 579 xmlChar *expr; /* the expression being computed */ 580 xmlDictPtr dict; /* the dictionnary to use if any */ 581 #ifdef DEBUG_EVAL_COUNTS 582 int nb; 583 xmlChar *string; 584 #endif 585 #ifdef XPATH_STREAMING 586 xmlPatternPtr stream; 587 #endif 588 }; 589 590 /************************************************************************ 591 * * 592 * Forward declarations * 593 * * 594 ************************************************************************/ 595 static void 596 xmlXPathFreeValueTree(xmlNodeSetPtr obj); 597 static void 598 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); 599 static int 600 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 601 xmlXPathStepOpPtr op, xmlNodePtr *first); 602 static int 603 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, 604 xmlXPathStepOpPtr op, 605 int isPredicate); 606 607 /************************************************************************ 608 * * 609 * Parser Type functions * 610 * * 611 ************************************************************************/ 612 613 /** 614 * xmlXPathNewCompExpr: 615 * 616 * Create a new Xpath component 617 * 618 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 619 */ 620 static xmlXPathCompExprPtr 621 xmlXPathNewCompExpr(void) { 622 xmlXPathCompExprPtr cur; 623 624 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 625 if (cur == NULL) { 626 xmlXPathErrMemory(NULL, "allocating component\n"); 627 return(NULL); 628 } 629 memset(cur, 0, sizeof(xmlXPathCompExpr)); 630 cur->maxStep = 10; 631 cur->nbStep = 0; 632 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 633 sizeof(xmlXPathStepOp)); 634 if (cur->steps == NULL) { 635 xmlXPathErrMemory(NULL, "allocating steps\n"); 636 xmlFree(cur); 637 return(NULL); 638 } 639 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 640 cur->last = -1; 641 #ifdef DEBUG_EVAL_COUNTS 642 cur->nb = 0; 643 #endif 644 return(cur); 645 } 646 647 /** 648 * xmlXPathFreeCompExpr: 649 * @comp: an XPATH comp 650 * 651 * Free up the memory allocated by @comp 652 */ 653 void 654 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 655 { 656 xmlXPathStepOpPtr op; 657 int i; 658 659 if (comp == NULL) 660 return; 661 if (comp->dict == NULL) { 662 for (i = 0; i < comp->nbStep; i++) { 663 op = &comp->steps[i]; 664 if (op->value4 != NULL) { 665 if (op->op == XPATH_OP_VALUE) 666 xmlXPathFreeObject(op->value4); 667 else 668 xmlFree(op->value4); 669 } 670 if (op->value5 != NULL) 671 xmlFree(op->value5); 672 } 673 } else { 674 for (i = 0; i < comp->nbStep; i++) { 675 op = &comp->steps[i]; 676 if (op->value4 != NULL) { 677 if (op->op == XPATH_OP_VALUE) 678 xmlXPathFreeObject(op->value4); 679 } 680 } 681 xmlDictFree(comp->dict); 682 } 683 if (comp->steps != NULL) { 684 xmlFree(comp->steps); 685 } 686 #ifdef DEBUG_EVAL_COUNTS 687 if (comp->string != NULL) { 688 xmlFree(comp->string); 689 } 690 #endif 691 #ifdef XPATH_STREAMING 692 if (comp->stream != NULL) { 693 xmlFreePatternList(comp->stream); 694 } 695 #endif 696 if (comp->expr != NULL) { 697 xmlFree(comp->expr); 698 } 699 700 xmlFree(comp); 701 } 702 703 /** 704 * xmlXPathCompExprAdd: 705 * @comp: the compiled expression 706 * @ch1: first child index 707 * @ch2: second child index 708 * @op: an op 709 * @value: the first int value 710 * @value2: the second int value 711 * @value3: the third int value 712 * @value4: the first string value 713 * @value5: the second string value 714 * 715 * Add a step to an XPath Compiled Expression 716 * 717 * Returns -1 in case of failure, the index otherwise 718 */ 719 static int 720 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 721 xmlXPathOp op, int value, 722 int value2, int value3, void *value4, void *value5) { 723 if (comp->nbStep >= comp->maxStep) { 724 xmlXPathStepOp *real; 725 726 comp->maxStep *= 2; 727 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 728 comp->maxStep * sizeof(xmlXPathStepOp)); 729 if (real == NULL) { 730 comp->maxStep /= 2; 731 xmlXPathErrMemory(NULL, "adding step\n"); 732 return(-1); 733 } 734 comp->steps = real; 735 } 736 comp->last = comp->nbStep; 737 comp->steps[comp->nbStep].rewriteType = 0; 738 comp->steps[comp->nbStep].ch1 = ch1; 739 comp->steps[comp->nbStep].ch2 = ch2; 740 comp->steps[comp->nbStep].op = op; 741 comp->steps[comp->nbStep].value = value; 742 comp->steps[comp->nbStep].value2 = value2; 743 comp->steps[comp->nbStep].value3 = value3; 744 if ((comp->dict != NULL) && 745 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || 746 (op == XPATH_OP_COLLECT))) { 747 if (value4 != NULL) { 748 comp->steps[comp->nbStep].value4 = (xmlChar *) 749 (void *)xmlDictLookup(comp->dict, value4, -1); 750 xmlFree(value4); 751 } else 752 comp->steps[comp->nbStep].value4 = NULL; 753 if (value5 != NULL) { 754 comp->steps[comp->nbStep].value5 = (xmlChar *) 755 (void *)xmlDictLookup(comp->dict, value5, -1); 756 xmlFree(value5); 757 } else 758 comp->steps[comp->nbStep].value5 = NULL; 759 } else { 760 comp->steps[comp->nbStep].value4 = value4; 761 comp->steps[comp->nbStep].value5 = value5; 762 } 763 comp->steps[comp->nbStep].cache = NULL; 764 return(comp->nbStep++); 765 } 766 767 /** 768 * xmlXPathCompSwap: 769 * @comp: the compiled expression 770 * @op: operation index 771 * 772 * Swaps 2 operations in the compiled expression 773 */ 774 static void 775 xmlXPathCompSwap(xmlXPathStepOpPtr op) { 776 int tmp; 777 778 #ifndef LIBXML_THREAD_ENABLED 779 /* 780 * Since this manipulates possibly shared variables, this is 781 * disabled if one detects that the library is used in a multithreaded 782 * application 783 */ 784 if (xmlXPathDisableOptimizer) 785 return; 786 #endif 787 788 tmp = op->ch1; 789 op->ch1 = op->ch2; 790 op->ch2 = tmp; 791 } 792 793 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 794 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 795 (op), (val), (val2), (val3), (val4), (val5)) 796 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 797 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 798 (op), (val), (val2), (val3), (val4), (val5)) 799 800 #define PUSH_LEAVE_EXPR(op, val, val2) \ 801 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 802 803 #define PUSH_UNARY_EXPR(op, ch, val, val2) \ 804 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 805 806 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 807 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ 808 (val), (val2), 0 ,NULL ,NULL) 809 810 /************************************************************************ 811 * * 812 * XPath object cache structures * 813 * * 814 ************************************************************************/ 815 816 /* #define XP_DEFAULT_CACHE_ON */ 817 818 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) 819 820 typedef struct _xmlXPathContextCache xmlXPathContextCache; 821 typedef xmlXPathContextCache *xmlXPathContextCachePtr; 822 struct _xmlXPathContextCache { 823 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ 824 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ 825 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ 826 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ 827 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ 828 int maxNodeset; 829 int maxString; 830 int maxBoolean; 831 int maxNumber; 832 int maxMisc; 833 #ifdef XP_DEBUG_OBJ_USAGE 834 int dbgCachedAll; 835 int dbgCachedNodeset; 836 int dbgCachedString; 837 int dbgCachedBool; 838 int dbgCachedNumber; 839 int dbgCachedPoint; 840 int dbgCachedRange; 841 int dbgCachedLocset; 842 int dbgCachedUsers; 843 int dbgCachedXSLTTree; 844 int dbgCachedUndefined; 845 846 847 int dbgReusedAll; 848 int dbgReusedNodeset; 849 int dbgReusedString; 850 int dbgReusedBool; 851 int dbgReusedNumber; 852 int dbgReusedPoint; 853 int dbgReusedRange; 854 int dbgReusedLocset; 855 int dbgReusedUsers; 856 int dbgReusedXSLTTree; 857 int dbgReusedUndefined; 858 859 #endif 860 }; 861 862 /************************************************************************ 863 * * 864 * Debugging related functions * 865 * * 866 ************************************************************************/ 867 868 #define STRANGE \ 869 xmlGenericError(xmlGenericErrorContext, \ 870 "Internal error at %s:%d\n", \ 871 __FILE__, __LINE__); 872 873 #ifdef LIBXML_DEBUG_ENABLED 874 static void 875 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 876 int i; 877 char shift[100]; 878 879 for (i = 0;((i < depth) && (i < 25));i++) 880 shift[2 * i] = shift[2 * i + 1] = ' '; 881 shift[2 * i] = shift[2 * i + 1] = 0; 882 if (cur == NULL) { 883 fprintf(output, "%s", shift); 884 fprintf(output, "Node is NULL !\n"); 885 return; 886 887 } 888 889 if ((cur->type == XML_DOCUMENT_NODE) || 890 (cur->type == XML_HTML_DOCUMENT_NODE)) { 891 fprintf(output, "%s", shift); 892 fprintf(output, " /\n"); 893 } else if (cur->type == XML_ATTRIBUTE_NODE) 894 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 895 else 896 xmlDebugDumpOneNode(output, cur, depth); 897 } 898 static void 899 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 900 xmlNodePtr tmp; 901 int i; 902 char shift[100]; 903 904 for (i = 0;((i < depth) && (i < 25));i++) 905 shift[2 * i] = shift[2 * i + 1] = ' '; 906 shift[2 * i] = shift[2 * i + 1] = 0; 907 if (cur == NULL) { 908 fprintf(output, "%s", shift); 909 fprintf(output, "Node is NULL !\n"); 910 return; 911 912 } 913 914 while (cur != NULL) { 915 tmp = cur; 916 cur = cur->next; 917 xmlDebugDumpOneNode(output, tmp, depth); 918 } 919 } 920 921 static void 922 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 923 int i; 924 char shift[100]; 925 926 for (i = 0;((i < depth) && (i < 25));i++) 927 shift[2 * i] = shift[2 * i + 1] = ' '; 928 shift[2 * i] = shift[2 * i + 1] = 0; 929 930 if (cur == NULL) { 931 fprintf(output, "%s", shift); 932 fprintf(output, "NodeSet is NULL !\n"); 933 return; 934 935 } 936 937 if (cur != NULL) { 938 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 939 for (i = 0;i < cur->nodeNr;i++) { 940 fprintf(output, "%s", shift); 941 fprintf(output, "%d", i + 1); 942 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 943 } 944 } 945 } 946 947 static void 948 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 949 int i; 950 char shift[100]; 951 952 for (i = 0;((i < depth) && (i < 25));i++) 953 shift[2 * i] = shift[2 * i + 1] = ' '; 954 shift[2 * i] = shift[2 * i + 1] = 0; 955 956 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 957 fprintf(output, "%s", shift); 958 fprintf(output, "Value Tree is NULL !\n"); 959 return; 960 961 } 962 963 fprintf(output, "%s", shift); 964 fprintf(output, "%d", i + 1); 965 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 966 } 967 #if defined(LIBXML_XPTR_ENABLED) 968 static void 969 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 970 int i; 971 char shift[100]; 972 973 for (i = 0;((i < depth) && (i < 25));i++) 974 shift[2 * i] = shift[2 * i + 1] = ' '; 975 shift[2 * i] = shift[2 * i + 1] = 0; 976 977 if (cur == NULL) { 978 fprintf(output, "%s", shift); 979 fprintf(output, "LocationSet is NULL !\n"); 980 return; 981 982 } 983 984 for (i = 0;i < cur->locNr;i++) { 985 fprintf(output, "%s", shift); 986 fprintf(output, "%d : ", i + 1); 987 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 988 } 989 } 990 #endif /* LIBXML_XPTR_ENABLED */ 991 992 /** 993 * xmlXPathDebugDumpObject: 994 * @output: the FILE * to dump the output 995 * @cur: the object to inspect 996 * @depth: indentation level 997 * 998 * Dump the content of the object for debugging purposes 999 */ 1000 void 1001 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 1002 int i; 1003 char shift[100]; 1004 1005 if (output == NULL) return; 1006 1007 for (i = 0;((i < depth) && (i < 25));i++) 1008 shift[2 * i] = shift[2 * i + 1] = ' '; 1009 shift[2 * i] = shift[2 * i + 1] = 0; 1010 1011 1012 fprintf(output, "%s", shift); 1013 1014 if (cur == NULL) { 1015 fprintf(output, "Object is empty (NULL)\n"); 1016 return; 1017 } 1018 switch(cur->type) { 1019 case XPATH_UNDEFINED: 1020 fprintf(output, "Object is uninitialized\n"); 1021 break; 1022 case XPATH_NODESET: 1023 fprintf(output, "Object is a Node Set :\n"); 1024 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 1025 break; 1026 case XPATH_XSLT_TREE: 1027 fprintf(output, "Object is an XSLT value tree :\n"); 1028 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 1029 break; 1030 case XPATH_BOOLEAN: 1031 fprintf(output, "Object is a Boolean : "); 1032 if (cur->boolval) fprintf(output, "true\n"); 1033 else fprintf(output, "false\n"); 1034 break; 1035 case XPATH_NUMBER: 1036 switch (xmlXPathIsInf(cur->floatval)) { 1037 case 1: 1038 fprintf(output, "Object is a number : Infinity\n"); 1039 break; 1040 case -1: 1041 fprintf(output, "Object is a number : -Infinity\n"); 1042 break; 1043 default: 1044 if (xmlXPathIsNaN(cur->floatval)) { 1045 fprintf(output, "Object is a number : NaN\n"); 1046 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 1047 fprintf(output, "Object is a number : 0\n"); 1048 } else { 1049 fprintf(output, "Object is a number : %0g\n", cur->floatval); 1050 } 1051 } 1052 break; 1053 case XPATH_STRING: 1054 fprintf(output, "Object is a string : "); 1055 xmlDebugDumpString(output, cur->stringval); 1056 fprintf(output, "\n"); 1057 break; 1058 case XPATH_POINT: 1059 fprintf(output, "Object is a point : index %d in node", cur->index); 1060 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 1061 fprintf(output, "\n"); 1062 break; 1063 case XPATH_RANGE: 1064 if ((cur->user2 == NULL) || 1065 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 1066 fprintf(output, "Object is a collapsed range :\n"); 1067 fprintf(output, "%s", shift); 1068 if (cur->index >= 0) 1069 fprintf(output, "index %d in ", cur->index); 1070 fprintf(output, "node\n"); 1071 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1072 depth + 1); 1073 } else { 1074 fprintf(output, "Object is a range :\n"); 1075 fprintf(output, "%s", shift); 1076 fprintf(output, "From "); 1077 if (cur->index >= 0) 1078 fprintf(output, "index %d in ", cur->index); 1079 fprintf(output, "node\n"); 1080 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 1081 depth + 1); 1082 fprintf(output, "%s", shift); 1083 fprintf(output, "To "); 1084 if (cur->index2 >= 0) 1085 fprintf(output, "index %d in ", cur->index2); 1086 fprintf(output, "node\n"); 1087 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 1088 depth + 1); 1089 fprintf(output, "\n"); 1090 } 1091 break; 1092 case XPATH_LOCATIONSET: 1093 #if defined(LIBXML_XPTR_ENABLED) 1094 fprintf(output, "Object is a Location Set:\n"); 1095 xmlXPathDebugDumpLocationSet(output, 1096 (xmlLocationSetPtr) cur->user, depth); 1097 #endif 1098 break; 1099 case XPATH_USERS: 1100 fprintf(output, "Object is user defined\n"); 1101 break; 1102 } 1103 } 1104 1105 static void 1106 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 1107 xmlXPathStepOpPtr op, int depth) { 1108 int i; 1109 char shift[100]; 1110 1111 for (i = 0;((i < depth) && (i < 25));i++) 1112 shift[2 * i] = shift[2 * i + 1] = ' '; 1113 shift[2 * i] = shift[2 * i + 1] = 0; 1114 1115 fprintf(output, "%s", shift); 1116 if (op == NULL) { 1117 fprintf(output, "Step is NULL\n"); 1118 return; 1119 } 1120 switch (op->op) { 1121 case XPATH_OP_END: 1122 fprintf(output, "END"); break; 1123 case XPATH_OP_AND: 1124 fprintf(output, "AND"); break; 1125 case XPATH_OP_OR: 1126 fprintf(output, "OR"); break; 1127 case XPATH_OP_EQUAL: 1128 if (op->value) 1129 fprintf(output, "EQUAL ="); 1130 else 1131 fprintf(output, "EQUAL !="); 1132 break; 1133 case XPATH_OP_CMP: 1134 if (op->value) 1135 fprintf(output, "CMP <"); 1136 else 1137 fprintf(output, "CMP >"); 1138 if (!op->value2) 1139 fprintf(output, "="); 1140 break; 1141 case XPATH_OP_PLUS: 1142 if (op->value == 0) 1143 fprintf(output, "PLUS -"); 1144 else if (op->value == 1) 1145 fprintf(output, "PLUS +"); 1146 else if (op->value == 2) 1147 fprintf(output, "PLUS unary -"); 1148 else if (op->value == 3) 1149 fprintf(output, "PLUS unary - -"); 1150 break; 1151 case XPATH_OP_MULT: 1152 if (op->value == 0) 1153 fprintf(output, "MULT *"); 1154 else if (op->value == 1) 1155 fprintf(output, "MULT div"); 1156 else 1157 fprintf(output, "MULT mod"); 1158 break; 1159 case XPATH_OP_UNION: 1160 fprintf(output, "UNION"); break; 1161 case XPATH_OP_ROOT: 1162 fprintf(output, "ROOT"); break; 1163 case XPATH_OP_NODE: 1164 fprintf(output, "NODE"); break; 1165 case XPATH_OP_RESET: 1166 fprintf(output, "RESET"); break; 1167 case XPATH_OP_SORT: 1168 fprintf(output, "SORT"); break; 1169 case XPATH_OP_COLLECT: { 1170 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; 1171 xmlXPathTestVal test = (xmlXPathTestVal)op->value2; 1172 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; 1173 const xmlChar *prefix = op->value4; 1174 const xmlChar *name = op->value5; 1175 1176 fprintf(output, "COLLECT "); 1177 switch (axis) { 1178 case AXIS_ANCESTOR: 1179 fprintf(output, " 'ancestors' "); break; 1180 case AXIS_ANCESTOR_OR_SELF: 1181 fprintf(output, " 'ancestors-or-self' "); break; 1182 case AXIS_ATTRIBUTE: 1183 fprintf(output, " 'attributes' "); break; 1184 case AXIS_CHILD: 1185 fprintf(output, " 'child' "); break; 1186 case AXIS_DESCENDANT: 1187 fprintf(output, " 'descendant' "); break; 1188 case AXIS_DESCENDANT_OR_SELF: 1189 fprintf(output, " 'descendant-or-self' "); break; 1190 case AXIS_FOLLOWING: 1191 fprintf(output, " 'following' "); break; 1192 case AXIS_FOLLOWING_SIBLING: 1193 fprintf(output, " 'following-siblings' "); break; 1194 case AXIS_NAMESPACE: 1195 fprintf(output, " 'namespace' "); break; 1196 case AXIS_PARENT: 1197 fprintf(output, " 'parent' "); break; 1198 case AXIS_PRECEDING: 1199 fprintf(output, " 'preceding' "); break; 1200 case AXIS_PRECEDING_SIBLING: 1201 fprintf(output, " 'preceding-sibling' "); break; 1202 case AXIS_SELF: 1203 fprintf(output, " 'self' "); break; 1204 } 1205 switch (test) { 1206 case NODE_TEST_NONE: 1207 fprintf(output, "'none' "); break; 1208 case NODE_TEST_TYPE: 1209 fprintf(output, "'type' "); break; 1210 case NODE_TEST_PI: 1211 fprintf(output, "'PI' "); break; 1212 case NODE_TEST_ALL: 1213 fprintf(output, "'all' "); break; 1214 case NODE_TEST_NS: 1215 fprintf(output, "'namespace' "); break; 1216 case NODE_TEST_NAME: 1217 fprintf(output, "'name' "); break; 1218 } 1219 switch (type) { 1220 case NODE_TYPE_NODE: 1221 fprintf(output, "'node' "); break; 1222 case NODE_TYPE_COMMENT: 1223 fprintf(output, "'comment' "); break; 1224 case NODE_TYPE_TEXT: 1225 fprintf(output, "'text' "); break; 1226 case NODE_TYPE_PI: 1227 fprintf(output, "'PI' "); break; 1228 } 1229 if (prefix != NULL) 1230 fprintf(output, "%s:", prefix); 1231 if (name != NULL) 1232 fprintf(output, "%s", (const char *) name); 1233 break; 1234 1235 } 1236 case XPATH_OP_VALUE: { 1237 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 1238 1239 fprintf(output, "ELEM "); 1240 xmlXPathDebugDumpObject(output, object, 0); 1241 goto finish; 1242 } 1243 case XPATH_OP_VARIABLE: { 1244 const xmlChar *prefix = op->value5; 1245 const xmlChar *name = op->value4; 1246 1247 if (prefix != NULL) 1248 fprintf(output, "VARIABLE %s:%s", prefix, name); 1249 else 1250 fprintf(output, "VARIABLE %s", name); 1251 break; 1252 } 1253 case XPATH_OP_FUNCTION: { 1254 int nbargs = op->value; 1255 const xmlChar *prefix = op->value5; 1256 const xmlChar *name = op->value4; 1257 1258 if (prefix != NULL) 1259 fprintf(output, "FUNCTION %s:%s(%d args)", 1260 prefix, name, nbargs); 1261 else 1262 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 1263 break; 1264 } 1265 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 1266 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 1267 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 1268 #ifdef LIBXML_XPTR_ENABLED 1269 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 1270 #endif 1271 default: 1272 fprintf(output, "UNKNOWN %d\n", op->op); return; 1273 } 1274 fprintf(output, "\n"); 1275 finish: 1276 if (op->ch1 >= 0) 1277 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 1278 if (op->ch2 >= 0) 1279 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 1280 } 1281 1282 /** 1283 * xmlXPathDebugDumpCompExpr: 1284 * @output: the FILE * for the output 1285 * @comp: the precompiled XPath expression 1286 * @depth: the indentation level. 1287 * 1288 * Dumps the tree of the compiled XPath expression. 1289 */ 1290 void 1291 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 1292 int depth) { 1293 int i; 1294 char shift[100]; 1295 1296 if ((output == NULL) || (comp == NULL)) return; 1297 1298 for (i = 0;((i < depth) && (i < 25));i++) 1299 shift[2 * i] = shift[2 * i + 1] = ' '; 1300 shift[2 * i] = shift[2 * i + 1] = 0; 1301 1302 fprintf(output, "%s", shift); 1303 1304 fprintf(output, "Compiled Expression : %d elements\n", 1305 comp->nbStep); 1306 i = comp->last; 1307 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 1308 } 1309 1310 #ifdef XP_DEBUG_OBJ_USAGE 1311 1312 /* 1313 * XPath object usage related debugging variables. 1314 */ 1315 static int xmlXPathDebugObjCounterUndefined = 0; 1316 static int xmlXPathDebugObjCounterNodeset = 0; 1317 static int xmlXPathDebugObjCounterBool = 0; 1318 static int xmlXPathDebugObjCounterNumber = 0; 1319 static int xmlXPathDebugObjCounterString = 0; 1320 static int xmlXPathDebugObjCounterPoint = 0; 1321 static int xmlXPathDebugObjCounterRange = 0; 1322 static int xmlXPathDebugObjCounterLocset = 0; 1323 static int xmlXPathDebugObjCounterUsers = 0; 1324 static int xmlXPathDebugObjCounterXSLTTree = 0; 1325 static int xmlXPathDebugObjCounterAll = 0; 1326 1327 static int xmlXPathDebugObjTotalUndefined = 0; 1328 static int xmlXPathDebugObjTotalNodeset = 0; 1329 static int xmlXPathDebugObjTotalBool = 0; 1330 static int xmlXPathDebugObjTotalNumber = 0; 1331 static int xmlXPathDebugObjTotalString = 0; 1332 static int xmlXPathDebugObjTotalPoint = 0; 1333 static int xmlXPathDebugObjTotalRange = 0; 1334 static int xmlXPathDebugObjTotalLocset = 0; 1335 static int xmlXPathDebugObjTotalUsers = 0; 1336 static int xmlXPathDebugObjTotalXSLTTree = 0; 1337 static int xmlXPathDebugObjTotalAll = 0; 1338 1339 static int xmlXPathDebugObjMaxUndefined = 0; 1340 static int xmlXPathDebugObjMaxNodeset = 0; 1341 static int xmlXPathDebugObjMaxBool = 0; 1342 static int xmlXPathDebugObjMaxNumber = 0; 1343 static int xmlXPathDebugObjMaxString = 0; 1344 static int xmlXPathDebugObjMaxPoint = 0; 1345 static int xmlXPathDebugObjMaxRange = 0; 1346 static int xmlXPathDebugObjMaxLocset = 0; 1347 static int xmlXPathDebugObjMaxUsers = 0; 1348 static int xmlXPathDebugObjMaxXSLTTree = 0; 1349 static int xmlXPathDebugObjMaxAll = 0; 1350 1351 /* REVISIT TODO: Make this static when committing */ 1352 static void 1353 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) 1354 { 1355 if (ctxt != NULL) { 1356 if (ctxt->cache != NULL) { 1357 xmlXPathContextCachePtr cache = 1358 (xmlXPathContextCachePtr) ctxt->cache; 1359 1360 cache->dbgCachedAll = 0; 1361 cache->dbgCachedNodeset = 0; 1362 cache->dbgCachedString = 0; 1363 cache->dbgCachedBool = 0; 1364 cache->dbgCachedNumber = 0; 1365 cache->dbgCachedPoint = 0; 1366 cache->dbgCachedRange = 0; 1367 cache->dbgCachedLocset = 0; 1368 cache->dbgCachedUsers = 0; 1369 cache->dbgCachedXSLTTree = 0; 1370 cache->dbgCachedUndefined = 0; 1371 1372 cache->dbgReusedAll = 0; 1373 cache->dbgReusedNodeset = 0; 1374 cache->dbgReusedString = 0; 1375 cache->dbgReusedBool = 0; 1376 cache->dbgReusedNumber = 0; 1377 cache->dbgReusedPoint = 0; 1378 cache->dbgReusedRange = 0; 1379 cache->dbgReusedLocset = 0; 1380 cache->dbgReusedUsers = 0; 1381 cache->dbgReusedXSLTTree = 0; 1382 cache->dbgReusedUndefined = 0; 1383 } 1384 } 1385 1386 xmlXPathDebugObjCounterUndefined = 0; 1387 xmlXPathDebugObjCounterNodeset = 0; 1388 xmlXPathDebugObjCounterBool = 0; 1389 xmlXPathDebugObjCounterNumber = 0; 1390 xmlXPathDebugObjCounterString = 0; 1391 xmlXPathDebugObjCounterPoint = 0; 1392 xmlXPathDebugObjCounterRange = 0; 1393 xmlXPathDebugObjCounterLocset = 0; 1394 xmlXPathDebugObjCounterUsers = 0; 1395 xmlXPathDebugObjCounterXSLTTree = 0; 1396 xmlXPathDebugObjCounterAll = 0; 1397 1398 xmlXPathDebugObjTotalUndefined = 0; 1399 xmlXPathDebugObjTotalNodeset = 0; 1400 xmlXPathDebugObjTotalBool = 0; 1401 xmlXPathDebugObjTotalNumber = 0; 1402 xmlXPathDebugObjTotalString = 0; 1403 xmlXPathDebugObjTotalPoint = 0; 1404 xmlXPathDebugObjTotalRange = 0; 1405 xmlXPathDebugObjTotalLocset = 0; 1406 xmlXPathDebugObjTotalUsers = 0; 1407 xmlXPathDebugObjTotalXSLTTree = 0; 1408 xmlXPathDebugObjTotalAll = 0; 1409 1410 xmlXPathDebugObjMaxUndefined = 0; 1411 xmlXPathDebugObjMaxNodeset = 0; 1412 xmlXPathDebugObjMaxBool = 0; 1413 xmlXPathDebugObjMaxNumber = 0; 1414 xmlXPathDebugObjMaxString = 0; 1415 xmlXPathDebugObjMaxPoint = 0; 1416 xmlXPathDebugObjMaxRange = 0; 1417 xmlXPathDebugObjMaxLocset = 0; 1418 xmlXPathDebugObjMaxUsers = 0; 1419 xmlXPathDebugObjMaxXSLTTree = 0; 1420 xmlXPathDebugObjMaxAll = 0; 1421 1422 } 1423 1424 static void 1425 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, 1426 xmlXPathObjectType objType) 1427 { 1428 int isCached = 0; 1429 1430 if (ctxt != NULL) { 1431 if (ctxt->cache != NULL) { 1432 xmlXPathContextCachePtr cache = 1433 (xmlXPathContextCachePtr) ctxt->cache; 1434 1435 isCached = 1; 1436 1437 cache->dbgReusedAll++; 1438 switch (objType) { 1439 case XPATH_UNDEFINED: 1440 cache->dbgReusedUndefined++; 1441 break; 1442 case XPATH_NODESET: 1443 cache->dbgReusedNodeset++; 1444 break; 1445 case XPATH_BOOLEAN: 1446 cache->dbgReusedBool++; 1447 break; 1448 case XPATH_NUMBER: 1449 cache->dbgReusedNumber++; 1450 break; 1451 case XPATH_STRING: 1452 cache->dbgReusedString++; 1453 break; 1454 case XPATH_POINT: 1455 cache->dbgReusedPoint++; 1456 break; 1457 case XPATH_RANGE: 1458 cache->dbgReusedRange++; 1459 break; 1460 case XPATH_LOCATIONSET: 1461 cache->dbgReusedLocset++; 1462 break; 1463 case XPATH_USERS: 1464 cache->dbgReusedUsers++; 1465 break; 1466 case XPATH_XSLT_TREE: 1467 cache->dbgReusedXSLTTree++; 1468 break; 1469 default: 1470 break; 1471 } 1472 } 1473 } 1474 1475 switch (objType) { 1476 case XPATH_UNDEFINED: 1477 if (! isCached) 1478 xmlXPathDebugObjTotalUndefined++; 1479 xmlXPathDebugObjCounterUndefined++; 1480 if (xmlXPathDebugObjCounterUndefined > 1481 xmlXPathDebugObjMaxUndefined) 1482 xmlXPathDebugObjMaxUndefined = 1483 xmlXPathDebugObjCounterUndefined; 1484 break; 1485 case XPATH_NODESET: 1486 if (! isCached) 1487 xmlXPathDebugObjTotalNodeset++; 1488 xmlXPathDebugObjCounterNodeset++; 1489 if (xmlXPathDebugObjCounterNodeset > 1490 xmlXPathDebugObjMaxNodeset) 1491 xmlXPathDebugObjMaxNodeset = 1492 xmlXPathDebugObjCounterNodeset; 1493 break; 1494 case XPATH_BOOLEAN: 1495 if (! isCached) 1496 xmlXPathDebugObjTotalBool++; 1497 xmlXPathDebugObjCounterBool++; 1498 if (xmlXPathDebugObjCounterBool > 1499 xmlXPathDebugObjMaxBool) 1500 xmlXPathDebugObjMaxBool = 1501 xmlXPathDebugObjCounterBool; 1502 break; 1503 case XPATH_NUMBER: 1504 if (! isCached) 1505 xmlXPathDebugObjTotalNumber++; 1506 xmlXPathDebugObjCounterNumber++; 1507 if (xmlXPathDebugObjCounterNumber > 1508 xmlXPathDebugObjMaxNumber) 1509 xmlXPathDebugObjMaxNumber = 1510 xmlXPathDebugObjCounterNumber; 1511 break; 1512 case XPATH_STRING: 1513 if (! isCached) 1514 xmlXPathDebugObjTotalString++; 1515 xmlXPathDebugObjCounterString++; 1516 if (xmlXPathDebugObjCounterString > 1517 xmlXPathDebugObjMaxString) 1518 xmlXPathDebugObjMaxString = 1519 xmlXPathDebugObjCounterString; 1520 break; 1521 case XPATH_POINT: 1522 if (! isCached) 1523 xmlXPathDebugObjTotalPoint++; 1524 xmlXPathDebugObjCounterPoint++; 1525 if (xmlXPathDebugObjCounterPoint > 1526 xmlXPathDebugObjMaxPoint) 1527 xmlXPathDebugObjMaxPoint = 1528 xmlXPathDebugObjCounterPoint; 1529 break; 1530 case XPATH_RANGE: 1531 if (! isCached) 1532 xmlXPathDebugObjTotalRange++; 1533 xmlXPathDebugObjCounterRange++; 1534 if (xmlXPathDebugObjCounterRange > 1535 xmlXPathDebugObjMaxRange) 1536 xmlXPathDebugObjMaxRange = 1537 xmlXPathDebugObjCounterRange; 1538 break; 1539 case XPATH_LOCATIONSET: 1540 if (! isCached) 1541 xmlXPathDebugObjTotalLocset++; 1542 xmlXPathDebugObjCounterLocset++; 1543 if (xmlXPathDebugObjCounterLocset > 1544 xmlXPathDebugObjMaxLocset) 1545 xmlXPathDebugObjMaxLocset = 1546 xmlXPathDebugObjCounterLocset; 1547 break; 1548 case XPATH_USERS: 1549 if (! isCached) 1550 xmlXPathDebugObjTotalUsers++; 1551 xmlXPathDebugObjCounterUsers++; 1552 if (xmlXPathDebugObjCounterUsers > 1553 xmlXPathDebugObjMaxUsers) 1554 xmlXPathDebugObjMaxUsers = 1555 xmlXPathDebugObjCounterUsers; 1556 break; 1557 case XPATH_XSLT_TREE: 1558 if (! isCached) 1559 xmlXPathDebugObjTotalXSLTTree++; 1560 xmlXPathDebugObjCounterXSLTTree++; 1561 if (xmlXPathDebugObjCounterXSLTTree > 1562 xmlXPathDebugObjMaxXSLTTree) 1563 xmlXPathDebugObjMaxXSLTTree = 1564 xmlXPathDebugObjCounterXSLTTree; 1565 break; 1566 default: 1567 break; 1568 } 1569 if (! isCached) 1570 xmlXPathDebugObjTotalAll++; 1571 xmlXPathDebugObjCounterAll++; 1572 if (xmlXPathDebugObjCounterAll > 1573 xmlXPathDebugObjMaxAll) 1574 xmlXPathDebugObjMaxAll = 1575 xmlXPathDebugObjCounterAll; 1576 } 1577 1578 static void 1579 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, 1580 xmlXPathObjectType objType) 1581 { 1582 int isCached = 0; 1583 1584 if (ctxt != NULL) { 1585 if (ctxt->cache != NULL) { 1586 xmlXPathContextCachePtr cache = 1587 (xmlXPathContextCachePtr) ctxt->cache; 1588 1589 isCached = 1; 1590 1591 cache->dbgCachedAll++; 1592 switch (objType) { 1593 case XPATH_UNDEFINED: 1594 cache->dbgCachedUndefined++; 1595 break; 1596 case XPATH_NODESET: 1597 cache->dbgCachedNodeset++; 1598 break; 1599 case XPATH_BOOLEAN: 1600 cache->dbgCachedBool++; 1601 break; 1602 case XPATH_NUMBER: 1603 cache->dbgCachedNumber++; 1604 break; 1605 case XPATH_STRING: 1606 cache->dbgCachedString++; 1607 break; 1608 case XPATH_POINT: 1609 cache->dbgCachedPoint++; 1610 break; 1611 case XPATH_RANGE: 1612 cache->dbgCachedRange++; 1613 break; 1614 case XPATH_LOCATIONSET: 1615 cache->dbgCachedLocset++; 1616 break; 1617 case XPATH_USERS: 1618 cache->dbgCachedUsers++; 1619 break; 1620 case XPATH_XSLT_TREE: 1621 cache->dbgCachedXSLTTree++; 1622 break; 1623 default: 1624 break; 1625 } 1626 1627 } 1628 } 1629 switch (objType) { 1630 case XPATH_UNDEFINED: 1631 xmlXPathDebugObjCounterUndefined--; 1632 break; 1633 case XPATH_NODESET: 1634 xmlXPathDebugObjCounterNodeset--; 1635 break; 1636 case XPATH_BOOLEAN: 1637 xmlXPathDebugObjCounterBool--; 1638 break; 1639 case XPATH_NUMBER: 1640 xmlXPathDebugObjCounterNumber--; 1641 break; 1642 case XPATH_STRING: 1643 xmlXPathDebugObjCounterString--; 1644 break; 1645 case XPATH_POINT: 1646 xmlXPathDebugObjCounterPoint--; 1647 break; 1648 case XPATH_RANGE: 1649 xmlXPathDebugObjCounterRange--; 1650 break; 1651 case XPATH_LOCATIONSET: 1652 xmlXPathDebugObjCounterLocset--; 1653 break; 1654 case XPATH_USERS: 1655 xmlXPathDebugObjCounterUsers--; 1656 break; 1657 case XPATH_XSLT_TREE: 1658 xmlXPathDebugObjCounterXSLTTree--; 1659 break; 1660 default: 1661 break; 1662 } 1663 xmlXPathDebugObjCounterAll--; 1664 } 1665 1666 /* REVISIT TODO: Make this static when committing */ 1667 static void 1668 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) 1669 { 1670 int reqAll, reqNodeset, reqString, reqBool, reqNumber, 1671 reqXSLTTree, reqUndefined; 1672 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, 1673 caNumber = 0, caXSLTTree = 0, caUndefined = 0; 1674 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, 1675 reNumber = 0, reXSLTTree = 0, reUndefined = 0; 1676 int leftObjs = xmlXPathDebugObjCounterAll; 1677 1678 reqAll = xmlXPathDebugObjTotalAll; 1679 reqNodeset = xmlXPathDebugObjTotalNodeset; 1680 reqString = xmlXPathDebugObjTotalString; 1681 reqBool = xmlXPathDebugObjTotalBool; 1682 reqNumber = xmlXPathDebugObjTotalNumber; 1683 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; 1684 reqUndefined = xmlXPathDebugObjTotalUndefined; 1685 1686 printf("# XPath object usage:\n"); 1687 1688 if (ctxt != NULL) { 1689 if (ctxt->cache != NULL) { 1690 xmlXPathContextCachePtr cache = 1691 (xmlXPathContextCachePtr) ctxt->cache; 1692 1693 reAll = cache->dbgReusedAll; 1694 reqAll += reAll; 1695 reNodeset = cache->dbgReusedNodeset; 1696 reqNodeset += reNodeset; 1697 reString = cache->dbgReusedString; 1698 reqString += reString; 1699 reBool = cache->dbgReusedBool; 1700 reqBool += reBool; 1701 reNumber = cache->dbgReusedNumber; 1702 reqNumber += reNumber; 1703 reXSLTTree = cache->dbgReusedXSLTTree; 1704 reqXSLTTree += reXSLTTree; 1705 reUndefined = cache->dbgReusedUndefined; 1706 reqUndefined += reUndefined; 1707 1708 caAll = cache->dbgCachedAll; 1709 caBool = cache->dbgCachedBool; 1710 caNodeset = cache->dbgCachedNodeset; 1711 caString = cache->dbgCachedString; 1712 caNumber = cache->dbgCachedNumber; 1713 caXSLTTree = cache->dbgCachedXSLTTree; 1714 caUndefined = cache->dbgCachedUndefined; 1715 1716 if (cache->nodesetObjs) 1717 leftObjs -= cache->nodesetObjs->number; 1718 if (cache->stringObjs) 1719 leftObjs -= cache->stringObjs->number; 1720 if (cache->booleanObjs) 1721 leftObjs -= cache->booleanObjs->number; 1722 if (cache->numberObjs) 1723 leftObjs -= cache->numberObjs->number; 1724 if (cache->miscObjs) 1725 leftObjs -= cache->miscObjs->number; 1726 } 1727 } 1728 1729 printf("# all\n"); 1730 printf("# total : %d\n", reqAll); 1731 printf("# left : %d\n", leftObjs); 1732 printf("# created: %d\n", xmlXPathDebugObjTotalAll); 1733 printf("# reused : %d\n", reAll); 1734 printf("# max : %d\n", xmlXPathDebugObjMaxAll); 1735 1736 printf("# node-sets\n"); 1737 printf("# total : %d\n", reqNodeset); 1738 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); 1739 printf("# reused : %d\n", reNodeset); 1740 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); 1741 1742 printf("# strings\n"); 1743 printf("# total : %d\n", reqString); 1744 printf("# created: %d\n", xmlXPathDebugObjTotalString); 1745 printf("# reused : %d\n", reString); 1746 printf("# max : %d\n", xmlXPathDebugObjMaxString); 1747 1748 printf("# booleans\n"); 1749 printf("# total : %d\n", reqBool); 1750 printf("# created: %d\n", xmlXPathDebugObjTotalBool); 1751 printf("# reused : %d\n", reBool); 1752 printf("# max : %d\n", xmlXPathDebugObjMaxBool); 1753 1754 printf("# numbers\n"); 1755 printf("# total : %d\n", reqNumber); 1756 printf("# created: %d\n", xmlXPathDebugObjTotalNumber); 1757 printf("# reused : %d\n", reNumber); 1758 printf("# max : %d\n", xmlXPathDebugObjMaxNumber); 1759 1760 printf("# XSLT result tree fragments\n"); 1761 printf("# total : %d\n", reqXSLTTree); 1762 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); 1763 printf("# reused : %d\n", reXSLTTree); 1764 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); 1765 1766 printf("# undefined\n"); 1767 printf("# total : %d\n", reqUndefined); 1768 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); 1769 printf("# reused : %d\n", reUndefined); 1770 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); 1771 1772 } 1773 1774 #endif /* XP_DEBUG_OBJ_USAGE */ 1775 1776 #endif /* LIBXML_DEBUG_ENABLED */ 1777 1778 /************************************************************************ 1779 * * 1780 * XPath object caching * 1781 * * 1782 ************************************************************************/ 1783 1784 /** 1785 * xmlXPathNewCache: 1786 * 1787 * Create a new object cache 1788 * 1789 * Returns the xmlXPathCache just allocated. 1790 */ 1791 static xmlXPathContextCachePtr 1792 xmlXPathNewCache(void) 1793 { 1794 xmlXPathContextCachePtr ret; 1795 1796 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); 1797 if (ret == NULL) { 1798 xmlXPathErrMemory(NULL, "creating object cache\n"); 1799 return(NULL); 1800 } 1801 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); 1802 ret->maxNodeset = 100; 1803 ret->maxString = 100; 1804 ret->maxBoolean = 100; 1805 ret->maxNumber = 100; 1806 ret->maxMisc = 100; 1807 return(ret); 1808 } 1809 1810 static void 1811 xmlXPathCacheFreeObjectList(xmlPointerListPtr list) 1812 { 1813 int i; 1814 xmlXPathObjectPtr obj; 1815 1816 if (list == NULL) 1817 return; 1818 1819 for (i = 0; i < list->number; i++) { 1820 obj = list->items[i]; 1821 /* 1822 * Note that it is already assured that we don't need to 1823 * look out for namespace nodes in the node-set. 1824 */ 1825 if (obj->nodesetval != NULL) { 1826 if (obj->nodesetval->nodeTab != NULL) 1827 xmlFree(obj->nodesetval->nodeTab); 1828 xmlFree(obj->nodesetval); 1829 } 1830 xmlFree(obj); 1831 #ifdef XP_DEBUG_OBJ_USAGE 1832 xmlXPathDebugObjCounterAll--; 1833 #endif 1834 } 1835 xmlPointerListFree(list); 1836 } 1837 1838 static void 1839 xmlXPathFreeCache(xmlXPathContextCachePtr cache) 1840 { 1841 if (cache == NULL) 1842 return; 1843 if (cache->nodesetObjs) 1844 xmlXPathCacheFreeObjectList(cache->nodesetObjs); 1845 if (cache->stringObjs) 1846 xmlXPathCacheFreeObjectList(cache->stringObjs); 1847 if (cache->booleanObjs) 1848 xmlXPathCacheFreeObjectList(cache->booleanObjs); 1849 if (cache->numberObjs) 1850 xmlXPathCacheFreeObjectList(cache->numberObjs); 1851 if (cache->miscObjs) 1852 xmlXPathCacheFreeObjectList(cache->miscObjs); 1853 xmlFree(cache); 1854 } 1855 1856 /** 1857 * xmlXPathContextSetCache: 1858 * 1859 * @ctxt: the XPath context 1860 * @active: enables/disables (creates/frees) the cache 1861 * @value: a value with semantics dependant on @options 1862 * @options: options (currently only the value 0 is used) 1863 * 1864 * Creates/frees an object cache on the XPath context. 1865 * If activates XPath objects (xmlXPathObject) will be cached internally 1866 * to be reused. 1867 * @options: 1868 * 0: This will set the XPath object caching: 1869 * @value: 1870 * This will set the maximum number of XPath objects 1871 * to be cached per slot 1872 * There are 5 slots for: node-set, string, number, boolean, and 1873 * misc objects. Use <0 for the default number (100). 1874 * Other values for @options have currently no effect. 1875 * 1876 * Returns 0 if the setting succeeded, and -1 on API or internal errors. 1877 */ 1878 int 1879 xmlXPathContextSetCache(xmlXPathContextPtr ctxt, 1880 int active, 1881 int value, 1882 int options) 1883 { 1884 if (ctxt == NULL) 1885 return(-1); 1886 if (active) { 1887 xmlXPathContextCachePtr cache; 1888 1889 if (ctxt->cache == NULL) { 1890 ctxt->cache = xmlXPathNewCache(); 1891 if (ctxt->cache == NULL) 1892 return(-1); 1893 } 1894 cache = (xmlXPathContextCachePtr) ctxt->cache; 1895 if (options == 0) { 1896 if (value < 0) 1897 value = 100; 1898 cache->maxNodeset = value; 1899 cache->maxString = value; 1900 cache->maxNumber = value; 1901 cache->maxBoolean = value; 1902 cache->maxMisc = value; 1903 } 1904 } else if (ctxt->cache != NULL) { 1905 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); 1906 ctxt->cache = NULL; 1907 } 1908 return(0); 1909 } 1910 1911 /** 1912 * xmlXPathCacheWrapNodeSet: 1913 * @ctxt: the XPath context 1914 * @val: the NodePtr value 1915 * 1916 * This is the cached version of xmlXPathWrapNodeSet(). 1917 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 1918 * 1919 * Returns the created or reused object. 1920 */ 1921 static xmlXPathObjectPtr 1922 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) 1923 { 1924 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1925 xmlXPathContextCachePtr cache = 1926 (xmlXPathContextCachePtr) ctxt->cache; 1927 1928 if ((cache->miscObjs != NULL) && 1929 (cache->miscObjs->number != 0)) 1930 { 1931 xmlXPathObjectPtr ret; 1932 1933 ret = (xmlXPathObjectPtr) 1934 cache->miscObjs->items[--cache->miscObjs->number]; 1935 ret->type = XPATH_NODESET; 1936 ret->nodesetval = val; 1937 #ifdef XP_DEBUG_OBJ_USAGE 1938 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 1939 #endif 1940 return(ret); 1941 } 1942 } 1943 1944 return(xmlXPathWrapNodeSet(val)); 1945 1946 } 1947 1948 /** 1949 * xmlXPathCacheWrapString: 1950 * @ctxt: the XPath context 1951 * @val: the xmlChar * value 1952 * 1953 * This is the cached version of xmlXPathWrapString(). 1954 * Wraps the @val string into an XPath object. 1955 * 1956 * Returns the created or reused object. 1957 */ 1958 static xmlXPathObjectPtr 1959 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) 1960 { 1961 if ((ctxt != NULL) && (ctxt->cache != NULL)) { 1962 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 1963 1964 if ((cache->stringObjs != NULL) && 1965 (cache->stringObjs->number != 0)) 1966 { 1967 1968 xmlXPathObjectPtr ret; 1969 1970 ret = (xmlXPathObjectPtr) 1971 cache->stringObjs->items[--cache->stringObjs->number]; 1972 ret->type = XPATH_STRING; 1973 ret->stringval = val; 1974 #ifdef XP_DEBUG_OBJ_USAGE 1975 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1976 #endif 1977 return(ret); 1978 } else if ((cache->miscObjs != NULL) && 1979 (cache->miscObjs->number != 0)) 1980 { 1981 xmlXPathObjectPtr ret; 1982 /* 1983 * Fallback to misc-cache. 1984 */ 1985 ret = (xmlXPathObjectPtr) 1986 cache->miscObjs->items[--cache->miscObjs->number]; 1987 1988 ret->type = XPATH_STRING; 1989 ret->stringval = val; 1990 #ifdef XP_DEBUG_OBJ_USAGE 1991 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 1992 #endif 1993 return(ret); 1994 } 1995 } 1996 return(xmlXPathWrapString(val)); 1997 } 1998 1999 /** 2000 * xmlXPathCacheNewNodeSet: 2001 * @ctxt: the XPath context 2002 * @val: the NodePtr value 2003 * 2004 * This is the cached version of xmlXPathNewNodeSet(). 2005 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize 2006 * it with the single Node @val 2007 * 2008 * Returns the created or reused object. 2009 */ 2010 static xmlXPathObjectPtr 2011 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) 2012 { 2013 if ((ctxt != NULL) && (ctxt->cache)) { 2014 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2015 2016 if ((cache->nodesetObjs != NULL) && 2017 (cache->nodesetObjs->number != 0)) 2018 { 2019 xmlXPathObjectPtr ret; 2020 /* 2021 * Use the nodset-cache. 2022 */ 2023 ret = (xmlXPathObjectPtr) 2024 cache->nodesetObjs->items[--cache->nodesetObjs->number]; 2025 ret->type = XPATH_NODESET; 2026 ret->boolval = 0; 2027 if (val) { 2028 if ((ret->nodesetval->nodeMax == 0) || 2029 (val->type == XML_NAMESPACE_DECL)) 2030 { 2031 xmlXPathNodeSetAddUnique(ret->nodesetval, val); 2032 } else { 2033 ret->nodesetval->nodeTab[0] = val; 2034 ret->nodesetval->nodeNr = 1; 2035 } 2036 } 2037 #ifdef XP_DEBUG_OBJ_USAGE 2038 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2039 #endif 2040 return(ret); 2041 } else if ((cache->miscObjs != NULL) && 2042 (cache->miscObjs->number != 0)) 2043 { 2044 xmlXPathObjectPtr ret; 2045 /* 2046 * Fallback to misc-cache. 2047 */ 2048 2049 ret = (xmlXPathObjectPtr) 2050 cache->miscObjs->items[--cache->miscObjs->number]; 2051 2052 ret->type = XPATH_NODESET; 2053 ret->boolval = 0; 2054 ret->nodesetval = xmlXPathNodeSetCreate(val); 2055 #ifdef XP_DEBUG_OBJ_USAGE 2056 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); 2057 #endif 2058 return(ret); 2059 } 2060 } 2061 return(xmlXPathNewNodeSet(val)); 2062 } 2063 2064 /** 2065 * xmlXPathCacheNewCString: 2066 * @ctxt: the XPath context 2067 * @val: the char * value 2068 * 2069 * This is the cached version of xmlXPathNewCString(). 2070 * Acquire an xmlXPathObjectPtr of type string and of value @val 2071 * 2072 * Returns the created or reused object. 2073 */ 2074 static xmlXPathObjectPtr 2075 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) 2076 { 2077 if ((ctxt != NULL) && (ctxt->cache)) { 2078 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2079 2080 if ((cache->stringObjs != NULL) && 2081 (cache->stringObjs->number != 0)) 2082 { 2083 xmlXPathObjectPtr ret; 2084 2085 ret = (xmlXPathObjectPtr) 2086 cache->stringObjs->items[--cache->stringObjs->number]; 2087 2088 ret->type = XPATH_STRING; 2089 ret->stringval = xmlStrdup(BAD_CAST val); 2090 #ifdef XP_DEBUG_OBJ_USAGE 2091 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2092 #endif 2093 return(ret); 2094 } else if ((cache->miscObjs != NULL) && 2095 (cache->miscObjs->number != 0)) 2096 { 2097 xmlXPathObjectPtr ret; 2098 2099 ret = (xmlXPathObjectPtr) 2100 cache->miscObjs->items[--cache->miscObjs->number]; 2101 2102 ret->type = XPATH_STRING; 2103 ret->stringval = xmlStrdup(BAD_CAST val); 2104 #ifdef XP_DEBUG_OBJ_USAGE 2105 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2106 #endif 2107 return(ret); 2108 } 2109 } 2110 return(xmlXPathNewCString(val)); 2111 } 2112 2113 /** 2114 * xmlXPathCacheNewString: 2115 * @ctxt: the XPath context 2116 * @val: the xmlChar * value 2117 * 2118 * This is the cached version of xmlXPathNewString(). 2119 * Acquire an xmlXPathObjectPtr of type string and of value @val 2120 * 2121 * Returns the created or reused object. 2122 */ 2123 static xmlXPathObjectPtr 2124 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) 2125 { 2126 if ((ctxt != NULL) && (ctxt->cache)) { 2127 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2128 2129 if ((cache->stringObjs != NULL) && 2130 (cache->stringObjs->number != 0)) 2131 { 2132 xmlXPathObjectPtr ret; 2133 2134 ret = (xmlXPathObjectPtr) 2135 cache->stringObjs->items[--cache->stringObjs->number]; 2136 ret->type = XPATH_STRING; 2137 if (val != NULL) 2138 ret->stringval = xmlStrdup(val); 2139 else 2140 ret->stringval = xmlStrdup((const xmlChar *)""); 2141 #ifdef XP_DEBUG_OBJ_USAGE 2142 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2143 #endif 2144 return(ret); 2145 } else if ((cache->miscObjs != NULL) && 2146 (cache->miscObjs->number != 0)) 2147 { 2148 xmlXPathObjectPtr ret; 2149 2150 ret = (xmlXPathObjectPtr) 2151 cache->miscObjs->items[--cache->miscObjs->number]; 2152 2153 ret->type = XPATH_STRING; 2154 if (val != NULL) 2155 ret->stringval = xmlStrdup(val); 2156 else 2157 ret->stringval = xmlStrdup((const xmlChar *)""); 2158 #ifdef XP_DEBUG_OBJ_USAGE 2159 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); 2160 #endif 2161 return(ret); 2162 } 2163 } 2164 return(xmlXPathNewString(val)); 2165 } 2166 2167 /** 2168 * xmlXPathCacheNewBoolean: 2169 * @ctxt: the XPath context 2170 * @val: the boolean value 2171 * 2172 * This is the cached version of xmlXPathNewBoolean(). 2173 * Acquires an xmlXPathObjectPtr of type boolean and of value @val 2174 * 2175 * Returns the created or reused object. 2176 */ 2177 static xmlXPathObjectPtr 2178 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) 2179 { 2180 if ((ctxt != NULL) && (ctxt->cache)) { 2181 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2182 2183 if ((cache->booleanObjs != NULL) && 2184 (cache->booleanObjs->number != 0)) 2185 { 2186 xmlXPathObjectPtr ret; 2187 2188 ret = (xmlXPathObjectPtr) 2189 cache->booleanObjs->items[--cache->booleanObjs->number]; 2190 ret->type = XPATH_BOOLEAN; 2191 ret->boolval = (val != 0); 2192 #ifdef XP_DEBUG_OBJ_USAGE 2193 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2194 #endif 2195 return(ret); 2196 } else if ((cache->miscObjs != NULL) && 2197 (cache->miscObjs->number != 0)) 2198 { 2199 xmlXPathObjectPtr ret; 2200 2201 ret = (xmlXPathObjectPtr) 2202 cache->miscObjs->items[--cache->miscObjs->number]; 2203 2204 ret->type = XPATH_BOOLEAN; 2205 ret->boolval = (val != 0); 2206 #ifdef XP_DEBUG_OBJ_USAGE 2207 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); 2208 #endif 2209 return(ret); 2210 } 2211 } 2212 return(xmlXPathNewBoolean(val)); 2213 } 2214 2215 /** 2216 * xmlXPathCacheNewFloat: 2217 * @ctxt: the XPath context 2218 * @val: the double value 2219 * 2220 * This is the cached version of xmlXPathNewFloat(). 2221 * Acquires an xmlXPathObjectPtr of type double and of value @val 2222 * 2223 * Returns the created or reused object. 2224 */ 2225 static xmlXPathObjectPtr 2226 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) 2227 { 2228 if ((ctxt != NULL) && (ctxt->cache)) { 2229 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; 2230 2231 if ((cache->numberObjs != NULL) && 2232 (cache->numberObjs->number != 0)) 2233 { 2234 xmlXPathObjectPtr ret; 2235 2236 ret = (xmlXPathObjectPtr) 2237 cache->numberObjs->items[--cache->numberObjs->number]; 2238 ret->type = XPATH_NUMBER; 2239 ret->floatval = val; 2240 #ifdef XP_DEBUG_OBJ_USAGE 2241 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2242 #endif 2243 return(ret); 2244 } else if ((cache->miscObjs != NULL) && 2245 (cache->miscObjs->number != 0)) 2246 { 2247 xmlXPathObjectPtr ret; 2248 2249 ret = (xmlXPathObjectPtr) 2250 cache->miscObjs->items[--cache->miscObjs->number]; 2251 2252 ret->type = XPATH_NUMBER; 2253 ret->floatval = val; 2254 #ifdef XP_DEBUG_OBJ_USAGE 2255 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); 2256 #endif 2257 return(ret); 2258 } 2259 } 2260 return(xmlXPathNewFloat(val)); 2261 } 2262 2263 /** 2264 * xmlXPathCacheConvertString: 2265 * @ctxt: the XPath context 2266 * @val: an XPath object 2267 * 2268 * This is the cached version of xmlXPathConvertString(). 2269 * Converts an existing object to its string() equivalent 2270 * 2271 * Returns a created or reused object, the old one is freed (cached) 2272 * (or the operation is done directly on @val) 2273 */ 2274 2275 static xmlXPathObjectPtr 2276 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2277 xmlChar *res = NULL; 2278 2279 if (val == NULL) 2280 return(xmlXPathCacheNewCString(ctxt, "")); 2281 2282 switch (val->type) { 2283 case XPATH_UNDEFINED: 2284 #ifdef DEBUG_EXPR 2285 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 2286 #endif 2287 break; 2288 case XPATH_NODESET: 2289 case XPATH_XSLT_TREE: 2290 res = xmlXPathCastNodeSetToString(val->nodesetval); 2291 break; 2292 case XPATH_STRING: 2293 return(val); 2294 case XPATH_BOOLEAN: 2295 res = xmlXPathCastBooleanToString(val->boolval); 2296 break; 2297 case XPATH_NUMBER: 2298 res = xmlXPathCastNumberToString(val->floatval); 2299 break; 2300 case XPATH_USERS: 2301 case XPATH_POINT: 2302 case XPATH_RANGE: 2303 case XPATH_LOCATIONSET: 2304 TODO; 2305 break; 2306 } 2307 xmlXPathReleaseObject(ctxt, val); 2308 if (res == NULL) 2309 return(xmlXPathCacheNewCString(ctxt, "")); 2310 return(xmlXPathCacheWrapString(ctxt, res)); 2311 } 2312 2313 /** 2314 * xmlXPathCacheObjectCopy: 2315 * @ctxt: the XPath context 2316 * @val: the original object 2317 * 2318 * This is the cached version of xmlXPathObjectCopy(). 2319 * Acquire a copy of a given object 2320 * 2321 * Returns a created or reused created object. 2322 */ 2323 static xmlXPathObjectPtr 2324 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) 2325 { 2326 if (val == NULL) 2327 return(NULL); 2328 2329 if (XP_HAS_CACHE(ctxt)) { 2330 switch (val->type) { 2331 case XPATH_NODESET: 2332 return(xmlXPathCacheWrapNodeSet(ctxt, 2333 xmlXPathNodeSetMerge(NULL, val->nodesetval))); 2334 case XPATH_STRING: 2335 return(xmlXPathCacheNewString(ctxt, val->stringval)); 2336 case XPATH_BOOLEAN: 2337 return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); 2338 case XPATH_NUMBER: 2339 return(xmlXPathCacheNewFloat(ctxt, val->floatval)); 2340 default: 2341 break; 2342 } 2343 } 2344 return(xmlXPathObjectCopy(val)); 2345 } 2346 2347 /** 2348 * xmlXPathCacheConvertBoolean: 2349 * @ctxt: the XPath context 2350 * @val: an XPath object 2351 * 2352 * This is the cached version of xmlXPathConvertBoolean(). 2353 * Converts an existing object to its boolean() equivalent 2354 * 2355 * Returns a created or reused object, the old one is freed (or the operation 2356 * is done directly on @val) 2357 */ 2358 static xmlXPathObjectPtr 2359 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2360 xmlXPathObjectPtr ret; 2361 2362 if (val == NULL) 2363 return(xmlXPathCacheNewBoolean(ctxt, 0)); 2364 if (val->type == XPATH_BOOLEAN) 2365 return(val); 2366 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); 2367 xmlXPathReleaseObject(ctxt, val); 2368 return(ret); 2369 } 2370 2371 /** 2372 * xmlXPathCacheConvertNumber: 2373 * @ctxt: the XPath context 2374 * @val: an XPath object 2375 * 2376 * This is the cached version of xmlXPathConvertNumber(). 2377 * Converts an existing object to its number() equivalent 2378 * 2379 * Returns a created or reused object, the old one is freed (or the operation 2380 * is done directly on @val) 2381 */ 2382 static xmlXPathObjectPtr 2383 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { 2384 xmlXPathObjectPtr ret; 2385 2386 if (val == NULL) 2387 return(xmlXPathCacheNewFloat(ctxt, 0.0)); 2388 if (val->type == XPATH_NUMBER) 2389 return(val); 2390 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); 2391 xmlXPathReleaseObject(ctxt, val); 2392 return(ret); 2393 } 2394 2395 /************************************************************************ 2396 * * 2397 * Parser stacks related functions and macros * 2398 * * 2399 ************************************************************************/ 2400 2401 /** 2402 * xmlXPathSetFrame: 2403 * @ctxt: an XPath parser context 2404 * 2405 * Set the callee evaluation frame 2406 * 2407 * Returns the previous frame value to be restored once done 2408 */ 2409 static int 2410 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { 2411 int ret; 2412 2413 if (ctxt == NULL) 2414 return(0); 2415 ret = ctxt->valueFrame; 2416 ctxt->valueFrame = ctxt->valueNr; 2417 return(ret); 2418 } 2419 2420 /** 2421 * xmlXPathPopFrame: 2422 * @ctxt: an XPath parser context 2423 * @frame: the previous frame value 2424 * 2425 * Remove the callee evaluation frame 2426 */ 2427 static void 2428 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { 2429 if (ctxt == NULL) 2430 return; 2431 if (ctxt->valueNr < ctxt->valueFrame) { 2432 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2433 } 2434 ctxt->valueFrame = frame; 2435 } 2436 2437 /** 2438 * valuePop: 2439 * @ctxt: an XPath evaluation context 2440 * 2441 * Pops the top XPath object from the value stack 2442 * 2443 * Returns the XPath object just removed 2444 */ 2445 xmlXPathObjectPtr 2446 valuePop(xmlXPathParserContextPtr ctxt) 2447 { 2448 xmlXPathObjectPtr ret; 2449 2450 if ((ctxt == NULL) || (ctxt->valueNr <= 0)) 2451 return (NULL); 2452 2453 if (ctxt->valueNr <= ctxt->valueFrame) { 2454 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); 2455 return (NULL); 2456 } 2457 2458 ctxt->valueNr--; 2459 if (ctxt->valueNr > 0) 2460 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; 2461 else 2462 ctxt->value = NULL; 2463 ret = ctxt->valueTab[ctxt->valueNr]; 2464 ctxt->valueTab[ctxt->valueNr] = NULL; 2465 return (ret); 2466 } 2467 /** 2468 * valuePush: 2469 * @ctxt: an XPath evaluation context 2470 * @value: the XPath object 2471 * 2472 * Pushes a new XPath object on top of the value stack 2473 * 2474 * returns the number of items on the value stack 2475 */ 2476 int 2477 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2478 { 2479 if ((ctxt == NULL) || (value == NULL)) return(-1); 2480 if (ctxt->valueNr >= ctxt->valueMax) { 2481 xmlXPathObjectPtr *tmp; 2482 2483 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2484 2 * ctxt->valueMax * 2485 sizeof(ctxt->valueTab[0])); 2486 if (tmp == NULL) { 2487 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 2488 ctxt->error = XPATH_MEMORY_ERROR; 2489 return (0); 2490 } 2491 ctxt->valueMax *= 2; 2492 ctxt->valueTab = tmp; 2493 } 2494 ctxt->valueTab[ctxt->valueNr] = value; 2495 ctxt->value = value; 2496 return (ctxt->valueNr++); 2497 } 2498 2499 /** 2500 * xmlXPathPopBoolean: 2501 * @ctxt: an XPath parser context 2502 * 2503 * Pops a boolean from the stack, handling conversion if needed. 2504 * Check error with #xmlXPathCheckError. 2505 * 2506 * Returns the boolean 2507 */ 2508 int 2509 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 2510 xmlXPathObjectPtr obj; 2511 int ret; 2512 2513 obj = valuePop(ctxt); 2514 if (obj == NULL) { 2515 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2516 return(0); 2517 } 2518 if (obj->type != XPATH_BOOLEAN) 2519 ret = xmlXPathCastToBoolean(obj); 2520 else 2521 ret = obj->boolval; 2522 xmlXPathReleaseObject(ctxt->context, obj); 2523 return(ret); 2524 } 2525 2526 /** 2527 * xmlXPathPopNumber: 2528 * @ctxt: an XPath parser context 2529 * 2530 * Pops a number from the stack, handling conversion if needed. 2531 * Check error with #xmlXPathCheckError. 2532 * 2533 * Returns the number 2534 */ 2535 double 2536 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 2537 xmlXPathObjectPtr obj; 2538 double ret; 2539 2540 obj = valuePop(ctxt); 2541 if (obj == NULL) { 2542 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2543 return(0); 2544 } 2545 if (obj->type != XPATH_NUMBER) 2546 ret = xmlXPathCastToNumber(obj); 2547 else 2548 ret = obj->floatval; 2549 xmlXPathReleaseObject(ctxt->context, obj); 2550 return(ret); 2551 } 2552 2553 /** 2554 * xmlXPathPopString: 2555 * @ctxt: an XPath parser context 2556 * 2557 * Pops a string from the stack, handling conversion if needed. 2558 * Check error with #xmlXPathCheckError. 2559 * 2560 * Returns the string 2561 */ 2562 xmlChar * 2563 xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 2564 xmlXPathObjectPtr obj; 2565 xmlChar * ret; 2566 2567 obj = valuePop(ctxt); 2568 if (obj == NULL) { 2569 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2570 return(NULL); 2571 } 2572 ret = xmlXPathCastToString(obj); /* this does required strdup */ 2573 /* TODO: needs refactoring somewhere else */ 2574 if (obj->stringval == ret) 2575 obj->stringval = NULL; 2576 xmlXPathReleaseObject(ctxt->context, obj); 2577 return(ret); 2578 } 2579 2580 /** 2581 * xmlXPathPopNodeSet: 2582 * @ctxt: an XPath parser context 2583 * 2584 * Pops a node-set from the stack, handling conversion if needed. 2585 * Check error with #xmlXPathCheckError. 2586 * 2587 * Returns the node-set 2588 */ 2589 xmlNodeSetPtr 2590 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 2591 xmlXPathObjectPtr obj; 2592 xmlNodeSetPtr ret; 2593 2594 if (ctxt == NULL) return(NULL); 2595 if (ctxt->value == NULL) { 2596 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2597 return(NULL); 2598 } 2599 if (!xmlXPathStackIsNodeSet(ctxt)) { 2600 xmlXPathSetTypeError(ctxt); 2601 return(NULL); 2602 } 2603 obj = valuePop(ctxt); 2604 ret = obj->nodesetval; 2605 #if 0 2606 /* to fix memory leak of not clearing obj->user */ 2607 if (obj->boolval && obj->user != NULL) 2608 xmlFreeNodeList((xmlNodePtr) obj->user); 2609 #endif 2610 obj->nodesetval = NULL; 2611 xmlXPathReleaseObject(ctxt->context, obj); 2612 return(ret); 2613 } 2614 2615 /** 2616 * xmlXPathPopExternal: 2617 * @ctxt: an XPath parser context 2618 * 2619 * Pops an external object from the stack, handling conversion if needed. 2620 * Check error with #xmlXPathCheckError. 2621 * 2622 * Returns the object 2623 */ 2624 void * 2625 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 2626 xmlXPathObjectPtr obj; 2627 void * ret; 2628 2629 if ((ctxt == NULL) || (ctxt->value == NULL)) { 2630 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 2631 return(NULL); 2632 } 2633 if (ctxt->value->type != XPATH_USERS) { 2634 xmlXPathSetTypeError(ctxt); 2635 return(NULL); 2636 } 2637 obj = valuePop(ctxt); 2638 ret = obj->user; 2639 obj->user = NULL; 2640 xmlXPathReleaseObject(ctxt->context, obj); 2641 return(ret); 2642 } 2643 2644 /* 2645 * Macros for accessing the content. Those should be used only by the parser, 2646 * and not exported. 2647 * 2648 * Dirty macros, i.e. one need to make assumption on the context to use them 2649 * 2650 * CUR_PTR return the current pointer to the xmlChar to be parsed. 2651 * CUR returns the current xmlChar value, i.e. a 8 bit value 2652 * in ISO-Latin or UTF-8. 2653 * This should be used internally by the parser 2654 * only to compare to ASCII values otherwise it would break when 2655 * running with UTF-8 encoding. 2656 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 2657 * to compare on ASCII based substring. 2658 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 2659 * strings within the parser. 2660 * CURRENT Returns the current char value, with the full decoding of 2661 * UTF-8 if we are using this mode. It returns an int. 2662 * NEXT Skip to the next character, this does the proper decoding 2663 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 2664 * It returns the pointer to the current xmlChar. 2665 */ 2666 2667 #define CUR (*ctxt->cur) 2668 #define SKIP(val) ctxt->cur += (val) 2669 #define NXT(val) ctxt->cur[(val)] 2670 #define CUR_PTR ctxt->cur 2671 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 2672 2673 #define COPY_BUF(l,b,i,v) \ 2674 if (l == 1) b[i++] = (xmlChar) v; \ 2675 else i += xmlCopyChar(l,&b[i],v) 2676 2677 #define NEXTL(l) ctxt->cur += l 2678 2679 #define SKIP_BLANKS \ 2680 while (IS_BLANK_CH(*(ctxt->cur))) NEXT 2681 2682 #define CURRENT (*ctxt->cur) 2683 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 2684 2685 2686 #ifndef DBL_DIG 2687 #define DBL_DIG 16 2688 #endif 2689 #ifndef DBL_EPSILON 2690 #define DBL_EPSILON 1E-9 2691 #endif 2692 2693 #define UPPER_DOUBLE 1E9 2694 #define LOWER_DOUBLE 1E-5 2695 #define LOWER_DOUBLE_EXP 5 2696 2697 #define INTEGER_DIGITS DBL_DIG 2698 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) 2699 #define EXPONENT_DIGITS (3 + 2) 2700 2701 /** 2702 * xmlXPathFormatNumber: 2703 * @number: number to format 2704 * @buffer: output buffer 2705 * @buffersize: size of output buffer 2706 * 2707 * Convert the number into a string representation. 2708 */ 2709 static void 2710 xmlXPathFormatNumber(double number, char buffer[], int buffersize) 2711 { 2712 switch (xmlXPathIsInf(number)) { 2713 case 1: 2714 if (buffersize > (int)sizeof("Infinity")) 2715 snprintf(buffer, buffersize, "Infinity"); 2716 break; 2717 case -1: 2718 if (buffersize > (int)sizeof("-Infinity")) 2719 snprintf(buffer, buffersize, "-Infinity"); 2720 break; 2721 default: 2722 if (xmlXPathIsNaN(number)) { 2723 if (buffersize > (int)sizeof("NaN")) 2724 snprintf(buffer, buffersize, "NaN"); 2725 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 2726 snprintf(buffer, buffersize, "0"); 2727 } else if (number == ((int) number)) { 2728 char work[30]; 2729 char *ptr, *cur; 2730 int value = (int) number; 2731 2732 ptr = &buffer[0]; 2733 if (value == 0) { 2734 *ptr++ = '0'; 2735 } else { 2736 snprintf(work, 29, "%d", value); 2737 cur = &work[0]; 2738 while ((*cur) && (ptr - buffer < buffersize)) { 2739 *ptr++ = *cur++; 2740 } 2741 } 2742 if (ptr - buffer < buffersize) { 2743 *ptr = 0; 2744 } else if (buffersize > 0) { 2745 ptr--; 2746 *ptr = 0; 2747 } 2748 } else { 2749 /* 2750 For the dimension of work, 2751 DBL_DIG is number of significant digits 2752 EXPONENT is only needed for "scientific notation" 2753 3 is sign, decimal point, and terminating zero 2754 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction 2755 Note that this dimension is slightly (a few characters) 2756 larger than actually necessary. 2757 */ 2758 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; 2759 int integer_place, fraction_place; 2760 char *ptr; 2761 char *after_fraction; 2762 double absolute_value; 2763 int size; 2764 2765 absolute_value = fabs(number); 2766 2767 /* 2768 * First choose format - scientific or regular floating point. 2769 * In either case, result is in work, and after_fraction points 2770 * just past the fractional part. 2771 */ 2772 if ( ((absolute_value > UPPER_DOUBLE) || 2773 (absolute_value < LOWER_DOUBLE)) && 2774 (absolute_value != 0.0) ) { 2775 /* Use scientific notation */ 2776 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 2777 fraction_place = DBL_DIG - 1; 2778 size = snprintf(work, sizeof(work),"%*.*e", 2779 integer_place, fraction_place, number); 2780 while ((size > 0) && (work[size] != 'e')) size--; 2781 2782 } 2783 else { 2784 /* Use regular notation */ 2785 if (absolute_value > 0.0) { 2786 integer_place = (int)log10(absolute_value); 2787 if (integer_place > 0) 2788 fraction_place = DBL_DIG - integer_place - 1; 2789 else 2790 fraction_place = DBL_DIG - integer_place; 2791 } else { 2792 fraction_place = 1; 2793 } 2794 size = snprintf(work, sizeof(work), "%0.*f", 2795 fraction_place, number); 2796 } 2797 2798 /* Remove fractional trailing zeroes */ 2799 after_fraction = work + size; 2800 ptr = after_fraction; 2801 while (*(--ptr) == '0') 2802 ; 2803 if (*ptr != '.') 2804 ptr++; 2805 while ((*ptr++ = *after_fraction++) != 0); 2806 2807 /* Finally copy result back to caller */ 2808 size = strlen(work) + 1; 2809 if (size > buffersize && buffersize <= (int)sizeof(work)) { 2810 work[buffersize - 1] = 0; 2811 size = buffersize; 2812 } 2813 memmove(buffer, work, size); 2814 } 2815 break; 2816 } 2817 } 2818 2819 2820 /************************************************************************ 2821 * * 2822 * Routines to handle NodeSets * 2823 * * 2824 ************************************************************************/ 2825 2826 /** 2827 * xmlXPathOrderDocElems: 2828 * @doc: an input document 2829 * 2830 * Call this routine to speed up XPath computation on static documents. 2831 * This stamps all the element nodes with the document order 2832 * Like for line information, the order is kept in the element->content 2833 * field, the value stored is actually - the node number (starting at -1) 2834 * to be able to differentiate from line numbers. 2835 * 2836 * Returns the number of elements found in the document or -1 in case 2837 * of error. 2838 */ 2839 long 2840 xmlXPathOrderDocElems(xmlDocPtr doc) { 2841 long count = 0; 2842 xmlNodePtr cur; 2843 2844 if (doc == NULL) 2845 return(-1); 2846 cur = doc->children; 2847 while (cur != NULL) { 2848 if (cur->type == XML_ELEMENT_NODE) { 2849 cur->content = (void *) (-(++count)); 2850 if (cur->children != NULL) { 2851 cur = cur->children; 2852 continue; 2853 } 2854 } 2855 if (cur->next != NULL) { 2856 cur = cur->next; 2857 continue; 2858 } 2859 do { 2860 cur = cur->parent; 2861 if (cur == NULL) 2862 break; 2863 if (cur == (xmlNodePtr) doc) { 2864 cur = NULL; 2865 break; 2866 } 2867 if (cur->next != NULL) { 2868 cur = cur->next; 2869 break; 2870 } 2871 } while (cur != NULL); 2872 } 2873 return(count); 2874 } 2875 2876 /** 2877 * xmlXPathCmpNodes: 2878 * @node1: the first node 2879 * @node2: the second node 2880 * 2881 * Compare two nodes w.r.t document order 2882 * 2883 * Returns -2 in case of error 1 if first point < second point, 0 if 2884 * it's the same node, -1 otherwise 2885 */ 2886 int 2887 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 2888 int depth1, depth2; 2889 int attr1 = 0, attr2 = 0; 2890 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; 2891 xmlNodePtr cur, root; 2892 2893 if ((node1 == NULL) || (node2 == NULL)) 2894 return(-2); 2895 /* 2896 * a couple of optimizations which will avoid computations in most cases 2897 */ 2898 if (node1 == node2) /* trivial case */ 2899 return(0); 2900 if (node1->type == XML_ATTRIBUTE_NODE) { 2901 attr1 = 1; 2902 attrNode1 = node1; 2903 node1 = node1->parent; 2904 } 2905 if (node2->type == XML_ATTRIBUTE_NODE) { 2906 attr2 = 1; 2907 attrNode2 = node2; 2908 node2 = node2->parent; 2909 } 2910 if (node1 == node2) { 2911 if (attr1 == attr2) { 2912 /* not required, but we keep attributes in order */ 2913 if (attr1 != 0) { 2914 cur = attrNode2->prev; 2915 while (cur != NULL) { 2916 if (cur == attrNode1) 2917 return (1); 2918 cur = cur->prev; 2919 } 2920 return (-1); 2921 } 2922 return(0); 2923 } 2924 if (attr2 == 1) 2925 return(1); 2926 return(-1); 2927 } 2928 if ((node1->type == XML_NAMESPACE_DECL) || 2929 (node2->type == XML_NAMESPACE_DECL)) 2930 return(1); 2931 if (node1 == node2->prev) 2932 return(1); 2933 if (node1 == node2->next) 2934 return(-1); 2935 2936 /* 2937 * Speedup using document order if availble. 2938 */ 2939 if ((node1->type == XML_ELEMENT_NODE) && 2940 (node2->type == XML_ELEMENT_NODE) && 2941 (0 > (long) node1->content) && 2942 (0 > (long) node2->content) && 2943 (node1->doc == node2->doc)) { 2944 long l1, l2; 2945 2946 l1 = -((long) node1->content); 2947 l2 = -((long) node2->content); 2948 if (l1 < l2) 2949 return(1); 2950 if (l1 > l2) 2951 return(-1); 2952 } 2953 2954 /* 2955 * compute depth to root 2956 */ 2957 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 2958 if (cur == node1) 2959 return(1); 2960 depth2++; 2961 } 2962 root = cur; 2963 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 2964 if (cur == node2) 2965 return(-1); 2966 depth1++; 2967 } 2968 /* 2969 * Distinct document (or distinct entities :-( ) case. 2970 */ 2971 if (root != cur) { 2972 return(-2); 2973 } 2974 /* 2975 * get the nearest common ancestor. 2976 */ 2977 while (depth1 > depth2) { 2978 depth1--; 2979 node1 = node1->parent; 2980 } 2981 while (depth2 > depth1) { 2982 depth2--; 2983 node2 = node2->parent; 2984 } 2985 while (node1->parent != node2->parent) { 2986 node1 = node1->parent; 2987 node2 = node2->parent; 2988 /* should not happen but just in case ... */ 2989 if ((node1 == NULL) || (node2 == NULL)) 2990 return(-2); 2991 } 2992 /* 2993 * Find who's first. 2994 */ 2995 if (node1 == node2->prev) 2996 return(1); 2997 if (node1 == node2->next) 2998 return(-1); 2999 /* 3000 * Speedup using document order if availble. 3001 */ 3002 if ((node1->type == XML_ELEMENT_NODE) && 3003 (node2->type == XML_ELEMENT_NODE) && 3004 (0 > (long) node1->content) && 3005 (0 > (long) node2->content) && 3006 (node1->doc == node2->doc)) { 3007 long l1, l2; 3008 3009 l1 = -((long) node1->content); 3010 l2 = -((long) node2->content); 3011 if (l1 < l2) 3012 return(1); 3013 if (l1 > l2) 3014 return(-1); 3015 } 3016 3017 for (cur = node1->next;cur != NULL;cur = cur->next) 3018 if (cur == node2) 3019 return(1); 3020 return(-1); /* assume there is no sibling list corruption */ 3021 } 3022 3023 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3024 /** 3025 * xmlXPathCmpNodesExt: 3026 * @node1: the first node 3027 * @node2: the second node 3028 * 3029 * Compare two nodes w.r.t document order. 3030 * This one is optimized for handling of non-element nodes. 3031 * 3032 * Returns -2 in case of error 1 if first point < second point, 0 if 3033 * it's the same node, -1 otherwise 3034 */ 3035 static int 3036 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { 3037 int depth1, depth2; 3038 int misc = 0, precedence1 = 0, precedence2 = 0; 3039 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; 3040 xmlNodePtr cur, root; 3041 long l1, l2; 3042 3043 if ((node1 == NULL) || (node2 == NULL)) 3044 return(-2); 3045 3046 if (node1 == node2) 3047 return(0); 3048 3049 /* 3050 * a couple of optimizations which will avoid computations in most cases 3051 */ 3052 switch (node1->type) { 3053 case XML_ELEMENT_NODE: 3054 if (node2->type == XML_ELEMENT_NODE) { 3055 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */ 3056 (0 > (long) node2->content) && 3057 (node1->doc == node2->doc)) 3058 { 3059 l1 = -((long) node1->content); 3060 l2 = -((long) node2->content); 3061 if (l1 < l2) 3062 return(1); 3063 if (l1 > l2) 3064 return(-1); 3065 } else 3066 goto turtle_comparison; 3067 } 3068 break; 3069 case XML_ATTRIBUTE_NODE: 3070 precedence1 = 1; /* element is owner */ 3071 miscNode1 = node1; 3072 node1 = node1->parent; 3073 misc = 1; 3074 break; 3075 case XML_TEXT_NODE: 3076 case XML_CDATA_SECTION_NODE: 3077 case XML_COMMENT_NODE: 3078 case XML_PI_NODE: { 3079 miscNode1 = node1; 3080 /* 3081 * Find nearest element node. 3082 */ 3083 if (node1->prev != NULL) { 3084 do { 3085 node1 = node1->prev; 3086 if (node1->type == XML_ELEMENT_NODE) { 3087 precedence1 = 3; /* element in prev-sibl axis */ 3088 break; 3089 } 3090 if (node1->prev == NULL) { 3091 precedence1 = 2; /* element is parent */ 3092 /* 3093 * URGENT TODO: Are there any cases, where the 3094 * parent of such a node is not an element node? 3095 */ 3096 node1 = node1->parent; 3097 break; 3098 } 3099 } while (1); 3100 } else { 3101 precedence1 = 2; /* element is parent */ 3102 node1 = node1->parent; 3103 } 3104 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || 3105 (0 <= (long) node1->content)) { 3106 /* 3107 * Fallback for whatever case. 3108 */ 3109 node1 = miscNode1; 3110 precedence1 = 0; 3111 } else 3112 misc = 1; 3113 } 3114 break; 3115 case XML_NAMESPACE_DECL: 3116 /* 3117 * TODO: why do we return 1 for namespace nodes? 3118 */ 3119 return(1); 3120 default: 3121 break; 3122 } 3123 switch (node2->type) { 3124 case XML_ELEMENT_NODE: 3125 break; 3126 case XML_ATTRIBUTE_NODE: 3127 precedence2 = 1; /* element is owner */ 3128 miscNode2 = node2; 3129 node2 = node2->parent; 3130 misc = 1; 3131 break; 3132 case XML_TEXT_NODE: 3133 case XML_CDATA_SECTION_NODE: 3134 case XML_COMMENT_NODE: 3135 case XML_PI_NODE: { 3136 miscNode2 = node2; 3137 if (node2->prev != NULL) { 3138 do { 3139 node2 = node2->prev; 3140 if (node2->type == XML_ELEMENT_NODE) { 3141 precedence2 = 3; /* element in prev-sibl axis */ 3142 break; 3143 } 3144 if (node2->prev == NULL) { 3145 precedence2 = 2; /* element is parent */ 3146 node2 = node2->parent; 3147 break; 3148 } 3149 } while (1); 3150 } else { 3151 precedence2 = 2; /* element is parent */ 3152 node2 = node2->parent; 3153 } 3154 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || 3155 (0 <= (long) node1->content)) 3156 { 3157 node2 = miscNode2; 3158 precedence2 = 0; 3159 } else 3160 misc = 1; 3161 } 3162 break; 3163 case XML_NAMESPACE_DECL: 3164 return(1); 3165 default: 3166 break; 3167 } 3168 if (misc) { 3169 if (node1 == node2) { 3170 if (precedence1 == precedence2) { 3171 /* 3172 * The ugly case; but normally there aren't many 3173 * adjacent non-element nodes around. 3174 */ 3175 cur = miscNode2->prev; 3176 while (cur != NULL) { 3177 if (cur == miscNode1) 3178 return(1); 3179 if (cur->type == XML_ELEMENT_NODE) 3180 return(-1); 3181 cur = cur->prev; 3182 } 3183 return (-1); 3184 } else { 3185 /* 3186 * Evaluate based on higher precedence wrt to the element. 3187 * TODO: This assumes attributes are sorted before content. 3188 * Is this 100% correct? 3189 */ 3190 if (precedence1 < precedence2) 3191 return(1); 3192 else 3193 return(-1); 3194 } 3195 } 3196 /* 3197 * Special case: One of the helper-elements is contained by the other. 3198 * <foo> 3199 * <node2> 3200 * <node1>Text-1(precedence1 == 2)</node1> 3201 * </node2> 3202 * Text-6(precedence2 == 3) 3203 * </foo> 3204 */ 3205 if ((precedence2 == 3) && (precedence1 > 1)) { 3206 cur = node1->parent; 3207 while (cur) { 3208 if (cur == node2) 3209 return(1); 3210 cur = cur->parent; 3211 } 3212 } 3213 if ((precedence1 == 3) && (precedence2 > 1)) { 3214 cur = node2->parent; 3215 while (cur) { 3216 if (cur == node1) 3217 return(-1); 3218 cur = cur->parent; 3219 } 3220 } 3221 } 3222 3223 /* 3224 * Speedup using document order if availble. 3225 */ 3226 if ((node1->type == XML_ELEMENT_NODE) && 3227 (node2->type == XML_ELEMENT_NODE) && 3228 (0 > (long) node1->content) && 3229 (0 > (long) node2->content) && 3230 (node1->doc == node2->doc)) { 3231 3232 l1 = -((long) node1->content); 3233 l2 = -((long) node2->content); 3234 if (l1 < l2) 3235 return(1); 3236 if (l1 > l2) 3237 return(-1); 3238 } 3239 3240 turtle_comparison: 3241 3242 if (node1 == node2->prev) 3243 return(1); 3244 if (node1 == node2->next) 3245 return(-1); 3246 /* 3247 * compute depth to root 3248 */ 3249 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 3250 if (cur == node1) 3251 return(1); 3252 depth2++; 3253 } 3254 root = cur; 3255 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 3256 if (cur == node2) 3257 return(-1); 3258 depth1++; 3259 } 3260 /* 3261 * Distinct document (or distinct entities :-( ) case. 3262 */ 3263 if (root != cur) { 3264 return(-2); 3265 } 3266 /* 3267 * get the nearest common ancestor. 3268 */ 3269 while (depth1 > depth2) { 3270 depth1--; 3271 node1 = node1->parent; 3272 } 3273 while (depth2 > depth1) { 3274 depth2--; 3275 node2 = node2->parent; 3276 } 3277 while (node1->parent != node2->parent) { 3278 node1 = node1->parent; 3279 node2 = node2->parent; 3280 /* should not happen but just in case ... */ 3281 if ((node1 == NULL) || (node2 == NULL)) 3282 return(-2); 3283 } 3284 /* 3285 * Find who's first. 3286 */ 3287 if (node1 == node2->prev) 3288 return(1); 3289 if (node1 == node2->next) 3290 return(-1); 3291 /* 3292 * Speedup using document order if availble. 3293 */ 3294 if ((node1->type == XML_ELEMENT_NODE) && 3295 (node2->type == XML_ELEMENT_NODE) && 3296 (0 > (long) node1->content) && 3297 (0 > (long) node2->content) && 3298 (node1->doc == node2->doc)) { 3299 3300 l1 = -((long) node1->content); 3301 l2 = -((long) node2->content); 3302 if (l1 < l2) 3303 return(1); 3304 if (l1 > l2) 3305 return(-1); 3306 } 3307 3308 for (cur = node1->next;cur != NULL;cur = cur->next) 3309 if (cur == node2) 3310 return(1); 3311 return(-1); /* assume there is no sibling list corruption */ 3312 } 3313 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ 3314 3315 /** 3316 * xmlXPathNodeSetSort: 3317 * @set: the node set 3318 * 3319 * Sort the node set in document order 3320 */ 3321 void 3322 xmlXPathNodeSetSort(xmlNodeSetPtr set) { 3323 int i, j, incr, len; 3324 xmlNodePtr tmp; 3325 3326 if (set == NULL) 3327 return; 3328 3329 /* Use Shell's sort to sort the node-set */ 3330 len = set->nodeNr; 3331 for (incr = len / 2; incr > 0; incr /= 2) { 3332 for (i = incr; i < len; i++) { 3333 j = i - incr; 3334 while (j >= 0) { 3335 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON 3336 if (xmlXPathCmpNodesExt(set->nodeTab[j], 3337 set->nodeTab[j + incr]) == -1) 3338 #else 3339 if (xmlXPathCmpNodes(set->nodeTab[j], 3340 set->nodeTab[j + incr]) == -1) 3341 #endif 3342 { 3343 tmp = set->nodeTab[j]; 3344 set->nodeTab[j] = set->nodeTab[j + incr]; 3345 set->nodeTab[j + incr] = tmp; 3346 j -= incr; 3347 } else 3348 break; 3349 } 3350 } 3351 } 3352 } 3353 3354 #define XML_NODESET_DEFAULT 10 3355 /** 3356 * xmlXPathNodeSetDupNs: 3357 * @node: the parent node of the namespace XPath node 3358 * @ns: the libxml namespace declaration node. 3359 * 3360 * Namespace node in libxml don't match the XPath semantic. In a node set 3361 * the namespace nodes are duplicated and the next pointer is set to the 3362 * parent node in the XPath semantic. 3363 * 3364 * Returns the newly created object. 3365 */ 3366 static xmlNodePtr 3367 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 3368 xmlNsPtr cur; 3369 3370 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3371 return(NULL); 3372 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 3373 return((xmlNodePtr) ns); 3374 3375 /* 3376 * Allocate a new Namespace and fill the fields. 3377 */ 3378 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 3379 if (cur == NULL) { 3380 xmlXPathErrMemory(NULL, "duplicating namespace\n"); 3381 return(NULL); 3382 } 3383 memset(cur, 0, sizeof(xmlNs)); 3384 cur->type = XML_NAMESPACE_DECL; 3385 if (ns->href != NULL) 3386 cur->href = xmlStrdup(ns->href); 3387 if (ns->prefix != NULL) 3388 cur->prefix = xmlStrdup(ns->prefix); 3389 cur->next = (xmlNsPtr) node; 3390 return((xmlNodePtr) cur); 3391 } 3392 3393 /** 3394 * xmlXPathNodeSetFreeNs: 3395 * @ns: the XPath namespace node found in a nodeset. 3396 * 3397 * Namespace nodes in libxml don't match the XPath semantic. In a node set 3398 * the namespace nodes are duplicated and the next pointer is set to the 3399 * parent node in the XPath semantic. Check if such a node needs to be freed 3400 */ 3401 void 3402 xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 3403 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 3404 return; 3405 3406 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 3407 if (ns->href != NULL) 3408 xmlFree((xmlChar *)ns->href); 3409 if (ns->prefix != NULL) 3410 xmlFree((xmlChar *)ns->prefix); 3411 xmlFree(ns); 3412 } 3413 } 3414 3415 /** 3416 * xmlXPathNodeSetCreate: 3417 * @val: an initial xmlNodePtr, or NULL 3418 * 3419 * Create a new xmlNodeSetPtr of type double and of value @val 3420 * 3421 * Returns the newly created object. 3422 */ 3423 xmlNodeSetPtr 3424 xmlXPathNodeSetCreate(xmlNodePtr val) { 3425 xmlNodeSetPtr ret; 3426 3427 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3428 if (ret == NULL) { 3429 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3430 return(NULL); 3431 } 3432 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3433 if (val != NULL) { 3434 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3435 sizeof(xmlNodePtr)); 3436 if (ret->nodeTab == NULL) { 3437 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3438 xmlFree(ret); 3439 return(NULL); 3440 } 3441 memset(ret->nodeTab, 0 , 3442 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3443 ret->nodeMax = XML_NODESET_DEFAULT; 3444 if (val->type == XML_NAMESPACE_DECL) { 3445 xmlNsPtr ns = (xmlNsPtr) val; 3446 3447 ret->nodeTab[ret->nodeNr++] = 3448 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3449 } else 3450 ret->nodeTab[ret->nodeNr++] = val; 3451 } 3452 return(ret); 3453 } 3454 3455 /** 3456 * xmlXPathNodeSetCreateSize: 3457 * @size: the initial size of the set 3458 * 3459 * Create a new xmlNodeSetPtr of type double and of value @val 3460 * 3461 * Returns the newly created object. 3462 */ 3463 static xmlNodeSetPtr 3464 xmlXPathNodeSetCreateSize(int size) { 3465 xmlNodeSetPtr ret; 3466 3467 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 3468 if (ret == NULL) { 3469 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3470 return(NULL); 3471 } 3472 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 3473 if (size < XML_NODESET_DEFAULT) 3474 size = XML_NODESET_DEFAULT; 3475 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr)); 3476 if (ret->nodeTab == NULL) { 3477 xmlXPathErrMemory(NULL, "creating nodeset\n"); 3478 xmlFree(ret); 3479 return(NULL); 3480 } 3481 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr)); 3482 ret->nodeMax = size; 3483 return(ret); 3484 } 3485 3486 /** 3487 * xmlXPathNodeSetContains: 3488 * @cur: the node-set 3489 * @val: the node 3490 * 3491 * checks whether @cur contains @val 3492 * 3493 * Returns true (1) if @cur contains @val, false (0) otherwise 3494 */ 3495 int 3496 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 3497 int i; 3498 3499 if ((cur == NULL) || (val == NULL)) return(0); 3500 if (val->type == XML_NAMESPACE_DECL) { 3501 for (i = 0; i < cur->nodeNr; i++) { 3502 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3503 xmlNsPtr ns1, ns2; 3504 3505 ns1 = (xmlNsPtr) val; 3506 ns2 = (xmlNsPtr) cur->nodeTab[i]; 3507 if (ns1 == ns2) 3508 return(1); 3509 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 3510 (xmlStrEqual(ns1->prefix, ns2->prefix))) 3511 return(1); 3512 } 3513 } 3514 } else { 3515 for (i = 0; i < cur->nodeNr; i++) { 3516 if (cur->nodeTab[i] == val) 3517 return(1); 3518 } 3519 } 3520 return(0); 3521 } 3522 3523 /** 3524 * xmlXPathNodeSetAddNs: 3525 * @cur: the initial node set 3526 * @node: the hosting node 3527 * @ns: a the namespace node 3528 * 3529 * add a new namespace node to an existing NodeSet 3530 */ 3531 void 3532 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 3533 int i; 3534 3535 3536 if ((cur == NULL) || (ns == NULL) || (node == NULL) || 3537 (ns->type != XML_NAMESPACE_DECL) || 3538 (node->type != XML_ELEMENT_NODE)) 3539 return; 3540 3541 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3542 /* 3543 * prevent duplicates 3544 */ 3545 for (i = 0;i < cur->nodeNr;i++) { 3546 if ((cur->nodeTab[i] != NULL) && 3547 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 3548 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 3549 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 3550 return; 3551 } 3552 3553 /* 3554 * grow the nodeTab if needed 3555 */ 3556 if (cur->nodeMax == 0) { 3557 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3558 sizeof(xmlNodePtr)); 3559 if (cur->nodeTab == NULL) { 3560 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3561 return; 3562 } 3563 memset(cur->nodeTab, 0 , 3564 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3565 cur->nodeMax = XML_NODESET_DEFAULT; 3566 } else if (cur->nodeNr == cur->nodeMax) { 3567 xmlNodePtr *temp; 3568 3569 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3570 sizeof(xmlNodePtr)); 3571 if (temp == NULL) { 3572 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3573 return; 3574 } 3575 cur->nodeMax *= 2; 3576 cur->nodeTab = temp; 3577 } 3578 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 3579 } 3580 3581 /** 3582 * xmlXPathNodeSetAdd: 3583 * @cur: the initial node set 3584 * @val: a new xmlNodePtr 3585 * 3586 * add a new xmlNodePtr to an existing NodeSet 3587 */ 3588 void 3589 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 3590 int i; 3591 3592 if ((cur == NULL) || (val == NULL)) return; 3593 3594 #if 0 3595 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3596 return; /* an XSLT fake node */ 3597 #endif 3598 3599 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3600 /* 3601 * prevent duplcates 3602 */ 3603 for (i = 0;i < cur->nodeNr;i++) 3604 if (cur->nodeTab[i] == val) return; 3605 3606 /* 3607 * grow the nodeTab if needed 3608 */ 3609 if (cur->nodeMax == 0) { 3610 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3611 sizeof(xmlNodePtr)); 3612 if (cur->nodeTab == NULL) { 3613 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3614 return; 3615 } 3616 memset(cur->nodeTab, 0 , 3617 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3618 cur->nodeMax = XML_NODESET_DEFAULT; 3619 } else if (cur->nodeNr == cur->nodeMax) { 3620 xmlNodePtr *temp; 3621 3622 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3623 sizeof(xmlNodePtr)); 3624 if (temp == NULL) { 3625 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3626 return; 3627 } 3628 cur->nodeMax *= 2; 3629 cur->nodeTab = temp; 3630 } 3631 if (val->type == XML_NAMESPACE_DECL) { 3632 xmlNsPtr ns = (xmlNsPtr) val; 3633 3634 cur->nodeTab[cur->nodeNr++] = 3635 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3636 } else 3637 cur->nodeTab[cur->nodeNr++] = val; 3638 } 3639 3640 /** 3641 * xmlXPathNodeSetAddUnique: 3642 * @cur: the initial node set 3643 * @val: a new xmlNodePtr 3644 * 3645 * add a new xmlNodePtr to an existing NodeSet, optimized version 3646 * when we are sure the node is not already in the set. 3647 */ 3648 void 3649 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 3650 if ((cur == NULL) || (val == NULL)) return; 3651 3652 #if 0 3653 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) 3654 return; /* an XSLT fake node */ 3655 #endif 3656 3657 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3658 /* 3659 * grow the nodeTab if needed 3660 */ 3661 if (cur->nodeMax == 0) { 3662 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3663 sizeof(xmlNodePtr)); 3664 if (cur->nodeTab == NULL) { 3665 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3666 return; 3667 } 3668 memset(cur->nodeTab, 0 , 3669 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3670 cur->nodeMax = XML_NODESET_DEFAULT; 3671 } else if (cur->nodeNr == cur->nodeMax) { 3672 xmlNodePtr *temp; 3673 3674 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * 3675 sizeof(xmlNodePtr)); 3676 if (temp == NULL) { 3677 xmlXPathErrMemory(NULL, "growing nodeset\n"); 3678 return; 3679 } 3680 cur->nodeTab = temp; 3681 cur->nodeMax *= 2; 3682 } 3683 if (val->type == XML_NAMESPACE_DECL) { 3684 xmlNsPtr ns = (xmlNsPtr) val; 3685 3686 cur->nodeTab[cur->nodeNr++] = 3687 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3688 } else 3689 cur->nodeTab[cur->nodeNr++] = val; 3690 } 3691 3692 /** 3693 * xmlXPathNodeSetMerge: 3694 * @val1: the first NodeSet or NULL 3695 * @val2: the second NodeSet 3696 * 3697 * Merges two nodesets, all nodes from @val2 are added to @val1 3698 * if @val1 is NULL, a new set is created and copied from @val2 3699 * 3700 * Returns @val1 once extended or NULL in case of error. 3701 */ 3702 xmlNodeSetPtr 3703 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3704 int i, j, initNr, skip; 3705 xmlNodePtr n1, n2; 3706 3707 if (val2 == NULL) return(val1); 3708 if (val1 == NULL) { 3709 val1 = xmlXPathNodeSetCreate(NULL); 3710 if (val1 == NULL) 3711 return (NULL); 3712 #if 0 3713 /* 3714 * TODO: The optimization won't work in every case, since 3715 * those nasty namespace nodes need to be added with 3716 * xmlXPathNodeSetDupNs() to the set; thus a pure 3717 * memcpy is not possible. 3718 * If there was a flag on the nodesetval, indicating that 3719 * some temporary nodes are in, that would be helpfull. 3720 */ 3721 /* 3722 * Optimization: Create an equally sized node-set 3723 * and memcpy the content. 3724 */ 3725 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); 3726 if (val1 == NULL) 3727 return(NULL); 3728 if (val2->nodeNr != 0) { 3729 if (val2->nodeNr == 1) 3730 *(val1->nodeTab) = *(val2->nodeTab); 3731 else { 3732 memcpy(val1->nodeTab, val2->nodeTab, 3733 val2->nodeNr * sizeof(xmlNodePtr)); 3734 } 3735 val1->nodeNr = val2->nodeNr; 3736 } 3737 return(val1); 3738 #endif 3739 } 3740 3741 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3742 initNr = val1->nodeNr; 3743 3744 for (i = 0;i < val2->nodeNr;i++) { 3745 n2 = val2->nodeTab[i]; 3746 /* 3747 * check against duplicates 3748 */ 3749 skip = 0; 3750 for (j = 0; j < initNr; j++) { 3751 n1 = val1->nodeTab[j]; 3752 if (n1 == n2) { 3753 skip = 1; 3754 break; 3755 } else if ((n1->type == XML_NAMESPACE_DECL) && 3756 (n2->type == XML_NAMESPACE_DECL)) { 3757 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3758 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3759 ((xmlNsPtr) n2)->prefix))) 3760 { 3761 skip = 1; 3762 break; 3763 } 3764 } 3765 } 3766 if (skip) 3767 continue; 3768 3769 /* 3770 * grow the nodeTab if needed 3771 */ 3772 if (val1->nodeMax == 0) { 3773 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3774 sizeof(xmlNodePtr)); 3775 if (val1->nodeTab == NULL) { 3776 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3777 return(NULL); 3778 } 3779 memset(val1->nodeTab, 0 , 3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3781 val1->nodeMax = XML_NODESET_DEFAULT; 3782 } else if (val1->nodeNr == val1->nodeMax) { 3783 xmlNodePtr *temp; 3784 3785 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * 3786 sizeof(xmlNodePtr)); 3787 if (temp == NULL) { 3788 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3789 return(NULL); 3790 } 3791 val1->nodeTab = temp; 3792 val1->nodeMax *= 2; 3793 } 3794 if (n2->type == XML_NAMESPACE_DECL) { 3795 xmlNsPtr ns = (xmlNsPtr) n2; 3796 3797 val1->nodeTab[val1->nodeNr++] = 3798 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3799 } else 3800 val1->nodeTab[val1->nodeNr++] = n2; 3801 } 3802 3803 return(val1); 3804 } 3805 3806 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 3807 /** 3808 * xmlXPathNodeSetMergeUnique: 3809 * @val1: the first NodeSet or NULL 3810 * @val2: the second NodeSet 3811 * 3812 * Merges two nodesets, all nodes from @val2 are added to @val1 3813 * if @val1 is NULL, a new set is created and copied from @val2 3814 * 3815 * Returns @val1 once extended or NULL in case of error. 3816 */ 3817 static xmlNodeSetPtr 3818 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 3819 int i; 3820 3821 if (val2 == NULL) return(val1); 3822 if (val1 == NULL) { 3823 val1 = xmlXPathNodeSetCreate(NULL); 3824 } 3825 if (val1 == NULL) 3826 return (NULL); 3827 3828 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 3829 3830 for (i = 0;i < val2->nodeNr;i++) { 3831 /* 3832 * grow the nodeTab if needed 3833 */ 3834 if (val1->nodeMax == 0) { 3835 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 3836 sizeof(xmlNodePtr)); 3837 if (val1->nodeTab == NULL) { 3838 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3839 return(NULL); 3840 } 3841 memset(val1->nodeTab, 0 , 3842 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3843 val1->nodeMax = XML_NODESET_DEFAULT; 3844 } else if (val1->nodeNr == val1->nodeMax) { 3845 xmlNodePtr *temp; 3846 3847 val1->nodeMax *= 2; 3848 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 3849 sizeof(xmlNodePtr)); 3850 if (temp == NULL) { 3851 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3852 return(NULL); 3853 } 3854 val1->nodeTab = temp; 3855 } 3856 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { 3857 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; 3858 3859 val1->nodeTab[val1->nodeNr++] = 3860 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3861 } else 3862 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; 3863 } 3864 3865 return(val1); 3866 } 3867 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ 3868 3869 /** 3870 * xmlXPathNodeSetMergeAndClear: 3871 * @set1: the first NodeSet or NULL 3872 * @set2: the second NodeSet 3873 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3874 * 3875 * Merges two nodesets, all nodes from @set2 are added to @set1 3876 * if @set1 is NULL, a new set is created and copied from @set2. 3877 * Checks for duplicate nodes. Clears set2. 3878 * 3879 * Returns @set1 once extended or NULL in case of error. 3880 */ 3881 static xmlNodeSetPtr 3882 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3883 int hasNullEntries) 3884 { 3885 if ((set1 == NULL) && (hasNullEntries == 0)) { 3886 /* 3887 * Note that doing a memcpy of the list, namespace nodes are 3888 * just assigned to set1, since set2 is cleared anyway. 3889 */ 3890 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 3891 if (set1 == NULL) 3892 return(NULL); 3893 if (set2->nodeNr != 0) { 3894 memcpy(set1->nodeTab, set2->nodeTab, 3895 set2->nodeNr * sizeof(xmlNodePtr)); 3896 set1->nodeNr = set2->nodeNr; 3897 } 3898 } else { 3899 int i, j, initNbSet1; 3900 xmlNodePtr n1, n2; 3901 3902 if (set1 == NULL) 3903 set1 = xmlXPathNodeSetCreate(NULL); 3904 if (set1 == NULL) 3905 return (NULL); 3906 3907 initNbSet1 = set1->nodeNr; 3908 for (i = 0;i < set2->nodeNr;i++) { 3909 n2 = set2->nodeTab[i]; 3910 /* 3911 * Skip NULLed entries. 3912 */ 3913 if (n2 == NULL) 3914 continue; 3915 /* 3916 * Skip duplicates. 3917 */ 3918 for (j = 0; j < initNbSet1; j++) { 3919 n1 = set1->nodeTab[j]; 3920 if (n1 == n2) { 3921 goto skip_node; 3922 } else if ((n1->type == XML_NAMESPACE_DECL) && 3923 (n2->type == XML_NAMESPACE_DECL)) 3924 { 3925 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && 3926 (xmlStrEqual(((xmlNsPtr) n1)->prefix, 3927 ((xmlNsPtr) n2)->prefix))) 3928 { 3929 /* 3930 * Free the namespace node. 3931 */ 3932 set2->nodeTab[i] = NULL; 3933 xmlXPathNodeSetFreeNs((xmlNsPtr) n2); 3934 goto skip_node; 3935 } 3936 } 3937 } 3938 /* 3939 * grow the nodeTab if needed 3940 */ 3941 if (set1->nodeMax == 0) { 3942 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 3943 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 3944 if (set1->nodeTab == NULL) { 3945 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3946 return(NULL); 3947 } 3948 memset(set1->nodeTab, 0, 3949 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 3950 set1->nodeMax = XML_NODESET_DEFAULT; 3951 } else if (set1->nodeNr >= set1->nodeMax) { 3952 xmlNodePtr *temp; 3953 3954 temp = (xmlNodePtr *) xmlRealloc( 3955 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 3956 if (temp == NULL) { 3957 xmlXPathErrMemory(NULL, "merging nodeset\n"); 3958 return(NULL); 3959 } 3960 set1->nodeTab = temp; 3961 set1->nodeMax *= 2; 3962 } 3963 if (n2->type == XML_NAMESPACE_DECL) { 3964 xmlNsPtr ns = (xmlNsPtr) n2; 3965 3966 set1->nodeTab[set1->nodeNr++] = 3967 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 3968 } else 3969 set1->nodeTab[set1->nodeNr++] = n2; 3970 skip_node: 3971 {} 3972 } 3973 } 3974 set2->nodeNr = 0; 3975 return(set1); 3976 } 3977 3978 /** 3979 * xmlXPathNodeSetMergeAndClearNoDupls: 3980 * @set1: the first NodeSet or NULL 3981 * @set2: the second NodeSet 3982 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes 3983 * 3984 * Merges two nodesets, all nodes from @set2 are added to @set1 3985 * if @set1 is NULL, a new set is created and copied from @set2. 3986 * Doesn't chack for duplicate nodes. Clears set2. 3987 * 3988 * Returns @set1 once extended or NULL in case of error. 3989 */ 3990 static xmlNodeSetPtr 3991 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, 3992 int hasNullEntries) 3993 { 3994 if (set2 == NULL) 3995 return(set1); 3996 if ((set1 == NULL) && (hasNullEntries == 0)) { 3997 /* 3998 * Note that doing a memcpy of the list, namespace nodes are 3999 * just assigned to set1, since set2 is cleared anyway. 4000 */ 4001 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); 4002 if (set1 == NULL) 4003 return(NULL); 4004 if (set2->nodeNr != 0) { 4005 memcpy(set1->nodeTab, set2->nodeTab, 4006 set2->nodeNr * sizeof(xmlNodePtr)); 4007 set1->nodeNr = set2->nodeNr; 4008 } 4009 } else { 4010 int i; 4011 xmlNodePtr n2; 4012 4013 if (set1 == NULL) 4014 set1 = xmlXPathNodeSetCreate(NULL); 4015 if (set1 == NULL) 4016 return (NULL); 4017 4018 for (i = 0;i < set2->nodeNr;i++) { 4019 n2 = set2->nodeTab[i]; 4020 /* 4021 * Skip NULLed entries. 4022 */ 4023 if (n2 == NULL) 4024 continue; 4025 if (set1->nodeMax == 0) { 4026 set1->nodeTab = (xmlNodePtr *) xmlMalloc( 4027 XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); 4028 if (set1->nodeTab == NULL) { 4029 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4030 return(NULL); 4031 } 4032 memset(set1->nodeTab, 0, 4033 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 4034 set1->nodeMax = XML_NODESET_DEFAULT; 4035 } else if (set1->nodeNr >= set1->nodeMax) { 4036 xmlNodePtr *temp; 4037 4038 temp = (xmlNodePtr *) xmlRealloc( 4039 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); 4040 if (temp == NULL) { 4041 xmlXPathErrMemory(NULL, "merging nodeset\n"); 4042 return(NULL); 4043 } 4044 set1->nodeTab = temp; 4045 set1->nodeMax *= 2; 4046 } 4047 set1->nodeTab[set1->nodeNr++] = n2; 4048 } 4049 } 4050 set2->nodeNr = 0; 4051 return(set1); 4052 } 4053 4054 /** 4055 * xmlXPathNodeSetDel: 4056 * @cur: the initial node set 4057 * @val: an xmlNodePtr 4058 * 4059 * Removes an xmlNodePtr from an existing NodeSet 4060 */ 4061 void 4062 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 4063 int i; 4064 4065 if (cur == NULL) return; 4066 if (val == NULL) return; 4067 4068 /* 4069 * find node in nodeTab 4070 */ 4071 for (i = 0;i < cur->nodeNr;i++) 4072 if (cur->nodeTab[i] == val) break; 4073 4074 if (i >= cur->nodeNr) { /* not found */ 4075 #ifdef DEBUG 4076 xmlGenericError(xmlGenericErrorContext, 4077 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 4078 val->name); 4079 #endif 4080 return; 4081 } 4082 if ((cur->nodeTab[i] != NULL) && 4083 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4084 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 4085 cur->nodeNr--; 4086 for (;i < cur->nodeNr;i++) 4087 cur->nodeTab[i] = cur->nodeTab[i + 1]; 4088 cur->nodeTab[cur->nodeNr] = NULL; 4089 } 4090 4091 /** 4092 * xmlXPathNodeSetRemove: 4093 * @cur: the initial node set 4094 * @val: the index to remove 4095 * 4096 * Removes an entry from an existing NodeSet list. 4097 */ 4098 void 4099 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 4100 if (cur == NULL) return; 4101 if (val >= cur->nodeNr) return; 4102 if ((cur->nodeTab[val] != NULL) && 4103 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 4104 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 4105 cur->nodeNr--; 4106 for (;val < cur->nodeNr;val++) 4107 cur->nodeTab[val] = cur->nodeTab[val + 1]; 4108 cur->nodeTab[cur->nodeNr] = NULL; 4109 } 4110 4111 /** 4112 * xmlXPathFreeNodeSet: 4113 * @obj: the xmlNodeSetPtr to free 4114 * 4115 * Free the NodeSet compound (not the actual nodes !). 4116 */ 4117 void 4118 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 4119 if (obj == NULL) return; 4120 if (obj->nodeTab != NULL) { 4121 int i; 4122 4123 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4124 for (i = 0;i < obj->nodeNr;i++) 4125 if ((obj->nodeTab[i] != NULL) && 4126 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 4127 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4128 xmlFree(obj->nodeTab); 4129 } 4130 xmlFree(obj); 4131 } 4132 4133 /** 4134 * xmlXPathNodeSetClear: 4135 * @set: the node set to clear 4136 * 4137 * Clears the list from all temporary XPath objects (e.g. namespace nodes 4138 * are feed), but does *not* free the list itself. Sets the length of the 4139 * list to 0. 4140 */ 4141 static void 4142 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) 4143 { 4144 if ((set == NULL) || (set->nodeNr <= 0)) 4145 return; 4146 else if (hasNsNodes) { 4147 int i; 4148 xmlNodePtr node; 4149 4150 for (i = 0; i < set->nodeNr; i++) { 4151 node = set->nodeTab[i]; 4152 if ((node != NULL) && 4153 (node->type == XML_NAMESPACE_DECL)) 4154 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4155 } 4156 } 4157 set->nodeNr = 0; 4158 } 4159 4160 /** 4161 * xmlXPathNodeSetClearFromPos: 4162 * @set: the node set to be cleared 4163 * @pos: the start position to clear from 4164 * 4165 * Clears the list from temporary XPath objects (e.g. namespace nodes 4166 * are feed) starting with the entry at @pos, but does *not* free the list 4167 * itself. Sets the length of the list to @pos. 4168 */ 4169 static void 4170 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) 4171 { 4172 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr)) 4173 return; 4174 else if ((hasNsNodes)) { 4175 int i; 4176 xmlNodePtr node; 4177 4178 for (i = pos; i < set->nodeNr; i++) { 4179 node = set->nodeTab[i]; 4180 if ((node != NULL) && 4181 (node->type == XML_NAMESPACE_DECL)) 4182 xmlXPathNodeSetFreeNs((xmlNsPtr) node); 4183 } 4184 } 4185 set->nodeNr = pos; 4186 } 4187 4188 /** 4189 * xmlXPathFreeValueTree: 4190 * @obj: the xmlNodeSetPtr to free 4191 * 4192 * Free the NodeSet compound and the actual tree, this is different 4193 * from xmlXPathFreeNodeSet() 4194 */ 4195 static void 4196 xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 4197 int i; 4198 4199 if (obj == NULL) return; 4200 4201 if (obj->nodeTab != NULL) { 4202 for (i = 0;i < obj->nodeNr;i++) { 4203 if (obj->nodeTab[i] != NULL) { 4204 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 4205 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 4206 } else { 4207 xmlFreeNodeList(obj->nodeTab[i]); 4208 } 4209 } 4210 } 4211 xmlFree(obj->nodeTab); 4212 } 4213 xmlFree(obj); 4214 } 4215 4216 #if defined(DEBUG) || defined(DEBUG_STEP) 4217 /** 4218 * xmlGenericErrorContextNodeSet: 4219 * @output: a FILE * for the output 4220 * @obj: the xmlNodeSetPtr to display 4221 * 4222 * Quick display of a NodeSet 4223 */ 4224 void 4225 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 4226 int i; 4227 4228 if (output == NULL) output = xmlGenericErrorContext; 4229 if (obj == NULL) { 4230 fprintf(output, "NodeSet == NULL !\n"); 4231 return; 4232 } 4233 if (obj->nodeNr == 0) { 4234 fprintf(output, "NodeSet is empty\n"); 4235 return; 4236 } 4237 if (obj->nodeTab == NULL) { 4238 fprintf(output, " nodeTab == NULL !\n"); 4239 return; 4240 } 4241 for (i = 0; i < obj->nodeNr; i++) { 4242 if (obj->nodeTab[i] == NULL) { 4243 fprintf(output, " NULL !\n"); 4244 return; 4245 } 4246 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 4247 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 4248 fprintf(output, " /"); 4249 else if (obj->nodeTab[i]->name == NULL) 4250 fprintf(output, " noname!"); 4251 else fprintf(output, " %s", obj->nodeTab[i]->name); 4252 } 4253 fprintf(output, "\n"); 4254 } 4255 #endif 4256 4257 /** 4258 * xmlXPathNewNodeSet: 4259 * @val: the NodePtr value 4260 * 4261 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4262 * it with the single Node @val 4263 * 4264 * Returns the newly created object. 4265 */ 4266 xmlXPathObjectPtr 4267 xmlXPathNewNodeSet(xmlNodePtr val) { 4268 xmlXPathObjectPtr ret; 4269 4270 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4271 if (ret == NULL) { 4272 xmlXPathErrMemory(NULL, "creating nodeset\n"); 4273 return(NULL); 4274 } 4275 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4276 ret->type = XPATH_NODESET; 4277 ret->boolval = 0; 4278 ret->nodesetval = xmlXPathNodeSetCreate(val); 4279 /* @@ with_ns to check whether namespace nodes should be looked at @@ */ 4280 #ifdef XP_DEBUG_OBJ_USAGE 4281 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4282 #endif 4283 return(ret); 4284 } 4285 4286 /** 4287 * xmlXPathNewValueTree: 4288 * @val: the NodePtr value 4289 * 4290 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 4291 * it with the tree root @val 4292 * 4293 * Returns the newly created object. 4294 */ 4295 xmlXPathObjectPtr 4296 xmlXPathNewValueTree(xmlNodePtr val) { 4297 xmlXPathObjectPtr ret; 4298 4299 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4300 if (ret == NULL) { 4301 xmlXPathErrMemory(NULL, "creating result value tree\n"); 4302 return(NULL); 4303 } 4304 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4305 ret->type = XPATH_XSLT_TREE; 4306 ret->boolval = 1; 4307 ret->user = (void *) val; 4308 ret->nodesetval = xmlXPathNodeSetCreate(val); 4309 #ifdef XP_DEBUG_OBJ_USAGE 4310 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); 4311 #endif 4312 return(ret); 4313 } 4314 4315 /** 4316 * xmlXPathNewNodeSetList: 4317 * @val: an existing NodeSet 4318 * 4319 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 4320 * it with the Nodeset @val 4321 * 4322 * Returns the newly created object. 4323 */ 4324 xmlXPathObjectPtr 4325 xmlXPathNewNodeSetList(xmlNodeSetPtr val) 4326 { 4327 xmlXPathObjectPtr ret; 4328 int i; 4329 4330 if (val == NULL) 4331 ret = NULL; 4332 else if (val->nodeTab == NULL) 4333 ret = xmlXPathNewNodeSet(NULL); 4334 else { 4335 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 4336 if (ret) 4337 for (i = 1; i < val->nodeNr; ++i) 4338 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]); 4339 } 4340 4341 return (ret); 4342 } 4343 4344 /** 4345 * xmlXPathWrapNodeSet: 4346 * @val: the NodePtr value 4347 * 4348 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 4349 * 4350 * Returns the newly created object. 4351 */ 4352 xmlXPathObjectPtr 4353 xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 4354 xmlXPathObjectPtr ret; 4355 4356 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 4357 if (ret == NULL) { 4358 xmlXPathErrMemory(NULL, "creating node set object\n"); 4359 return(NULL); 4360 } 4361 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 4362 ret->type = XPATH_NODESET; 4363 ret->nodesetval = val; 4364 #ifdef XP_DEBUG_OBJ_USAGE 4365 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); 4366 #endif 4367 return(ret); 4368 } 4369 4370 /** 4371 * xmlXPathFreeNodeSetList: 4372 * @obj: an existing NodeSetList object 4373 * 4374 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 4375 * the list contrary to xmlXPathFreeObject(). 4376 */ 4377 void 4378 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 4379 if (obj == NULL) return; 4380 #ifdef XP_DEBUG_OBJ_USAGE 4381 xmlXPathDebugObjUsageReleased(NULL, obj->type); 4382 #endif 4383 xmlFree(obj); 4384 } 4385 4386 /** 4387 * xmlXPathDifference: 4388 * @nodes1: a node-set 4389 * @nodes2: a node-set 4390 * 4391 * Implements the EXSLT - Sets difference() function: 4392 * node-set set:difference (node-set, node-set) 4393 * 4394 * Returns the difference between the two node sets, or nodes1 if 4395 * nodes2 is empty 4396 */ 4397 xmlNodeSetPtr 4398 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4399 xmlNodeSetPtr ret; 4400 int i, l1; 4401 xmlNodePtr cur; 4402 4403 if (xmlXPathNodeSetIsEmpty(nodes2)) 4404 return(nodes1); 4405 4406 ret = xmlXPathNodeSetCreate(NULL); 4407 if (xmlXPathNodeSetIsEmpty(nodes1)) 4408 return(ret); 4409 4410 l1 = xmlXPathNodeSetGetLength(nodes1); 4411 4412 for (i = 0; i < l1; i++) { 4413 cur = xmlXPathNodeSetItem(nodes1, i); 4414 if (!xmlXPathNodeSetContains(nodes2, cur)) 4415 xmlXPathNodeSetAddUnique(ret, cur); 4416 } 4417 return(ret); 4418 } 4419 4420 /** 4421 * xmlXPathIntersection: 4422 * @nodes1: a node-set 4423 * @nodes2: a node-set 4424 * 4425 * Implements the EXSLT - Sets intersection() function: 4426 * node-set set:intersection (node-set, node-set) 4427 * 4428 * Returns a node set comprising the nodes that are within both the 4429 * node sets passed as arguments 4430 */ 4431 xmlNodeSetPtr 4432 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4433 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 4434 int i, l1; 4435 xmlNodePtr cur; 4436 4437 if (ret == NULL) 4438 return(ret); 4439 if (xmlXPathNodeSetIsEmpty(nodes1)) 4440 return(ret); 4441 if (xmlXPathNodeSetIsEmpty(nodes2)) 4442 return(ret); 4443 4444 l1 = xmlXPathNodeSetGetLength(nodes1); 4445 4446 for (i = 0; i < l1; i++) { 4447 cur = xmlXPathNodeSetItem(nodes1, i); 4448 if (xmlXPathNodeSetContains(nodes2, cur)) 4449 xmlXPathNodeSetAddUnique(ret, cur); 4450 } 4451 return(ret); 4452 } 4453 4454 /** 4455 * xmlXPathDistinctSorted: 4456 * @nodes: a node-set, sorted by document order 4457 * 4458 * Implements the EXSLT - Sets distinct() function: 4459 * node-set set:distinct (node-set) 4460 * 4461 * Returns a subset of the nodes contained in @nodes, or @nodes if 4462 * it is empty 4463 */ 4464 xmlNodeSetPtr 4465 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 4466 xmlNodeSetPtr ret; 4467 xmlHashTablePtr hash; 4468 int i, l; 4469 xmlChar * strval; 4470 xmlNodePtr cur; 4471 4472 if (xmlXPathNodeSetIsEmpty(nodes)) 4473 return(nodes); 4474 4475 ret = xmlXPathNodeSetCreate(NULL); 4476 if (ret == NULL) 4477 return(ret); 4478 l = xmlXPathNodeSetGetLength(nodes); 4479 hash = xmlHashCreate (l); 4480 for (i = 0; i < l; i++) { 4481 cur = xmlXPathNodeSetItem(nodes, i); 4482 strval = xmlXPathCastNodeToString(cur); 4483 if (xmlHashLookup(hash, strval) == NULL) { 4484 xmlHashAddEntry(hash, strval, strval); 4485 xmlXPathNodeSetAddUnique(ret, cur); 4486 } else { 4487 xmlFree(strval); 4488 } 4489 } 4490 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 4491 return(ret); 4492 } 4493 4494 /** 4495 * xmlXPathDistinct: 4496 * @nodes: a node-set 4497 * 4498 * Implements the EXSLT - Sets distinct() function: 4499 * node-set set:distinct (node-set) 4500 * @nodes is sorted by document order, then #exslSetsDistinctSorted 4501 * is called with the sorted node-set 4502 * 4503 * Returns a subset of the nodes contained in @nodes, or @nodes if 4504 * it is empty 4505 */ 4506 xmlNodeSetPtr 4507 xmlXPathDistinct (xmlNodeSetPtr nodes) { 4508 if (xmlXPathNodeSetIsEmpty(nodes)) 4509 return(nodes); 4510 4511 xmlXPathNodeSetSort(nodes); 4512 return(xmlXPathDistinctSorted(nodes)); 4513 } 4514 4515 /** 4516 * xmlXPathHasSameNodes: 4517 * @nodes1: a node-set 4518 * @nodes2: a node-set 4519 * 4520 * Implements the EXSLT - Sets has-same-nodes function: 4521 * boolean set:has-same-node(node-set, node-set) 4522 * 4523 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 4524 * otherwise 4525 */ 4526 int 4527 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4528 int i, l; 4529 xmlNodePtr cur; 4530 4531 if (xmlXPathNodeSetIsEmpty(nodes1) || 4532 xmlXPathNodeSetIsEmpty(nodes2)) 4533 return(0); 4534 4535 l = xmlXPathNodeSetGetLength(nodes1); 4536 for (i = 0; i < l; i++) { 4537 cur = xmlXPathNodeSetItem(nodes1, i); 4538 if (xmlXPathNodeSetContains(nodes2, cur)) 4539 return(1); 4540 } 4541 return(0); 4542 } 4543 4544 /** 4545 * xmlXPathNodeLeadingSorted: 4546 * @nodes: a node-set, sorted by document order 4547 * @node: a node 4548 * 4549 * Implements the EXSLT - Sets leading() function: 4550 * node-set set:leading (node-set, node-set) 4551 * 4552 * Returns the nodes in @nodes that precede @node in document order, 4553 * @nodes if @node is NULL or an empty node-set if @nodes 4554 * doesn't contain @node 4555 */ 4556 xmlNodeSetPtr 4557 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4558 int i, l; 4559 xmlNodePtr cur; 4560 xmlNodeSetPtr ret; 4561 4562 if (node == NULL) 4563 return(nodes); 4564 4565 ret = xmlXPathNodeSetCreate(NULL); 4566 if (ret == NULL) 4567 return(ret); 4568 if (xmlXPathNodeSetIsEmpty(nodes) || 4569 (!xmlXPathNodeSetContains(nodes, node))) 4570 return(ret); 4571 4572 l = xmlXPathNodeSetGetLength(nodes); 4573 for (i = 0; i < l; i++) { 4574 cur = xmlXPathNodeSetItem(nodes, i); 4575 if (cur == node) 4576 break; 4577 xmlXPathNodeSetAddUnique(ret, cur); 4578 } 4579 return(ret); 4580 } 4581 4582 /** 4583 * xmlXPathNodeLeading: 4584 * @nodes: a node-set 4585 * @node: a node 4586 * 4587 * Implements the EXSLT - Sets leading() function: 4588 * node-set set:leading (node-set, node-set) 4589 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 4590 * is called. 4591 * 4592 * Returns the nodes in @nodes that precede @node in document order, 4593 * @nodes if @node is NULL or an empty node-set if @nodes 4594 * doesn't contain @node 4595 */ 4596 xmlNodeSetPtr 4597 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 4598 xmlXPathNodeSetSort(nodes); 4599 return(xmlXPathNodeLeadingSorted(nodes, node)); 4600 } 4601 4602 /** 4603 * xmlXPathLeadingSorted: 4604 * @nodes1: a node-set, sorted by document order 4605 * @nodes2: a node-set, sorted by document order 4606 * 4607 * Implements the EXSLT - Sets leading() function: 4608 * node-set set:leading (node-set, node-set) 4609 * 4610 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4611 * in document order, @nodes1 if @nodes2 is NULL or empty or 4612 * an empty node-set if @nodes1 doesn't contain @nodes2 4613 */ 4614 xmlNodeSetPtr 4615 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4616 if (xmlXPathNodeSetIsEmpty(nodes2)) 4617 return(nodes1); 4618 return(xmlXPathNodeLeadingSorted(nodes1, 4619 xmlXPathNodeSetItem(nodes2, 1))); 4620 } 4621 4622 /** 4623 * xmlXPathLeading: 4624 * @nodes1: a node-set 4625 * @nodes2: a node-set 4626 * 4627 * Implements the EXSLT - Sets leading() function: 4628 * node-set set:leading (node-set, node-set) 4629 * @nodes1 and @nodes2 are sorted by document order, then 4630 * #exslSetsLeadingSorted is called. 4631 * 4632 * Returns the nodes in @nodes1 that precede the first node in @nodes2 4633 * in document order, @nodes1 if @nodes2 is NULL or empty or 4634 * an empty node-set if @nodes1 doesn't contain @nodes2 4635 */ 4636 xmlNodeSetPtr 4637 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4638 if (xmlXPathNodeSetIsEmpty(nodes2)) 4639 return(nodes1); 4640 if (xmlXPathNodeSetIsEmpty(nodes1)) 4641 return(xmlXPathNodeSetCreate(NULL)); 4642 xmlXPathNodeSetSort(nodes1); 4643 xmlXPathNodeSetSort(nodes2); 4644 return(xmlXPathNodeLeadingSorted(nodes1, 4645 xmlXPathNodeSetItem(nodes2, 1))); 4646 } 4647 4648 /** 4649 * xmlXPathNodeTrailingSorted: 4650 * @nodes: a node-set, sorted by document order 4651 * @node: a node 4652 * 4653 * Implements the EXSLT - Sets trailing() function: 4654 * node-set set:trailing (node-set, node-set) 4655 * 4656 * Returns the nodes in @nodes that follow @node in document order, 4657 * @nodes if @node is NULL or an empty node-set if @nodes 4658 * doesn't contain @node 4659 */ 4660 xmlNodeSetPtr 4661 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 4662 int i, l; 4663 xmlNodePtr cur; 4664 xmlNodeSetPtr ret; 4665 4666 if (node == NULL) 4667 return(nodes); 4668 4669 ret = xmlXPathNodeSetCreate(NULL); 4670 if (ret == NULL) 4671 return(ret); 4672 if (xmlXPathNodeSetIsEmpty(nodes) || 4673 (!xmlXPathNodeSetContains(nodes, node))) 4674 return(ret); 4675 4676 l = xmlXPathNodeSetGetLength(nodes); 4677 for (i = l - 1; i >= 0; i--) { 4678 cur = xmlXPathNodeSetItem(nodes, i); 4679 if (cur == node) 4680 break; 4681 xmlXPathNodeSetAddUnique(ret, cur); 4682 } 4683 xmlXPathNodeSetSort(ret); /* bug 413451 */ 4684 return(ret); 4685 } 4686 4687 /** 4688 * xmlXPathNodeTrailing: 4689 * @nodes: a node-set 4690 * @node: a node 4691 * 4692 * Implements the EXSLT - Sets trailing() function: 4693 * node-set set:trailing (node-set, node-set) 4694 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 4695 * is called. 4696 * 4697 * Returns the nodes in @nodes that follow @node in document order, 4698 * @nodes if @node is NULL or an empty node-set if @nodes 4699 * doesn't contain @node 4700 */ 4701 xmlNodeSetPtr 4702 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 4703 xmlXPathNodeSetSort(nodes); 4704 return(xmlXPathNodeTrailingSorted(nodes, node)); 4705 } 4706 4707 /** 4708 * xmlXPathTrailingSorted: 4709 * @nodes1: a node-set, sorted by document order 4710 * @nodes2: a node-set, sorted by document order 4711 * 4712 * Implements the EXSLT - Sets trailing() function: 4713 * node-set set:trailing (node-set, node-set) 4714 * 4715 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4716 * in document order, @nodes1 if @nodes2 is NULL or empty or 4717 * an empty node-set if @nodes1 doesn't contain @nodes2 4718 */ 4719 xmlNodeSetPtr 4720 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4721 if (xmlXPathNodeSetIsEmpty(nodes2)) 4722 return(nodes1); 4723 return(xmlXPathNodeTrailingSorted(nodes1, 4724 xmlXPathNodeSetItem(nodes2, 0))); 4725 } 4726 4727 /** 4728 * xmlXPathTrailing: 4729 * @nodes1: a node-set 4730 * @nodes2: a node-set 4731 * 4732 * Implements the EXSLT - Sets trailing() function: 4733 * node-set set:trailing (node-set, node-set) 4734 * @nodes1 and @nodes2 are sorted by document order, then 4735 * #xmlXPathTrailingSorted is called. 4736 * 4737 * Returns the nodes in @nodes1 that follow the first node in @nodes2 4738 * in document order, @nodes1 if @nodes2 is NULL or empty or 4739 * an empty node-set if @nodes1 doesn't contain @nodes2 4740 */ 4741 xmlNodeSetPtr 4742 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 4743 if (xmlXPathNodeSetIsEmpty(nodes2)) 4744 return(nodes1); 4745 if (xmlXPathNodeSetIsEmpty(nodes1)) 4746 return(xmlXPathNodeSetCreate(NULL)); 4747 xmlXPathNodeSetSort(nodes1); 4748 xmlXPathNodeSetSort(nodes2); 4749 return(xmlXPathNodeTrailingSorted(nodes1, 4750 xmlXPathNodeSetItem(nodes2, 0))); 4751 } 4752 4753 /************************************************************************ 4754 * * 4755 * Routines to handle extra functions * 4756 * * 4757 ************************************************************************/ 4758 4759 /** 4760 * xmlXPathRegisterFunc: 4761 * @ctxt: the XPath context 4762 * @name: the function name 4763 * @f: the function implementation or NULL 4764 * 4765 * Register a new function. If @f is NULL it unregisters the function 4766 * 4767 * Returns 0 in case of success, -1 in case of error 4768 */ 4769 int 4770 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 4771 xmlXPathFunction f) { 4772 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 4773 } 4774 4775 /** 4776 * xmlXPathRegisterFuncNS: 4777 * @ctxt: the XPath context 4778 * @name: the function name 4779 * @ns_uri: the function namespace URI 4780 * @f: the function implementation or NULL 4781 * 4782 * Register a new function. If @f is NULL it unregisters the function 4783 * 4784 * Returns 0 in case of success, -1 in case of error 4785 */ 4786 int 4787 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4788 const xmlChar *ns_uri, xmlXPathFunction f) { 4789 if (ctxt == NULL) 4790 return(-1); 4791 if (name == NULL) 4792 return(-1); 4793 4794 if (ctxt->funcHash == NULL) 4795 ctxt->funcHash = xmlHashCreate(0); 4796 if (ctxt->funcHash == NULL) 4797 return(-1); 4798 if (f == NULL) 4799 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); 4800 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f))); 4801 } 4802 4803 /** 4804 * xmlXPathRegisterFuncLookup: 4805 * @ctxt: the XPath context 4806 * @f: the lookup function 4807 * @funcCtxt: the lookup data 4808 * 4809 * Registers an external mechanism to do function lookup. 4810 */ 4811 void 4812 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 4813 xmlXPathFuncLookupFunc f, 4814 void *funcCtxt) { 4815 if (ctxt == NULL) 4816 return; 4817 ctxt->funcLookupFunc = f; 4818 ctxt->funcLookupData = funcCtxt; 4819 } 4820 4821 /** 4822 * xmlXPathFunctionLookup: 4823 * @ctxt: the XPath context 4824 * @name: the function name 4825 * 4826 * Search in the Function array of the context for the given 4827 * function. 4828 * 4829 * Returns the xmlXPathFunction or NULL if not found 4830 */ 4831 xmlXPathFunction 4832 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4833 if (ctxt == NULL) 4834 return (NULL); 4835 4836 if (ctxt->funcLookupFunc != NULL) { 4837 xmlXPathFunction ret; 4838 xmlXPathFuncLookupFunc f; 4839 4840 f = ctxt->funcLookupFunc; 4841 ret = f(ctxt->funcLookupData, name, NULL); 4842 if (ret != NULL) 4843 return(ret); 4844 } 4845 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 4846 } 4847 4848 /** 4849 * xmlXPathFunctionLookupNS: 4850 * @ctxt: the XPath context 4851 * @name: the function name 4852 * @ns_uri: the function namespace URI 4853 * 4854 * Search in the Function array of the context for the given 4855 * function. 4856 * 4857 * Returns the xmlXPathFunction or NULL if not found 4858 */ 4859 xmlXPathFunction 4860 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4861 const xmlChar *ns_uri) { 4862 xmlXPathFunction ret; 4863 4864 if (ctxt == NULL) 4865 return(NULL); 4866 if (name == NULL) 4867 return(NULL); 4868 4869 if (ctxt->funcLookupFunc != NULL) { 4870 xmlXPathFuncLookupFunc f; 4871 4872 f = ctxt->funcLookupFunc; 4873 ret = f(ctxt->funcLookupData, name, ns_uri); 4874 if (ret != NULL) 4875 return(ret); 4876 } 4877 4878 if (ctxt->funcHash == NULL) 4879 return(NULL); 4880 4881 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); 4882 return(ret); 4883 } 4884 4885 /** 4886 * xmlXPathRegisteredFuncsCleanup: 4887 * @ctxt: the XPath context 4888 * 4889 * Cleanup the XPath context data associated to registered functions 4890 */ 4891 void 4892 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 4893 if (ctxt == NULL) 4894 return; 4895 4896 xmlHashFree(ctxt->funcHash, NULL); 4897 ctxt->funcHash = NULL; 4898 } 4899 4900 /************************************************************************ 4901 * * 4902 * Routines to handle Variables * 4903 * * 4904 ************************************************************************/ 4905 4906 /** 4907 * xmlXPathRegisterVariable: 4908 * @ctxt: the XPath context 4909 * @name: the variable name 4910 * @value: the variable value or NULL 4911 * 4912 * Register a new variable value. If @value is NULL it unregisters 4913 * the variable 4914 * 4915 * Returns 0 in case of success, -1 in case of error 4916 */ 4917 int 4918 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 4919 xmlXPathObjectPtr value) { 4920 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 4921 } 4922 4923 /** 4924 * xmlXPathRegisterVariableNS: 4925 * @ctxt: the XPath context 4926 * @name: the variable name 4927 * @ns_uri: the variable namespace URI 4928 * @value: the variable value or NULL 4929 * 4930 * Register a new variable value. If @value is NULL it unregisters 4931 * the variable 4932 * 4933 * Returns 0 in case of success, -1 in case of error 4934 */ 4935 int 4936 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 4937 const xmlChar *ns_uri, 4938 xmlXPathObjectPtr value) { 4939 if (ctxt == NULL) 4940 return(-1); 4941 if (name == NULL) 4942 return(-1); 4943 4944 if (ctxt->varHash == NULL) 4945 ctxt->varHash = xmlHashCreate(0); 4946 if (ctxt->varHash == NULL) 4947 return(-1); 4948 if (value == NULL) 4949 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, 4950 (xmlHashDeallocator)xmlXPathFreeObject)); 4951 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 4952 (void *) value, 4953 (xmlHashDeallocator)xmlXPathFreeObject)); 4954 } 4955 4956 /** 4957 * xmlXPathRegisterVariableLookup: 4958 * @ctxt: the XPath context 4959 * @f: the lookup function 4960 * @data: the lookup data 4961 * 4962 * register an external mechanism to do variable lookup 4963 */ 4964 void 4965 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 4966 xmlXPathVariableLookupFunc f, void *data) { 4967 if (ctxt == NULL) 4968 return; 4969 ctxt->varLookupFunc = f; 4970 ctxt->varLookupData = data; 4971 } 4972 4973 /** 4974 * xmlXPathVariableLookup: 4975 * @ctxt: the XPath context 4976 * @name: the variable name 4977 * 4978 * Search in the Variable array of the context for the given 4979 * variable value. 4980 * 4981 * Returns a copy of the value or NULL if not found 4982 */ 4983 xmlXPathObjectPtr 4984 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 4985 if (ctxt == NULL) 4986 return(NULL); 4987 4988 if (ctxt->varLookupFunc != NULL) { 4989 xmlXPathObjectPtr ret; 4990 4991 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 4992 (ctxt->varLookupData, name, NULL); 4993 return(ret); 4994 } 4995 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 4996 } 4997 4998 /** 4999 * xmlXPathVariableLookupNS: 5000 * @ctxt: the XPath context 5001 * @name: the variable name 5002 * @ns_uri: the variable namespace URI 5003 * 5004 * Search in the Variable array of the context for the given 5005 * variable value. 5006 * 5007 * Returns the a copy of the value or NULL if not found 5008 */ 5009 xmlXPathObjectPtr 5010 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 5011 const xmlChar *ns_uri) { 5012 if (ctxt == NULL) 5013 return(NULL); 5014 5015 if (ctxt->varLookupFunc != NULL) { 5016 xmlXPathObjectPtr ret; 5017 5018 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 5019 (ctxt->varLookupData, name, ns_uri); 5020 if (ret != NULL) return(ret); 5021 } 5022 5023 if (ctxt->varHash == NULL) 5024 return(NULL); 5025 if (name == NULL) 5026 return(NULL); 5027 5028 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) 5029 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 5030 } 5031 5032 /** 5033 * xmlXPathRegisteredVariablesCleanup: 5034 * @ctxt: the XPath context 5035 * 5036 * Cleanup the XPath context data associated to registered variables 5037 */ 5038 void 5039 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 5040 if (ctxt == NULL) 5041 return; 5042 5043 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 5044 ctxt->varHash = NULL; 5045 } 5046 5047 /** 5048 * xmlXPathRegisterNs: 5049 * @ctxt: the XPath context 5050 * @prefix: the namespace prefix cannot be NULL or empty string 5051 * @ns_uri: the namespace name 5052 * 5053 * Register a new namespace. If @ns_uri is NULL it unregisters 5054 * the namespace 5055 * 5056 * Returns 0 in case of success, -1 in case of error 5057 */ 5058 int 5059 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 5060 const xmlChar *ns_uri) { 5061 if (ctxt == NULL) 5062 return(-1); 5063 if (prefix == NULL) 5064 return(-1); 5065 if (prefix[0] == 0) 5066 return(-1); 5067 5068 if (ctxt->nsHash == NULL) 5069 ctxt->nsHash = xmlHashCreate(10); 5070 if (ctxt->nsHash == NULL) 5071 return(-1); 5072 if (ns_uri == NULL) 5073 return(xmlHashRemoveEntry(ctxt->nsHash, prefix, 5074