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