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