VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/xpath.c

Last change on this file was 104180, checked in by vboxsync, 6 weeks ago

libxml2-2.12.6: Make it build for windows. bugref:10640

  • Property svn:eol-style set to native
File size: 375.1 KB
Line 
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/* To avoid EBCDIC trouble when parsing on zOS */
18#if defined(__MVS__)
19#pragma convert("ISO8859-1")
20#endif
21
22#define IN_LIBXML
23#include "libxml.h"
24
25#include <limits.h>
26#include <string.h>
27#include <stddef.h>
28#include <math.h>
29#include <float.h>
30#include <ctype.h>
31
32#include <libxml/xmlmemory.h>
33#include <libxml/tree.h>
34#include <libxml/xpath.h>
35#include <libxml/xpathInternals.h>
36#include <libxml/parserInternals.h>
37#include <libxml/hash.h>
38#ifdef LIBXML_XPTR_LOCS_ENABLED
39#include <libxml/xpointer.h>
40#endif
41#ifdef LIBXML_DEBUG_ENABLED
42#include <libxml/debugXML.h>
43#endif
44#include <libxml/xmlerror.h>
45#include <libxml/threads.h>
46#ifdef LIBXML_PATTERN_ENABLED
47#include <libxml/pattern.h>
48#endif
49
50#include "private/buf.h"
51#include "private/error.h"
52#include "private/xpath.h"
53
54#ifdef LIBXML_PATTERN_ENABLED
55#define XPATH_STREAMING
56#endif
57
58#define TODO \
59 xmlGenericError(xmlGenericErrorContext, \
60 "Unimplemented block at %s:%d\n", \
61 __FILE__, __LINE__);
62
63/**
64 * WITH_TIM_SORT:
65 *
66 * Use the Timsort algorithm provided in timsort.h to sort
67 * nodeset as this is a great improvement over the old Shell sort
68 * used in xmlXPathNodeSetSort()
69 */
70#define WITH_TIM_SORT
71
72/*
73* XP_OPTIMIZED_NON_ELEM_COMPARISON:
74* If defined, this will use xmlXPathCmpNodesExt() instead of
75* xmlXPathCmpNodes(). The new function is optimized comparison of
76* non-element nodes; actually it will speed up comparison only if
77* xmlXPathOrderDocElems() was called in order to index the elements of
78* a tree in document order; Libxslt does such an indexing, thus it will
79* benefit from this optimization.
80*/
81#define XP_OPTIMIZED_NON_ELEM_COMPARISON
82
83/*
84* XP_OPTIMIZED_FILTER_FIRST:
85* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
86* in a way, that it stop evaluation at the first node.
87*/
88#define XP_OPTIMIZED_FILTER_FIRST
89
90/*
91 * XPATH_MAX_STEPS:
92 * when compiling an XPath expression we arbitrary limit the maximum
93 * number of step operation in the compiled expression. 1000000 is
94 * an insanely large value which should never be reached under normal
95 * circumstances
96 */
97#define XPATH_MAX_STEPS 1000000
98
99/*
100 * XPATH_MAX_STACK_DEPTH:
101 * when evaluating an XPath expression we arbitrary limit the maximum
102 * number of object allowed to be pushed on the stack. 1000000 is
103 * an insanely large value which should never be reached under normal
104 * circumstances
105 */
106#define XPATH_MAX_STACK_DEPTH 1000000
107
108/*
109 * XPATH_MAX_NODESET_LENGTH:
110 * when evaluating an XPath expression nodesets are created and we
111 * arbitrary limit the maximum length of those node set. 10000000 is
112 * an insanely large value which should never be reached under normal
113 * circumstances, one would first need to construct an in memory tree
114 * with more than 10 millions nodes.
115 */
116#define XPATH_MAX_NODESET_LENGTH 10000000
117
118/*
119 * XPATH_MAX_RECRUSION_DEPTH:
120 * Maximum amount of nested functions calls when parsing or evaluating
121 * expressions
122 */
123#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
124#define XPATH_MAX_RECURSION_DEPTH 500
125#elif defined(_WIN32)
126/* Windows typically limits stack size to 1MB. */
127#define XPATH_MAX_RECURSION_DEPTH 1000
128#else
129#define XPATH_MAX_RECURSION_DEPTH 5000
130#endif
131
132/*
133 * TODO:
134 * There are a few spots where some tests are done which depend upon ascii
135 * data. These should be enhanced for full UTF8 support (see particularly
136 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
137 */
138
139#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
140
141/************************************************************************
142 * *
143 * Floating point stuff *
144 * *
145 ************************************************************************/
146
147double xmlXPathNAN = 0.0;
148double xmlXPathPINF = 0.0;
149double xmlXPathNINF = 0.0;
150
151/**
152 * xmlXPathInit:
153 *
154 * DEPRECATED: Alias for xmlInitParser.
155 */
156void
157xmlXPathInit(void) {
158 xmlInitParser();
159}
160
161/**
162 * xmlInitXPathInternal:
163 *
164 * Initialize the XPath environment
165 */
166ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
167void
168xmlInitXPathInternal(void) {
169#if defined(NAN) && defined(INFINITY) && !defined(VBOX)
170 xmlXPathNAN = NAN;
171 xmlXPathPINF = INFINITY;
172 xmlXPathNINF = -INFINITY;
173#else
174 /* MSVC doesn't allow division by zero in constant expressions. */
175 double zero = 0.0;
176 xmlXPathNAN = 0.0 / zero;
177 xmlXPathPINF = 1.0 / zero;
178 xmlXPathNINF = -xmlXPathPINF;
179#endif
180}
181
182/**
183 * xmlXPathIsNaN:
184 * @val: a double value
185 *
186 * Checks whether a double is a NaN.
187 *
188 * Returns 1 if the value is a NaN, 0 otherwise
189 */
190int
191xmlXPathIsNaN(double val) {
192#ifdef isnan
193 return isnan(val);
194#else
195 return !(val == val);
196#endif
197}
198
199/**
200 * xmlXPathIsInf:
201 * @val: a double value
202 *
203 * Checks whether a double is an infinity.
204 *
205 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
206 */
207int
208xmlXPathIsInf(double val) {
209#ifdef isinf
210 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
211#else
212 if (val >= xmlXPathPINF)
213 return 1;
214 if (val <= -xmlXPathPINF)
215 return -1;
216 return 0;
217#endif
218}
219
220#endif /* SCHEMAS or XPATH */
221
222#ifdef LIBXML_XPATH_ENABLED
223
224/*
225 * TODO: when compatibility allows remove all "fake node libxslt" strings
226 * the test should just be name[0] = ' '
227 */
228
229static xmlNs xmlXPathXMLNamespaceStruct = {
230 NULL,
231 XML_NAMESPACE_DECL,
232 XML_XML_NAMESPACE,
233 BAD_CAST "xml",
234 NULL,
235 NULL
236};
237static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
238#ifndef LIBXML_THREAD_ENABLED
239/*
240 * Optimizer is disabled only when threaded apps are detected while
241 * the library ain't compiled for thread safety.
242 */
243static int xmlXPathDisableOptimizer = 0;
244#endif
245
246static void
247xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
248
249#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
250/**
251 * xmlXPathCmpNodesExt:
252 * @node1: the first node
253 * @node2: the second node
254 *
255 * Compare two nodes w.r.t document order.
256 * This one is optimized for handling of non-element nodes.
257 *
258 * Returns -2 in case of error 1 if first point < second point, 0 if
259 * it's the same node, -1 otherwise
260 */
261static int
262xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
263 int depth1, depth2;
264 int misc = 0, precedence1 = 0, precedence2 = 0;
265 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
266 xmlNodePtr cur, root;
267 ptrdiff_t l1, l2;
268
269 if ((node1 == NULL) || (node2 == NULL))
270 return(-2);
271
272 if (node1 == node2)
273 return(0);
274
275 /*
276 * a couple of optimizations which will avoid computations in most cases
277 */
278 switch (node1->type) {
279 case XML_ELEMENT_NODE:
280 if (node2->type == XML_ELEMENT_NODE) {
281 if ((0 > (ptrdiff_t) node1->content) &&
282 (0 > (ptrdiff_t) node2->content) &&
283 (node1->doc == node2->doc))
284 {
285 l1 = -((ptrdiff_t) node1->content);
286 l2 = -((ptrdiff_t) node2->content);
287 if (l1 < l2)
288 return(1);
289 if (l1 > l2)
290 return(-1);
291 } else
292 goto turtle_comparison;
293 }
294 break;
295 case XML_ATTRIBUTE_NODE:
296 precedence1 = 1; /* element is owner */
297 miscNode1 = node1;
298 node1 = node1->parent;
299 misc = 1;
300 break;
301 case XML_TEXT_NODE:
302 case XML_CDATA_SECTION_NODE:
303 case XML_COMMENT_NODE:
304 case XML_PI_NODE: {
305 miscNode1 = node1;
306 /*
307 * Find nearest element node.
308 */
309 if (node1->prev != NULL) {
310 do {
311 node1 = node1->prev;
312 if (node1->type == XML_ELEMENT_NODE) {
313 precedence1 = 3; /* element in prev-sibl axis */
314 break;
315 }
316 if (node1->prev == NULL) {
317 precedence1 = 2; /* element is parent */
318 /*
319 * URGENT TODO: Are there any cases, where the
320 * parent of such a node is not an element node?
321 */
322 node1 = node1->parent;
323 break;
324 }
325 } while (1);
326 } else {
327 precedence1 = 2; /* element is parent */
328 node1 = node1->parent;
329 }
330 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
331 (0 <= (ptrdiff_t) node1->content)) {
332 /*
333 * Fallback for whatever case.
334 */
335 node1 = miscNode1;
336 precedence1 = 0;
337 } else
338 misc = 1;
339 }
340 break;
341 case XML_NAMESPACE_DECL:
342 /*
343 * TODO: why do we return 1 for namespace nodes?
344 */
345 return(1);
346 default:
347 break;
348 }
349 switch (node2->type) {
350 case XML_ELEMENT_NODE:
351 break;
352 case XML_ATTRIBUTE_NODE:
353 precedence2 = 1; /* element is owner */
354 miscNode2 = node2;
355 node2 = node2->parent;
356 misc = 1;
357 break;
358 case XML_TEXT_NODE:
359 case XML_CDATA_SECTION_NODE:
360 case XML_COMMENT_NODE:
361 case XML_PI_NODE: {
362 miscNode2 = node2;
363 if (node2->prev != NULL) {
364 do {
365 node2 = node2->prev;
366 if (node2->type == XML_ELEMENT_NODE) {
367 precedence2 = 3; /* element in prev-sibl axis */
368 break;
369 }
370 if (node2->prev == NULL) {
371 precedence2 = 2; /* element is parent */
372 node2 = node2->parent;
373 break;
374 }
375 } while (1);
376 } else {
377 precedence2 = 2; /* element is parent */
378 node2 = node2->parent;
379 }
380 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
381 (0 <= (ptrdiff_t) node2->content))
382 {
383 node2 = miscNode2;
384 precedence2 = 0;
385 } else
386 misc = 1;
387 }
388 break;
389 case XML_NAMESPACE_DECL:
390 return(1);
391 default:
392 break;
393 }
394 if (misc) {
395 if (node1 == node2) {
396 if (precedence1 == precedence2) {
397 /*
398 * The ugly case; but normally there aren't many
399 * adjacent non-element nodes around.
400 */
401 cur = miscNode2->prev;
402 while (cur != NULL) {
403 if (cur == miscNode1)
404 return(1);
405 if (cur->type == XML_ELEMENT_NODE)
406 return(-1);
407 cur = cur->prev;
408 }
409 return (-1);
410 } else {
411 /*
412 * Evaluate based on higher precedence wrt to the element.
413 * TODO: This assumes attributes are sorted before content.
414 * Is this 100% correct?
415 */
416 if (precedence1 < precedence2)
417 return(1);
418 else
419 return(-1);
420 }
421 }
422 /*
423 * Special case: One of the helper-elements is contained by the other.
424 * <foo>
425 * <node2>
426 * <node1>Text-1(precedence1 == 2)</node1>
427 * </node2>
428 * Text-6(precedence2 == 3)
429 * </foo>
430 */
431 if ((precedence2 == 3) && (precedence1 > 1)) {
432 cur = node1->parent;
433 while (cur) {
434 if (cur == node2)
435 return(1);
436 cur = cur->parent;
437 }
438 }
439 if ((precedence1 == 3) && (precedence2 > 1)) {
440 cur = node2->parent;
441 while (cur) {
442 if (cur == node1)
443 return(-1);
444 cur = cur->parent;
445 }
446 }
447 }
448
449 /*
450 * Speedup using document order if available.
451 */
452 if ((node1->type == XML_ELEMENT_NODE) &&
453 (node2->type == XML_ELEMENT_NODE) &&
454 (0 > (ptrdiff_t) node1->content) &&
455 (0 > (ptrdiff_t) node2->content) &&
456 (node1->doc == node2->doc)) {
457
458 l1 = -((ptrdiff_t) node1->content);
459 l2 = -((ptrdiff_t) node2->content);
460 if (l1 < l2)
461 return(1);
462 if (l1 > l2)
463 return(-1);
464 }
465
466turtle_comparison:
467
468 if (node1 == node2->prev)
469 return(1);
470 if (node1 == node2->next)
471 return(-1);
472 /*
473 * compute depth to root
474 */
475 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
476 if (cur->parent == node1)
477 return(1);
478 depth2++;
479 }
480 root = cur;
481 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
482 if (cur->parent == node2)
483 return(-1);
484 depth1++;
485 }
486 /*
487 * Distinct document (or distinct entities :-( ) case.
488 */
489 if (root != cur) {
490 return(-2);
491 }
492 /*
493 * get the nearest common ancestor.
494 */
495 while (depth1 > depth2) {
496 depth1--;
497 node1 = node1->parent;
498 }
499 while (depth2 > depth1) {
500 depth2--;
501 node2 = node2->parent;
502 }
503 while (node1->parent != node2->parent) {
504 node1 = node1->parent;
505 node2 = node2->parent;
506 /* should not happen but just in case ... */
507 if ((node1 == NULL) || (node2 == NULL))
508 return(-2);
509 }
510 /*
511 * Find who's first.
512 */
513 if (node1 == node2->prev)
514 return(1);
515 if (node1 == node2->next)
516 return(-1);
517 /*
518 * Speedup using document order if available.
519 */
520 if ((node1->type == XML_ELEMENT_NODE) &&
521 (node2->type == XML_ELEMENT_NODE) &&
522 (0 > (ptrdiff_t) node1->content) &&
523 (0 > (ptrdiff_t) node2->content) &&
524 (node1->doc == node2->doc)) {
525
526 l1 = -((ptrdiff_t) node1->content);
527 l2 = -((ptrdiff_t) node2->content);
528 if (l1 < l2)
529 return(1);
530 if (l1 > l2)
531 return(-1);
532 }
533
534 for (cur = node1->next;cur != NULL;cur = cur->next)
535 if (cur == node2)
536 return(1);
537 return(-1); /* assume there is no sibling list corruption */
538}
539#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
540
541/*
542 * Wrapper for the Timsort algorithm from timsort.h
543 */
544#ifdef WITH_TIM_SORT
545#define SORT_NAME libxml_domnode
546#define SORT_TYPE xmlNodePtr
547/**
548 * wrap_cmp:
549 * @x: a node
550 * @y: another node
551 *
552 * Comparison function for the Timsort implementation
553 *
554 * Returns -2 in case of error -1 if first point < second point, 0 if
555 * it's the same node, +1 otherwise
556 */
557static
558int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
559#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
560 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
561 {
562 int res = xmlXPathCmpNodesExt(x, y);
563 return res == -2 ? res : -res;
564 }
565#else
566 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
567 {
568 int res = xmlXPathCmpNodes(x, y);
569 return res == -2 ? res : -res;
570 }
571#endif
572#define SORT_CMP(x, y) (wrap_cmp(x, y))
573#include "timsort.h"
574#endif /* WITH_TIM_SORT */
575
576/************************************************************************
577 * *
578 * Error handling routines *
579 * *
580 ************************************************************************/
581
582/**
583 * XP_ERRORNULL:
584 * @X: the error code
585 *
586 * Macro to raise an XPath error and return NULL.
587 */
588#define XP_ERRORNULL(X) \
589 { xmlXPathErr(ctxt, X); return(NULL); }
590
591/*
592 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
593 */
594static const char* const xmlXPathErrorMessages[] = {
595 "Ok\n",
596 "Number encoding\n",
597 "Unfinished literal\n",
598 "Start of literal\n",
599 "Expected $ for variable reference\n",
600 "Undefined variable\n",
601 "Invalid predicate\n",
602 "Invalid expression\n",
603 "Missing closing curly brace\n",
604 "Unregistered function\n",
605 "Invalid operand\n",
606 "Invalid type\n",
607 "Invalid number of arguments\n",
608 "Invalid context size\n",
609 "Invalid context position\n",
610 "Memory allocation error\n",
611 "Syntax error\n",
612 "Resource error\n",
613 "Sub resource error\n",
614 "Undefined namespace prefix\n",
615 "Encoding error\n",
616 "Char out of XML range\n",
617 "Invalid or incomplete context\n",
618 "Stack usage error\n",
619 "Forbidden variable\n",
620 "Operation limit exceeded\n",
621 "Recursion limit exceeded\n",
622 "?? Unknown error ??\n" /* Must be last in the list! */
623};
624#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
625 sizeof(xmlXPathErrorMessages[0])) - 1)
626/**
627 * xmlXPathErrMemory:
628 * @ctxt: an XPath context
629 * @extra: extra information
630 *
631 * Handle a redefinition of attribute error
632 */
633static void
634xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
635{
636 if (ctxt != NULL) {
637 xmlResetError(&ctxt->lastError);
638 if (extra) {
639 xmlChar buf[200];
640
641 xmlStrPrintf(buf, 200,
642 "Memory allocation failed : %s\n",
643 extra);
644 ctxt->lastError.message = (char *) xmlStrdup(buf);
645 } else {
646 ctxt->lastError.message = (char *)
647 xmlStrdup(BAD_CAST "Memory allocation failed\n");
648 }
649 ctxt->lastError.domain = XML_FROM_XPATH;
650 ctxt->lastError.code = XML_ERR_NO_MEMORY;
651 if (ctxt->error != NULL)
652 ctxt->error(ctxt->userData, &ctxt->lastError);
653 } else {
654 if (extra)
655 __xmlRaiseError(NULL, NULL, NULL,
656 NULL, NULL, XML_FROM_XPATH,
657 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
658 extra, NULL, NULL, 0, 0,
659 "Memory allocation failed : %s\n", extra);
660 else
661 __xmlRaiseError(NULL, NULL, NULL,
662 NULL, NULL, XML_FROM_XPATH,
663 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
664 NULL, NULL, NULL, 0, 0,
665 "Memory allocation failed\n");
666 }
667}
668
669/**
670 * xmlXPathPErrMemory:
671 * @ctxt: an XPath parser context
672 * @extra: extra information
673 *
674 * Handle a redefinition of attribute error
675 */
676static void
677xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
678{
679 if (ctxt == NULL)
680 xmlXPathErrMemory(NULL, extra);
681 else {
682 ctxt->error = XPATH_MEMORY_ERROR;
683 xmlXPathErrMemory(ctxt->context, extra);
684 }
685}
686
687/**
688 * xmlXPathErr:
689 * @ctxt: a XPath parser context
690 * @error: the error code
691 *
692 * Handle an XPath error
693 */
694void
695xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
696{
697 if ((error < 0) || (error > MAXERRNO))
698 error = MAXERRNO;
699 if (ctxt == NULL) {
700 __xmlRaiseError(NULL, NULL, NULL,
701 NULL, NULL, XML_FROM_XPATH,
702 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703 XML_ERR_ERROR, NULL, 0,
704 NULL, NULL, NULL, 0, 0,
705 "%s", xmlXPathErrorMessages[error]);
706 return;
707 }
708 /* Only report the first error */
709 if (ctxt->error != 0)
710 return;
711 ctxt->error = error;
712 if (ctxt->context == NULL) {
713 __xmlRaiseError(NULL, NULL, NULL,
714 NULL, NULL, XML_FROM_XPATH,
715 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
716 XML_ERR_ERROR, NULL, 0,
717 (const char *) ctxt->base, NULL, NULL,
718 ctxt->cur - ctxt->base, 0,
719 "%s", xmlXPathErrorMessages[error]);
720 return;
721 }
722
723 /* cleanup current last error */
724 xmlResetError(&ctxt->context->lastError);
725
726 ctxt->context->lastError.domain = XML_FROM_XPATH;
727 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
728 XPATH_EXPRESSION_OK;
729 ctxt->context->lastError.level = XML_ERR_ERROR;
730 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
731 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
732 ctxt->context->lastError.node = ctxt->context->debugNode;
733 if (ctxt->context->error != NULL) {
734 ctxt->context->error(ctxt->context->userData,
735 &ctxt->context->lastError);
736 } else {
737 __xmlRaiseError(NULL, NULL, NULL,
738 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
739 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
740 XML_ERR_ERROR, NULL, 0,
741 (const char *) ctxt->base, NULL, NULL,
742 ctxt->cur - ctxt->base, 0,
743 "%s", xmlXPathErrorMessages[error]);
744 }
745
746}
747
748/**
749 * xmlXPatherror:
750 * @ctxt: the XPath Parser context
751 * @file: the file name
752 * @line: the line number
753 * @no: the error number
754 *
755 * Formats an error message.
756 */
757void
758xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
759 int line ATTRIBUTE_UNUSED, int no) {
760 xmlXPathErr(ctxt, no);
761}
762
763/**
764 * xmlXPathCheckOpLimit:
765 * @ctxt: the XPath Parser context
766 * @opCount: the number of operations to be added
767 *
768 * Adds opCount to the running total of operations and returns -1 if the
769 * operation limit is exceeded. Returns 0 otherwise.
770 */
771static int
772xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
773 xmlXPathContextPtr xpctxt = ctxt->context;
774
775 if ((opCount > xpctxt->opLimit) ||
776 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
777 xpctxt->opCount = xpctxt->opLimit;
778 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
779 return(-1);
780 }
781
782 xpctxt->opCount += opCount;
783 return(0);
784}
785
786#define OP_LIMIT_EXCEEDED(ctxt, n) \
787 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
788
789/************************************************************************
790 * *
791 * Utilities *
792 * *
793 ************************************************************************/
794
795/**
796 * xsltPointerList:
797 *
798 * Pointer-list for various purposes.
799 */
800typedef struct _xmlPointerList xmlPointerList;
801typedef xmlPointerList *xmlPointerListPtr;
802struct _xmlPointerList {
803 void **items;
804 int number;
805 int size;
806};
807/*
808* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
809* and here, we should make the functions public.
810*/
811static int
812xmlPointerListAddSize(xmlPointerListPtr list,
813 void *item,
814 int initialSize)
815{
816 if (list->size <= list->number) {
817 void **tmp;
818 size_t newSize;
819
820 if (list->size == 0) {
821 if (initialSize <= 0)
822 initialSize = 1;
823 newSize = initialSize;
824 } else {
825 if (list->size > 50000000) {
826 xmlXPathErrMemory(NULL,
827 "xmlPointerListAddSize: re-allocating item\n");
828 return(-1);
829 }
830 newSize = list->size * 2;
831 }
832 tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
833 if (tmp == NULL) {
834 xmlXPathErrMemory(NULL,
835 "xmlPointerListAddSize: re-allocating item\n");
836 return(-1);
837 }
838 list->items = tmp;
839 list->size = newSize;
840 }
841 list->items[list->number++] = item;
842 return(0);
843}
844
845/**
846 * xsltPointerListCreate:
847 *
848 * Creates an xsltPointerList structure.
849 *
850 * Returns a xsltPointerList structure or NULL in case of an error.
851 */
852static xmlPointerListPtr
853xmlPointerListCreate(int initialSize)
854{
855 xmlPointerListPtr ret;
856
857 ret = xmlMalloc(sizeof(xmlPointerList));
858 if (ret == NULL) {
859 xmlXPathErrMemory(NULL,
860 "xmlPointerListCreate: allocating item\n");
861 return (NULL);
862 }
863 memset(ret, 0, sizeof(xmlPointerList));
864 if (initialSize > 0) {
865 xmlPointerListAddSize(ret, NULL, initialSize);
866 ret->number = 0;
867 }
868 return (ret);
869}
870
871/**
872 * xsltPointerListFree:
873 *
874 * Frees the xsltPointerList structure. This does not free
875 * the content of the list.
876 */
877static void
878xmlPointerListFree(xmlPointerListPtr list)
879{
880 if (list == NULL)
881 return;
882 if (list->items != NULL)
883 xmlFree(list->items);
884 xmlFree(list);
885}
886
887/************************************************************************
888 * *
889 * Parser Types *
890 * *
891 ************************************************************************/
892
893/*
894 * Types are private:
895 */
896
897typedef enum {
898 XPATH_OP_END=0,
899 XPATH_OP_AND,
900 XPATH_OP_OR,
901 XPATH_OP_EQUAL,
902 XPATH_OP_CMP,
903 XPATH_OP_PLUS,
904 XPATH_OP_MULT,
905 XPATH_OP_UNION,
906 XPATH_OP_ROOT,
907 XPATH_OP_NODE,
908 XPATH_OP_COLLECT,
909 XPATH_OP_VALUE, /* 11 */
910 XPATH_OP_VARIABLE,
911 XPATH_OP_FUNCTION,
912 XPATH_OP_ARG,
913 XPATH_OP_PREDICATE,
914 XPATH_OP_FILTER, /* 16 */
915 XPATH_OP_SORT /* 17 */
916#ifdef LIBXML_XPTR_LOCS_ENABLED
917 ,XPATH_OP_RANGETO
918#endif
919} xmlXPathOp;
920
921typedef enum {
922 AXIS_ANCESTOR = 1,
923 AXIS_ANCESTOR_OR_SELF,
924 AXIS_ATTRIBUTE,
925 AXIS_CHILD,
926 AXIS_DESCENDANT,
927 AXIS_DESCENDANT_OR_SELF,
928 AXIS_FOLLOWING,
929 AXIS_FOLLOWING_SIBLING,
930 AXIS_NAMESPACE,
931 AXIS_PARENT,
932 AXIS_PRECEDING,
933 AXIS_PRECEDING_SIBLING,
934 AXIS_SELF
935} xmlXPathAxisVal;
936
937typedef enum {
938 NODE_TEST_NONE = 0,
939 NODE_TEST_TYPE = 1,
940 NODE_TEST_PI = 2,
941 NODE_TEST_ALL = 3,
942 NODE_TEST_NS = 4,
943 NODE_TEST_NAME = 5
944} xmlXPathTestVal;
945
946typedef enum {
947 NODE_TYPE_NODE = 0,
948 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
949 NODE_TYPE_TEXT = XML_TEXT_NODE,
950 NODE_TYPE_PI = XML_PI_NODE
951} xmlXPathTypeVal;
952
953typedef struct _xmlXPathStepOp xmlXPathStepOp;
954typedef xmlXPathStepOp *xmlXPathStepOpPtr;
955struct _xmlXPathStepOp {
956 xmlXPathOp op; /* The identifier of the operation */
957 int ch1; /* First child */
958 int ch2; /* Second child */
959 int value;
960 int value2;
961 int value3;
962 void *value4;
963 void *value5;
964 xmlXPathFunction cache;
965 void *cacheURI;
966};
967
968struct _xmlXPathCompExpr {
969 int nbStep; /* Number of steps in this expression */
970 int maxStep; /* Maximum number of steps allocated */
971 xmlXPathStepOp *steps; /* ops for computation of this expression */
972 int last; /* index of last step in expression */
973 xmlChar *expr; /* the expression being computed */
974 xmlDictPtr dict; /* the dictionary to use if any */
975#ifdef XPATH_STREAMING
976 xmlPatternPtr stream;
977#endif
978};
979
980/************************************************************************
981 * *
982 * Forward declarations *
983 * *
984 ************************************************************************/
985static void
986xmlXPathFreeValueTree(xmlNodeSetPtr obj);
987static void
988xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
989static int
990xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
991 xmlXPathStepOpPtr op, xmlNodePtr *first);
992static int
993xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
994 xmlXPathStepOpPtr op,
995 int isPredicate);
996static void
997xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
998
999/************************************************************************
1000 * *
1001 * Parser Type functions *
1002 * *
1003 ************************************************************************/
1004
1005/**
1006 * xmlXPathNewCompExpr:
1007 *
1008 * Create a new Xpath component
1009 *
1010 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1011 */
1012static xmlXPathCompExprPtr
1013xmlXPathNewCompExpr(void) {
1014 xmlXPathCompExprPtr cur;
1015
1016 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1017 if (cur == NULL) {
1018 xmlXPathErrMemory(NULL, "allocating component\n");
1019 return(NULL);
1020 }
1021 memset(cur, 0, sizeof(xmlXPathCompExpr));
1022 cur->maxStep = 10;
1023 cur->nbStep = 0;
1024 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1025 sizeof(xmlXPathStepOp));
1026 if (cur->steps == NULL) {
1027 xmlXPathErrMemory(NULL, "allocating steps\n");
1028 xmlFree(cur);
1029 return(NULL);
1030 }
1031 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1032 cur->last = -1;
1033 return(cur);
1034}
1035
1036/**
1037 * xmlXPathFreeCompExpr:
1038 * @comp: an XPATH comp
1039 *
1040 * Free up the memory allocated by @comp
1041 */
1042void
1043xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1044{
1045 xmlXPathStepOpPtr op;
1046 int i;
1047
1048 if (comp == NULL)
1049 return;
1050 if (comp->dict == NULL) {
1051 for (i = 0; i < comp->nbStep; i++) {
1052 op = &comp->steps[i];
1053 if (op->value4 != NULL) {
1054 if (op->op == XPATH_OP_VALUE)
1055 xmlXPathFreeObject(op->value4);
1056 else
1057 xmlFree(op->value4);
1058 }
1059 if (op->value5 != NULL)
1060 xmlFree(op->value5);
1061 }
1062 } else {
1063 for (i = 0; i < comp->nbStep; i++) {
1064 op = &comp->steps[i];
1065 if (op->value4 != NULL) {
1066 if (op->op == XPATH_OP_VALUE)
1067 xmlXPathFreeObject(op->value4);
1068 }
1069 }
1070 xmlDictFree(comp->dict);
1071 }
1072 if (comp->steps != NULL) {
1073 xmlFree(comp->steps);
1074 }
1075#ifdef XPATH_STREAMING
1076 if (comp->stream != NULL) {
1077 xmlFreePatternList(comp->stream);
1078 }
1079#endif
1080 if (comp->expr != NULL) {
1081 xmlFree(comp->expr);
1082 }
1083
1084 xmlFree(comp);
1085}
1086
1087/**
1088 * xmlXPathCompExprAdd:
1089 * @comp: the compiled expression
1090 * @ch1: first child index
1091 * @ch2: second child index
1092 * @op: an op
1093 * @value: the first int value
1094 * @value2: the second int value
1095 * @value3: the third int value
1096 * @value4: the first string value
1097 * @value5: the second string value
1098 *
1099 * Add a step to an XPath Compiled Expression
1100 *
1101 * Returns -1 in case of failure, the index otherwise
1102 */
1103static int
1104xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1105 xmlXPathOp op, int value,
1106 int value2, int value3, void *value4, void *value5) {
1107 xmlXPathCompExprPtr comp = ctxt->comp;
1108 if (comp->nbStep >= comp->maxStep) {
1109 xmlXPathStepOp *real;
1110
1111 if (comp->maxStep >= XPATH_MAX_STEPS) {
1112 xmlXPathPErrMemory(ctxt, "adding step\n");
1113 return(-1);
1114 }
1115 comp->maxStep *= 2;
1116 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1117 comp->maxStep * sizeof(xmlXPathStepOp));
1118 if (real == NULL) {
1119 comp->maxStep /= 2;
1120 xmlXPathPErrMemory(ctxt, "adding step\n");
1121 return(-1);
1122 }
1123 comp->steps = real;
1124 }
1125 comp->last = comp->nbStep;
1126 comp->steps[comp->nbStep].ch1 = ch1;
1127 comp->steps[comp->nbStep].ch2 = ch2;
1128 comp->steps[comp->nbStep].op = op;
1129 comp->steps[comp->nbStep].value = value;
1130 comp->steps[comp->nbStep].value2 = value2;
1131 comp->steps[comp->nbStep].value3 = value3;
1132 if ((comp->dict != NULL) &&
1133 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1134 (op == XPATH_OP_COLLECT))) {
1135 if (value4 != NULL) {
1136 comp->steps[comp->nbStep].value4 = (xmlChar *)
1137 (void *)xmlDictLookup(comp->dict, value4, -1);
1138 xmlFree(value4);
1139 } else
1140 comp->steps[comp->nbStep].value4 = NULL;
1141 if (value5 != NULL) {
1142 comp->steps[comp->nbStep].value5 = (xmlChar *)
1143 (void *)xmlDictLookup(comp->dict, value5, -1);
1144 xmlFree(value5);
1145 } else
1146 comp->steps[comp->nbStep].value5 = NULL;
1147 } else {
1148 comp->steps[comp->nbStep].value4 = value4;
1149 comp->steps[comp->nbStep].value5 = value5;
1150 }
1151 comp->steps[comp->nbStep].cache = NULL;
1152 return(comp->nbStep++);
1153}
1154
1155/**
1156 * xmlXPathCompSwap:
1157 * @comp: the compiled expression
1158 * @op: operation index
1159 *
1160 * Swaps 2 operations in the compiled expression
1161 */
1162static void
1163xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1164 int tmp;
1165
1166#ifndef LIBXML_THREAD_ENABLED
1167 /*
1168 * Since this manipulates possibly shared variables, this is
1169 * disabled if one detects that the library is used in a multithreaded
1170 * application
1171 */
1172 if (xmlXPathDisableOptimizer)
1173 return;
1174#endif
1175
1176 tmp = op->ch1;
1177 op->ch1 = op->ch2;
1178 op->ch2 = tmp;
1179}
1180
1181#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1182 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1183 (op), (val), (val2), (val3), (val4), (val5))
1184#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1185 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1186 (op), (val), (val2), (val3), (val4), (val5))
1187
1188#define PUSH_LEAVE_EXPR(op, val, val2) \
1189xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1190
1191#define PUSH_UNARY_EXPR(op, ch, val, val2) \
1192xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1193
1194#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1195xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1196 (val), (val2), 0 ,NULL ,NULL)
1197
1198/************************************************************************
1199 * *
1200 * XPath object cache structures *
1201 * *
1202 ************************************************************************/
1203
1204/* #define XP_DEFAULT_CACHE_ON */
1205
1206#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1207
1208typedef struct _xmlXPathContextCache xmlXPathContextCache;
1209typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1210struct _xmlXPathContextCache {
1211 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1212 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1213 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1214 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1215 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1216 int maxNodeset;
1217 int maxString;
1218 int maxBoolean;
1219 int maxNumber;
1220 int maxMisc;
1221};
1222
1223/************************************************************************
1224 * *
1225 * Debugging related functions *
1226 * *
1227 ************************************************************************/
1228
1229#define STRANGE \
1230 xmlGenericError(xmlGenericErrorContext, \
1231 "Internal error at %s:%d\n", \
1232 __FILE__, __LINE__);
1233
1234#ifdef LIBXML_DEBUG_ENABLED
1235static void
1236xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1237 int i;
1238 char shift[100];
1239
1240 for (i = 0;((i < depth) && (i < 25));i++)
1241 shift[2 * i] = shift[2 * i + 1] = ' ';
1242 shift[2 * i] = shift[2 * i + 1] = 0;
1243 if (cur == NULL) {
1244 fprintf(output, "%s", shift);
1245 fprintf(output, "Node is NULL !\n");
1246 return;
1247
1248 }
1249
1250 if ((cur->type == XML_DOCUMENT_NODE) ||
1251 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1252 fprintf(output, "%s", shift);
1253 fprintf(output, " /\n");
1254 } else if (cur->type == XML_ATTRIBUTE_NODE)
1255 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1256 else
1257 xmlDebugDumpOneNode(output, cur, depth);
1258}
1259static void
1260xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1261 xmlNodePtr tmp;
1262 int i;
1263 char shift[100];
1264
1265 for (i = 0;((i < depth) && (i < 25));i++)
1266 shift[2 * i] = shift[2 * i + 1] = ' ';
1267 shift[2 * i] = shift[2 * i + 1] = 0;
1268 if (cur == NULL) {
1269 fprintf(output, "%s", shift);
1270 fprintf(output, "Node is NULL !\n");
1271 return;
1272
1273 }
1274
1275 while (cur != NULL) {
1276 tmp = cur;
1277 cur = cur->next;
1278 xmlDebugDumpOneNode(output, tmp, depth);
1279 }
1280}
1281
1282static void
1283xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1284 int i;
1285 char shift[100];
1286
1287 for (i = 0;((i < depth) && (i < 25));i++)
1288 shift[2 * i] = shift[2 * i + 1] = ' ';
1289 shift[2 * i] = shift[2 * i + 1] = 0;
1290
1291 if (cur == NULL) {
1292 fprintf(output, "%s", shift);
1293 fprintf(output, "NodeSet is NULL !\n");
1294 return;
1295
1296 }
1297
1298 if (cur != NULL) {
1299 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1300 for (i = 0;i < cur->nodeNr;i++) {
1301 fprintf(output, "%s", shift);
1302 fprintf(output, "%d", i + 1);
1303 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1304 }
1305 }
1306}
1307
1308static void
1309xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1310 int i;
1311 char shift[100];
1312
1313 for (i = 0;((i < depth) && (i < 25));i++)
1314 shift[2 * i] = shift[2 * i + 1] = ' ';
1315 shift[2 * i] = shift[2 * i + 1] = 0;
1316
1317 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1318 fprintf(output, "%s", shift);
1319 fprintf(output, "Value Tree is NULL !\n");
1320 return;
1321
1322 }
1323
1324 fprintf(output, "%s", shift);
1325 fprintf(output, "%d", i + 1);
1326 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1327}
1328#if defined(LIBXML_XPTR_LOCS_ENABLED)
1329static void
1330xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1331 int i;
1332 char shift[100];
1333
1334 for (i = 0;((i < depth) && (i < 25));i++)
1335 shift[2 * i] = shift[2 * i + 1] = ' ';
1336 shift[2 * i] = shift[2 * i + 1] = 0;
1337
1338 if (cur == NULL) {
1339 fprintf(output, "%s", shift);
1340 fprintf(output, "LocationSet is NULL !\n");
1341 return;
1342
1343 }
1344
1345 for (i = 0;i < cur->locNr;i++) {
1346 fprintf(output, "%s", shift);
1347 fprintf(output, "%d : ", i + 1);
1348 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1349 }
1350}
1351#endif /* LIBXML_XPTR_LOCS_ENABLED */
1352
1353/**
1354 * xmlXPathDebugDumpObject:
1355 * @output: the FILE * to dump the output
1356 * @cur: the object to inspect
1357 * @depth: indentation level
1358 *
1359 * Dump the content of the object for debugging purposes
1360 */
1361void
1362xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1363 int i;
1364 char shift[100];
1365
1366 if (output == NULL) return;
1367
1368 for (i = 0;((i < depth) && (i < 25));i++)
1369 shift[2 * i] = shift[2 * i + 1] = ' ';
1370 shift[2 * i] = shift[2 * i + 1] = 0;
1371
1372
1373 fprintf(output, "%s", shift);
1374
1375 if (cur == NULL) {
1376 fprintf(output, "Object is empty (NULL)\n");
1377 return;
1378 }
1379 switch(cur->type) {
1380 case XPATH_UNDEFINED:
1381 fprintf(output, "Object is uninitialized\n");
1382 break;
1383 case XPATH_NODESET:
1384 fprintf(output, "Object is a Node Set :\n");
1385 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1386 break;
1387 case XPATH_XSLT_TREE:
1388 fprintf(output, "Object is an XSLT value tree :\n");
1389 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1390 break;
1391 case XPATH_BOOLEAN:
1392 fprintf(output, "Object is a Boolean : ");
1393 if (cur->boolval) fprintf(output, "true\n");
1394 else fprintf(output, "false\n");
1395 break;
1396 case XPATH_NUMBER:
1397 switch (xmlXPathIsInf(cur->floatval)) {
1398 case 1:
1399 fprintf(output, "Object is a number : Infinity\n");
1400 break;
1401 case -1:
1402 fprintf(output, "Object is a number : -Infinity\n");
1403 break;
1404 default:
1405 if (xmlXPathIsNaN(cur->floatval)) {
1406 fprintf(output, "Object is a number : NaN\n");
1407 } else if (cur->floatval == 0) {
1408 /* Omit sign for negative zero. */
1409 fprintf(output, "Object is a number : 0\n");
1410 } else {
1411 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1412 }
1413 }
1414 break;
1415 case XPATH_STRING:
1416 fprintf(output, "Object is a string : ");
1417 xmlDebugDumpString(output, cur->stringval);
1418 fprintf(output, "\n");
1419 break;
1420#ifdef LIBXML_XPTR_LOCS_ENABLED
1421 case XPATH_POINT:
1422 fprintf(output, "Object is a point : index %d in node", cur->index);
1423 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1424 fprintf(output, "\n");
1425 break;
1426 case XPATH_RANGE:
1427 if ((cur->user2 == NULL) ||
1428 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1429 fprintf(output, "Object is a collapsed range :\n");
1430 fprintf(output, "%s", shift);
1431 if (cur->index >= 0)
1432 fprintf(output, "index %d in ", cur->index);
1433 fprintf(output, "node\n");
1434 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1435 depth + 1);
1436 } else {
1437 fprintf(output, "Object is a range :\n");
1438 fprintf(output, "%s", shift);
1439 fprintf(output, "From ");
1440 if (cur->index >= 0)
1441 fprintf(output, "index %d in ", cur->index);
1442 fprintf(output, "node\n");
1443 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1444 depth + 1);
1445 fprintf(output, "%s", shift);
1446 fprintf(output, "To ");
1447 if (cur->index2 >= 0)
1448 fprintf(output, "index %d in ", cur->index2);
1449 fprintf(output, "node\n");
1450 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1451 depth + 1);
1452 fprintf(output, "\n");
1453 }
1454 break;
1455 case XPATH_LOCATIONSET:
1456 fprintf(output, "Object is a Location Set:\n");
1457 xmlXPathDebugDumpLocationSet(output,
1458 (xmlLocationSetPtr) cur->user, depth);
1459 break;
1460#endif /* LIBXML_XPTR_LOCS_ENABLED */
1461 case XPATH_USERS:
1462 fprintf(output, "Object is user defined\n");
1463 break;
1464 }
1465}
1466
1467static void
1468xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1469 xmlXPathStepOpPtr op, int depth) {
1470 int i;
1471 char shift[100];
1472
1473 for (i = 0;((i < depth) && (i < 25));i++)
1474 shift[2 * i] = shift[2 * i + 1] = ' ';
1475 shift[2 * i] = shift[2 * i + 1] = 0;
1476
1477 fprintf(output, "%s", shift);
1478 if (op == NULL) {
1479 fprintf(output, "Step is NULL\n");
1480 return;
1481 }
1482 switch (op->op) {
1483 case XPATH_OP_END:
1484 fprintf(output, "END"); break;
1485 case XPATH_OP_AND:
1486 fprintf(output, "AND"); break;
1487 case XPATH_OP_OR:
1488 fprintf(output, "OR"); break;
1489 case XPATH_OP_EQUAL:
1490 if (op->value)
1491 fprintf(output, "EQUAL =");
1492 else
1493 fprintf(output, "EQUAL !=");
1494 break;
1495 case XPATH_OP_CMP:
1496 if (op->value)
1497 fprintf(output, "CMP <");
1498 else
1499 fprintf(output, "CMP >");
1500 if (!op->value2)
1501 fprintf(output, "=");
1502 break;
1503 case XPATH_OP_PLUS:
1504 if (op->value == 0)
1505 fprintf(output, "PLUS -");
1506 else if (op->value == 1)
1507 fprintf(output, "PLUS +");
1508 else if (op->value == 2)
1509 fprintf(output, "PLUS unary -");
1510 else if (op->value == 3)
1511 fprintf(output, "PLUS unary - -");
1512 break;
1513 case XPATH_OP_MULT:
1514 if (op->value == 0)
1515 fprintf(output, "MULT *");
1516 else if (op->value == 1)
1517 fprintf(output, "MULT div");
1518 else
1519 fprintf(output, "MULT mod");
1520 break;
1521 case XPATH_OP_UNION:
1522 fprintf(output, "UNION"); break;
1523 case XPATH_OP_ROOT:
1524 fprintf(output, "ROOT"); break;
1525 case XPATH_OP_NODE:
1526 fprintf(output, "NODE"); break;
1527 case XPATH_OP_SORT:
1528 fprintf(output, "SORT"); break;
1529 case XPATH_OP_COLLECT: {
1530 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1531 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1532 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1533 const xmlChar *prefix = op->value4;
1534 const xmlChar *name = op->value5;
1535
1536 fprintf(output, "COLLECT ");
1537 switch (axis) {
1538 case AXIS_ANCESTOR:
1539 fprintf(output, " 'ancestors' "); break;
1540 case AXIS_ANCESTOR_OR_SELF:
1541 fprintf(output, " 'ancestors-or-self' "); break;
1542 case AXIS_ATTRIBUTE:
1543 fprintf(output, " 'attributes' "); break;
1544 case AXIS_CHILD:
1545 fprintf(output, " 'child' "); break;
1546 case AXIS_DESCENDANT:
1547 fprintf(output, " 'descendant' "); break;
1548 case AXIS_DESCENDANT_OR_SELF:
1549 fprintf(output, " 'descendant-or-self' "); break;
1550 case AXIS_FOLLOWING:
1551 fprintf(output, " 'following' "); break;
1552 case AXIS_FOLLOWING_SIBLING:
1553 fprintf(output, " 'following-siblings' "); break;
1554 case AXIS_NAMESPACE:
1555 fprintf(output, " 'namespace' "); break;
1556 case AXIS_PARENT:
1557 fprintf(output, " 'parent' "); break;
1558 case AXIS_PRECEDING:
1559 fprintf(output, " 'preceding' "); break;
1560 case AXIS_PRECEDING_SIBLING:
1561 fprintf(output, " 'preceding-sibling' "); break;
1562 case AXIS_SELF:
1563 fprintf(output, " 'self' "); break;
1564 }
1565 switch (test) {
1566 case NODE_TEST_NONE:
1567 fprintf(output, "'none' "); break;
1568 case NODE_TEST_TYPE:
1569 fprintf(output, "'type' "); break;
1570 case NODE_TEST_PI:
1571 fprintf(output, "'PI' "); break;
1572 case NODE_TEST_ALL:
1573 fprintf(output, "'all' "); break;
1574 case NODE_TEST_NS:
1575 fprintf(output, "'namespace' "); break;
1576 case NODE_TEST_NAME:
1577 fprintf(output, "'name' "); break;
1578 }
1579 switch (type) {
1580 case NODE_TYPE_NODE:
1581 fprintf(output, "'node' "); break;
1582 case NODE_TYPE_COMMENT:
1583 fprintf(output, "'comment' "); break;
1584 case NODE_TYPE_TEXT:
1585 fprintf(output, "'text' "); break;
1586 case NODE_TYPE_PI:
1587 fprintf(output, "'PI' "); break;
1588 }
1589 if (prefix != NULL)
1590 fprintf(output, "%s:", prefix);
1591 if (name != NULL)
1592 fprintf(output, "%s", (const char *) name);
1593 break;
1594
1595 }
1596 case XPATH_OP_VALUE: {
1597 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1598
1599 fprintf(output, "ELEM ");
1600 xmlXPathDebugDumpObject(output, object, 0);
1601 goto finish;
1602 }
1603 case XPATH_OP_VARIABLE: {
1604 const xmlChar *prefix = op->value5;
1605 const xmlChar *name = op->value4;
1606
1607 if (prefix != NULL)
1608 fprintf(output, "VARIABLE %s:%s", prefix, name);
1609 else
1610 fprintf(output, "VARIABLE %s", name);
1611 break;
1612 }
1613 case XPATH_OP_FUNCTION: {
1614 int nbargs = op->value;
1615 const xmlChar *prefix = op->value5;
1616 const xmlChar *name = op->value4;
1617
1618 if (prefix != NULL)
1619 fprintf(output, "FUNCTION %s:%s(%d args)",
1620 prefix, name, nbargs);
1621 else
1622 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1623 break;
1624 }
1625 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1626 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1627 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1628#ifdef LIBXML_XPTR_LOCS_ENABLED
1629 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1630#endif
1631 default:
1632 fprintf(output, "UNKNOWN %d\n", op->op); return;
1633 }
1634 fprintf(output, "\n");
1635finish:
1636 if (op->ch1 >= 0)
1637 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1638 if (op->ch2 >= 0)
1639 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1640}
1641
1642/**
1643 * xmlXPathDebugDumpCompExpr:
1644 * @output: the FILE * for the output
1645 * @comp: the precompiled XPath expression
1646 * @depth: the indentation level.
1647 *
1648 * Dumps the tree of the compiled XPath expression.
1649 */
1650void
1651xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1652 int depth) {
1653 int i;
1654 char shift[100];
1655
1656 if ((output == NULL) || (comp == NULL)) return;
1657
1658 for (i = 0;((i < depth) && (i < 25));i++)
1659 shift[2 * i] = shift[2 * i + 1] = ' ';
1660 shift[2 * i] = shift[2 * i + 1] = 0;
1661
1662 fprintf(output, "%s", shift);
1663
1664#ifdef XPATH_STREAMING
1665 if (comp->stream) {
1666 fprintf(output, "Streaming Expression\n");
1667 } else
1668#endif
1669 {
1670 fprintf(output, "Compiled Expression : %d elements\n",
1671 comp->nbStep);
1672 i = comp->last;
1673 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1674 }
1675}
1676
1677#endif /* LIBXML_DEBUG_ENABLED */
1678
1679/************************************************************************
1680 * *
1681 * XPath object caching *
1682 * *
1683 ************************************************************************/
1684
1685/**
1686 * xmlXPathNewCache:
1687 *
1688 * Create a new object cache
1689 *
1690 * Returns the xmlXPathCache just allocated.
1691 */
1692static xmlXPathContextCachePtr
1693xmlXPathNewCache(void)
1694{
1695 xmlXPathContextCachePtr ret;
1696
1697 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1698 if (ret == NULL) {
1699 xmlXPathErrMemory(NULL, "creating object cache\n");
1700 return(NULL);
1701 }
1702 memset(ret, 0 , sizeof(xmlXPathContextCache));
1703 ret->maxNodeset = 100;
1704 ret->maxString = 100;
1705 ret->maxBoolean = 100;
1706 ret->maxNumber = 100;
1707 ret->maxMisc = 100;
1708 return(ret);
1709}
1710
1711static void
1712xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1713{
1714 int i;
1715 xmlXPathObjectPtr obj;
1716
1717 if (list == NULL)
1718 return;
1719
1720 for (i = 0; i < list->number; i++) {
1721 obj = list->items[i];
1722 /*
1723 * Note that it is already assured that we don't need to
1724 * look out for namespace nodes in the node-set.
1725 */
1726 if (obj->nodesetval != NULL) {
1727 if (obj->nodesetval->nodeTab != NULL)
1728 xmlFree(obj->nodesetval->nodeTab);
1729 xmlFree(obj->nodesetval);
1730 }
1731 xmlFree(obj);
1732 }
1733 xmlPointerListFree(list);
1734}
1735
1736static void
1737xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1738{
1739 if (cache == NULL)
1740 return;
1741 if (cache->nodesetObjs)
1742 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1743 if (cache->stringObjs)
1744 xmlXPathCacheFreeObjectList(cache->stringObjs);
1745 if (cache->booleanObjs)
1746 xmlXPathCacheFreeObjectList(cache->booleanObjs);
1747 if (cache->numberObjs)
1748 xmlXPathCacheFreeObjectList(cache->numberObjs);
1749 if (cache->miscObjs)
1750 xmlXPathCacheFreeObjectList(cache->miscObjs);
1751 xmlFree(cache);
1752}
1753
1754/**
1755 * xmlXPathContextSetCache:
1756 *
1757 * @ctxt: the XPath context
1758 * @active: enables/disables (creates/frees) the cache
1759 * @value: a value with semantics dependent on @options
1760 * @options: options (currently only the value 0 is used)
1761 *
1762 * Creates/frees an object cache on the XPath context.
1763 * If activates XPath objects (xmlXPathObject) will be cached internally
1764 * to be reused.
1765 * @options:
1766 * 0: This will set the XPath object caching:
1767 * @value:
1768 * This will set the maximum number of XPath objects
1769 * to be cached per slot
1770 * There are 5 slots for: node-set, string, number, boolean, and
1771 * misc objects. Use <0 for the default number (100).
1772 * Other values for @options have currently no effect.
1773 *
1774 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1775 */
1776int
1777xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1778 int active,
1779 int value,
1780 int options)
1781{
1782 if (ctxt == NULL)
1783 return(-1);
1784 if (active) {
1785 xmlXPathContextCachePtr cache;
1786
1787 if (ctxt->cache == NULL) {
1788 ctxt->cache = xmlXPathNewCache();
1789 if (ctxt->cache == NULL)
1790 return(-1);
1791 }
1792 cache = (xmlXPathContextCachePtr) ctxt->cache;
1793 if (options == 0) {
1794 if (value < 0)
1795 value = 100;
1796 cache->maxNodeset = value;
1797 cache->maxString = value;
1798 cache->maxNumber = value;
1799 cache->maxBoolean = value;
1800 cache->maxMisc = value;
1801 }
1802 } else if (ctxt->cache != NULL) {
1803 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1804 ctxt->cache = NULL;
1805 }
1806 return(0);
1807}
1808
1809/**
1810 * xmlXPathCacheWrapNodeSet:
1811 * @ctxt: the XPath context
1812 * @val: the NodePtr value
1813 *
1814 * This is the cached version of xmlXPathWrapNodeSet().
1815 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1816 *
1817 * Returns the created or reused object.
1818 *
1819 * In case of error the node set is destroyed and NULL is returned.
1820 */
1821static xmlXPathObjectPtr
1822xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1823{
1824 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1825 xmlXPathContextCachePtr cache =
1826 (xmlXPathContextCachePtr) ctxt->cache;
1827
1828 if ((cache->miscObjs != NULL) &&
1829 (cache->miscObjs->number != 0))
1830 {
1831 xmlXPathObjectPtr ret;
1832
1833 ret = (xmlXPathObjectPtr)
1834 cache->miscObjs->items[--cache->miscObjs->number];
1835 ret->type = XPATH_NODESET;
1836 ret->nodesetval = val;
1837 return(ret);
1838 }
1839 }
1840
1841 return(xmlXPathWrapNodeSet(val));
1842
1843}
1844
1845/**
1846 * xmlXPathCacheWrapString:
1847 * @ctxt: the XPath context
1848 * @val: the xmlChar * value
1849 *
1850 * This is the cached version of xmlXPathWrapString().
1851 * Wraps the @val string into an XPath object.
1852 *
1853 * Returns the created or reused object.
1854 */
1855static xmlXPathObjectPtr
1856xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1857{
1858 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1859 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1860
1861 if ((cache->stringObjs != NULL) &&
1862 (cache->stringObjs->number != 0))
1863 {
1864
1865 xmlXPathObjectPtr ret;
1866
1867 ret = (xmlXPathObjectPtr)
1868 cache->stringObjs->items[--cache->stringObjs->number];
1869 ret->type = XPATH_STRING;
1870 ret->stringval = val;
1871 return(ret);
1872 } else if ((cache->miscObjs != NULL) &&
1873 (cache->miscObjs->number != 0))
1874 {
1875 xmlXPathObjectPtr ret;
1876 /*
1877 * Fallback to misc-cache.
1878 */
1879 ret = (xmlXPathObjectPtr)
1880 cache->miscObjs->items[--cache->miscObjs->number];
1881
1882 ret->type = XPATH_STRING;
1883 ret->stringval = val;
1884 return(ret);
1885 }
1886 }
1887 return(xmlXPathWrapString(val));
1888}
1889
1890/**
1891 * xmlXPathCacheNewNodeSet:
1892 * @ctxt: the XPath context
1893 * @val: the NodePtr value
1894 *
1895 * This is the cached version of xmlXPathNewNodeSet().
1896 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1897 * it with the single Node @val
1898 *
1899 * Returns the created or reused object.
1900 */
1901static xmlXPathObjectPtr
1902xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
1903{
1904 if ((ctxt != NULL) && (ctxt->cache)) {
1905 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1906
1907 if ((cache->nodesetObjs != NULL) &&
1908 (cache->nodesetObjs->number != 0))
1909 {
1910 xmlXPathObjectPtr ret;
1911 /*
1912 * Use the nodeset-cache.
1913 */
1914 ret = (xmlXPathObjectPtr)
1915 cache->nodesetObjs->items[--cache->nodesetObjs->number];
1916 ret->type = XPATH_NODESET;
1917 ret->boolval = 0;
1918 if (val) {
1919 if ((ret->nodesetval->nodeMax == 0) ||
1920 (val->type == XML_NAMESPACE_DECL))
1921 {
1922 /* TODO: Check memory error. */
1923 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
1924 } else {
1925 ret->nodesetval->nodeTab[0] = val;
1926 ret->nodesetval->nodeNr = 1;
1927 }
1928 }
1929 return(ret);
1930 } else if ((cache->miscObjs != NULL) &&
1931 (cache->miscObjs->number != 0))
1932 {
1933 xmlXPathObjectPtr ret;
1934 xmlNodeSetPtr set;
1935 /*
1936 * Fallback to misc-cache.
1937 */
1938
1939 set = xmlXPathNodeSetCreate(val);
1940 if (set == NULL) {
1941 ctxt->lastError.domain = XML_FROM_XPATH;
1942 ctxt->lastError.code = XML_ERR_NO_MEMORY;
1943 return(NULL);
1944 }
1945
1946 ret = (xmlXPathObjectPtr)
1947 cache->miscObjs->items[--cache->miscObjs->number];
1948
1949 ret->type = XPATH_NODESET;
1950 ret->boolval = 0;
1951 ret->nodesetval = set;
1952 return(ret);
1953 }
1954 }
1955 return(xmlXPathNewNodeSet(val));
1956}
1957
1958/**
1959 * xmlXPathCacheNewString:
1960 * @ctxt: the XPath context
1961 * @val: the xmlChar * value
1962 *
1963 * This is the cached version of xmlXPathNewString().
1964 * Acquire an xmlXPathObjectPtr of type string and of value @val
1965 *
1966 * Returns the created or reused object.
1967 */
1968static xmlXPathObjectPtr
1969xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
1970{
1971 if ((ctxt != NULL) && (ctxt->cache)) {
1972 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1973
1974 if ((cache->stringObjs != NULL) &&
1975 (cache->stringObjs->number != 0))
1976 {
1977 xmlXPathObjectPtr ret;
1978 xmlChar *copy;
1979
1980 if (val == NULL)
1981 val = BAD_CAST "";
1982 copy = xmlStrdup(val);
1983 if (copy == NULL) {
1984 xmlXPathErrMemory(ctxt, NULL);
1985 return(NULL);
1986 }
1987
1988 ret = (xmlXPathObjectPtr)
1989 cache->stringObjs->items[--cache->stringObjs->number];
1990 ret->type = XPATH_STRING;
1991 ret->stringval = copy;
1992 return(ret);
1993 } else if ((cache->miscObjs != NULL) &&
1994 (cache->miscObjs->number != 0))
1995 {
1996 xmlXPathObjectPtr ret;
1997 xmlChar *copy;
1998
1999 if (val == NULL)
2000 val = BAD_CAST "";
2001 copy = xmlStrdup(val);
2002 if (copy == NULL) {
2003 xmlXPathErrMemory(ctxt, NULL);
2004 return(NULL);
2005 }
2006
2007 ret = (xmlXPathObjectPtr)
2008 cache->miscObjs->items[--cache->miscObjs->number];
2009
2010 ret->type = XPATH_STRING;
2011 ret->stringval = copy;
2012 return(ret);
2013 }
2014 }
2015 return(xmlXPathNewString(val));
2016}
2017
2018/**
2019 * xmlXPathCacheNewCString:
2020 * @ctxt: the XPath context
2021 * @val: the char * value
2022 *
2023 * This is the cached version of xmlXPathNewCString().
2024 * Acquire an xmlXPathObjectPtr of type string and of value @val
2025 *
2026 * Returns the created or reused object.
2027 */
2028static xmlXPathObjectPtr
2029xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2030{
2031 return xmlXPathCacheNewString(ctxt, BAD_CAST val);
2032}
2033
2034/**
2035 * xmlXPathCacheNewBoolean:
2036 * @ctxt: the XPath context
2037 * @val: the boolean value
2038 *
2039 * This is the cached version of xmlXPathNewBoolean().
2040 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2041 *
2042 * Returns the created or reused object.
2043 */
2044static xmlXPathObjectPtr
2045xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2046{
2047 if ((ctxt != NULL) && (ctxt->cache)) {
2048 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2049
2050 if ((cache->booleanObjs != NULL) &&
2051 (cache->booleanObjs->number != 0))
2052 {
2053 xmlXPathObjectPtr ret;
2054
2055 ret = (xmlXPathObjectPtr)
2056 cache->booleanObjs->items[--cache->booleanObjs->number];
2057 ret->type = XPATH_BOOLEAN;
2058 ret->boolval = (val != 0);
2059 return(ret);
2060 } else if ((cache->miscObjs != NULL) &&
2061 (cache->miscObjs->number != 0))
2062 {
2063 xmlXPathObjectPtr ret;
2064
2065 ret = (xmlXPathObjectPtr)
2066 cache->miscObjs->items[--cache->miscObjs->number];
2067
2068 ret->type = XPATH_BOOLEAN;
2069 ret->boolval = (val != 0);
2070 return(ret);
2071 }
2072 }
2073 return(xmlXPathNewBoolean(val));
2074}
2075
2076/**
2077 * xmlXPathCacheNewFloat:
2078 * @ctxt: the XPath context
2079 * @val: the double value
2080 *
2081 * This is the cached version of xmlXPathNewFloat().
2082 * Acquires an xmlXPathObjectPtr of type double and of value @val
2083 *
2084 * Returns the created or reused object.
2085 */
2086static xmlXPathObjectPtr
2087xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2088{
2089 if ((ctxt != NULL) && (ctxt->cache)) {
2090 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2091
2092 if ((cache->numberObjs != NULL) &&
2093 (cache->numberObjs->number != 0))
2094 {
2095 xmlXPathObjectPtr ret;
2096
2097 ret = (xmlXPathObjectPtr)
2098 cache->numberObjs->items[--cache->numberObjs->number];
2099 ret->type = XPATH_NUMBER;
2100 ret->floatval = val;
2101 return(ret);
2102 } else if ((cache->miscObjs != NULL) &&
2103 (cache->miscObjs->number != 0))
2104 {
2105 xmlXPathObjectPtr ret;
2106
2107 ret = (xmlXPathObjectPtr)
2108 cache->miscObjs->items[--cache->miscObjs->number];
2109
2110 ret->type = XPATH_NUMBER;
2111 ret->floatval = val;
2112 return(ret);
2113 }
2114 }
2115 return(xmlXPathNewFloat(val));
2116}
2117
2118/**
2119 * xmlXPathCacheConvertString:
2120 * @ctxt: the XPath context
2121 * @val: an XPath object
2122 *
2123 * This is the cached version of xmlXPathConvertString().
2124 * Converts an existing object to its string() equivalent
2125 *
2126 * Returns a created or reused object, the old one is freed (cached)
2127 * (or the operation is done directly on @val)
2128 */
2129
2130static xmlXPathObjectPtr
2131xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2132 xmlChar *res = NULL;
2133
2134 if (val == NULL)
2135 return(xmlXPathCacheNewCString(ctxt, ""));
2136
2137 switch (val->type) {
2138 case XPATH_UNDEFINED:
2139 break;
2140 case XPATH_NODESET:
2141 case XPATH_XSLT_TREE:
2142 res = xmlXPathCastNodeSetToString(val->nodesetval);
2143 break;
2144 case XPATH_STRING:
2145 return(val);
2146 case XPATH_BOOLEAN:
2147 res = xmlXPathCastBooleanToString(val->boolval);
2148 break;
2149 case XPATH_NUMBER:
2150 res = xmlXPathCastNumberToString(val->floatval);
2151 break;
2152 case XPATH_USERS:
2153#ifdef LIBXML_XPTR_LOCS_ENABLED
2154 case XPATH_POINT:
2155 case XPATH_RANGE:
2156 case XPATH_LOCATIONSET:
2157#endif /* LIBXML_XPTR_LOCS_ENABLED */
2158 TODO;
2159 break;
2160 }
2161 xmlXPathReleaseObject(ctxt, val);
2162 if (res == NULL)
2163 return(xmlXPathCacheNewCString(ctxt, ""));
2164 return(xmlXPathCacheWrapString(ctxt, res));
2165}
2166
2167/**
2168 * xmlXPathCacheObjectCopy:
2169 * @ctxt: the XPath context
2170 * @val: the original object
2171 *
2172 * This is the cached version of xmlXPathObjectCopy().
2173 * Acquire a copy of a given object
2174 *
2175 * Returns a created or reused created object.
2176 */
2177static xmlXPathObjectPtr
2178xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2179{
2180 if (val == NULL)
2181 return(NULL);
2182
2183 if (XP_HAS_CACHE(ctxt)) {
2184 switch (val->type) {
2185 case XPATH_NODESET:
2186 return(xmlXPathCacheWrapNodeSet(ctxt,
2187 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2188 case XPATH_STRING:
2189 return(xmlXPathCacheNewString(ctxt, val->stringval));
2190 case XPATH_BOOLEAN:
2191 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2192 case XPATH_NUMBER:
2193 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2194 default:
2195 break;
2196 }
2197 }
2198 return(xmlXPathObjectCopy(val));
2199}
2200
2201/**
2202 * xmlXPathCacheConvertBoolean:
2203 * @ctxt: the XPath context
2204 * @val: an XPath object
2205 *
2206 * This is the cached version of xmlXPathConvertBoolean().
2207 * Converts an existing object to its boolean() equivalent
2208 *
2209 * Returns a created or reused object, the old one is freed (or the operation
2210 * is done directly on @val)
2211 */
2212static xmlXPathObjectPtr
2213xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2214 xmlXPathObjectPtr ret;
2215
2216 if (val == NULL)
2217 return(xmlXPathCacheNewBoolean(ctxt, 0));
2218 if (val->type == XPATH_BOOLEAN)
2219 return(val);
2220 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2221 xmlXPathReleaseObject(ctxt, val);
2222 return(ret);
2223}
2224
2225/**
2226 * xmlXPathCacheConvertNumber:
2227 * @ctxt: the XPath context
2228 * @val: an XPath object
2229 *
2230 * This is the cached version of xmlXPathConvertNumber().
2231 * Converts an existing object to its number() equivalent
2232 *
2233 * Returns a created or reused object, the old one is freed (or the operation
2234 * is done directly on @val)
2235 */
2236static xmlXPathObjectPtr
2237xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2238 xmlXPathObjectPtr ret;
2239
2240 if (val == NULL)
2241 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2242 if (val->type == XPATH_NUMBER)
2243 return(val);
2244 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2245 xmlXPathReleaseObject(ctxt, val);
2246 return(ret);
2247}
2248
2249/************************************************************************
2250 * *
2251 * Parser stacks related functions and macros *
2252 * *
2253 ************************************************************************/
2254
2255/**
2256 * valuePop:
2257 * @ctxt: an XPath evaluation context
2258 *
2259 * Pops the top XPath object from the value stack
2260 *
2261 * Returns the XPath object just removed
2262 */
2263xmlXPathObjectPtr
2264valuePop(xmlXPathParserContextPtr ctxt)
2265{
2266 xmlXPathObjectPtr ret;
2267
2268 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2269 return (NULL);
2270
2271 ctxt->valueNr--;
2272 if (ctxt->valueNr > 0)
2273 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2274 else
2275 ctxt->value = NULL;
2276 ret = ctxt->valueTab[ctxt->valueNr];
2277 ctxt->valueTab[ctxt->valueNr] = NULL;
2278 return (ret);
2279}
2280/**
2281 * valuePush:
2282 * @ctxt: an XPath evaluation context
2283 * @value: the XPath object
2284 *
2285 * Pushes a new XPath object on top of the value stack. If value is NULL,
2286 * a memory error is recorded in the parser context.
2287 *
2288 * Returns the number of items on the value stack, or -1 in case of error.
2289 *
2290 * The object is destroyed in case of error.
2291 */
2292int
2293valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2294{
2295 if (ctxt == NULL) return(-1);
2296 if (value == NULL) {
2297 /*
2298 * A NULL value typically indicates that a memory allocation failed,
2299 * so we set ctxt->error here to propagate the error.
2300 */
2301 ctxt->error = XPATH_MEMORY_ERROR;
2302 return(-1);
2303 }
2304 if (ctxt->valueNr >= ctxt->valueMax) {
2305 xmlXPathObjectPtr *tmp;
2306
2307 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2308 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2309 xmlXPathFreeObject(value);
2310 return (-1);
2311 }
2312 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2313 2 * ctxt->valueMax *
2314 sizeof(ctxt->valueTab[0]));
2315 if (tmp == NULL) {
2316 xmlXPathPErrMemory(ctxt, "pushing value\n");
2317 xmlXPathFreeObject(value);
2318 return (-1);
2319 }
2320 ctxt->valueMax *= 2;
2321 ctxt->valueTab = tmp;
2322 }
2323 ctxt->valueTab[ctxt->valueNr] = value;
2324 ctxt->value = value;
2325 return (ctxt->valueNr++);
2326}
2327
2328/**
2329 * xmlXPathPopBoolean:
2330 * @ctxt: an XPath parser context
2331 *
2332 * Pops a boolean from the stack, handling conversion if needed.
2333 * Check error with #xmlXPathCheckError.
2334 *
2335 * Returns the boolean
2336 */
2337int
2338xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2339 xmlXPathObjectPtr obj;
2340 int ret;
2341
2342 obj = valuePop(ctxt);
2343 if (obj == NULL) {
2344 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2345 return(0);
2346 }
2347 if (obj->type != XPATH_BOOLEAN)
2348 ret = xmlXPathCastToBoolean(obj);
2349 else
2350 ret = obj->boolval;
2351 xmlXPathReleaseObject(ctxt->context, obj);
2352 return(ret);
2353}
2354
2355/**
2356 * xmlXPathPopNumber:
2357 * @ctxt: an XPath parser context
2358 *
2359 * Pops a number from the stack, handling conversion if needed.
2360 * Check error with #xmlXPathCheckError.
2361 *
2362 * Returns the number
2363 */
2364double
2365xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2366 xmlXPathObjectPtr obj;
2367 double ret;
2368
2369 obj = valuePop(ctxt);
2370 if (obj == NULL) {
2371 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2372 return(0);
2373 }
2374 if (obj->type != XPATH_NUMBER)
2375 ret = xmlXPathCastToNumber(obj);
2376 else
2377 ret = obj->floatval;
2378 xmlXPathReleaseObject(ctxt->context, obj);
2379 return(ret);
2380}
2381
2382/**
2383 * xmlXPathPopString:
2384 * @ctxt: an XPath parser context
2385 *
2386 * Pops a string from the stack, handling conversion if needed.
2387 * Check error with #xmlXPathCheckError.
2388 *
2389 * Returns the string
2390 */
2391xmlChar *
2392xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2393 xmlXPathObjectPtr obj;
2394 xmlChar * ret;
2395
2396 obj = valuePop(ctxt);
2397 if (obj == NULL) {
2398 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2399 return(NULL);
2400 }
2401 ret = xmlXPathCastToString(obj); /* this does required strdup */
2402 /* TODO: needs refactoring somewhere else */
2403 if (obj->stringval == ret)
2404 obj->stringval = NULL;
2405 xmlXPathReleaseObject(ctxt->context, obj);
2406 return(ret);
2407}
2408
2409/**
2410 * xmlXPathPopNodeSet:
2411 * @ctxt: an XPath parser context
2412 *
2413 * Pops a node-set from the stack, handling conversion if needed.
2414 * Check error with #xmlXPathCheckError.
2415 *
2416 * Returns the node-set
2417 */
2418xmlNodeSetPtr
2419xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2420 xmlXPathObjectPtr obj;
2421 xmlNodeSetPtr ret;
2422
2423 if (ctxt == NULL) return(NULL);
2424 if (ctxt->value == NULL) {
2425 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2426 return(NULL);
2427 }
2428 if (!xmlXPathStackIsNodeSet(ctxt)) {
2429 xmlXPathSetTypeError(ctxt);
2430 return(NULL);
2431 }
2432 obj = valuePop(ctxt);
2433 ret = obj->nodesetval;
2434#if 0
2435 /* to fix memory leak of not clearing obj->user */
2436 if (obj->boolval && obj->user != NULL)
2437 xmlFreeNodeList((xmlNodePtr) obj->user);
2438#endif
2439 obj->nodesetval = NULL;
2440 xmlXPathReleaseObject(ctxt->context, obj);
2441 return(ret);
2442}
2443
2444/**
2445 * xmlXPathPopExternal:
2446 * @ctxt: an XPath parser context
2447 *
2448 * Pops an external object from the stack, handling conversion if needed.
2449 * Check error with #xmlXPathCheckError.
2450 *
2451 * Returns the object
2452 */
2453void *
2454xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2455 xmlXPathObjectPtr obj;
2456 void * ret;
2457
2458 if ((ctxt == NULL) || (ctxt->value == NULL)) {
2459 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2460 return(NULL);
2461 }
2462 if (ctxt->value->type != XPATH_USERS) {
2463 xmlXPathSetTypeError(ctxt);
2464 return(NULL);
2465 }
2466 obj = valuePop(ctxt);
2467 ret = obj->user;
2468 obj->user = NULL;
2469 xmlXPathReleaseObject(ctxt->context, obj);
2470 return(ret);
2471}
2472
2473/*
2474 * Macros for accessing the content. Those should be used only by the parser,
2475 * and not exported.
2476 *
2477 * Dirty macros, i.e. one need to make assumption on the context to use them
2478 *
2479 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2480 * CUR returns the current xmlChar value, i.e. a 8 bit value
2481 * in ISO-Latin or UTF-8.
2482 * This should be used internally by the parser
2483 * only to compare to ASCII values otherwise it would break when
2484 * running with UTF-8 encoding.
2485 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2486 * to compare on ASCII based substring.
2487 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2488 * strings within the parser.
2489 * CURRENT Returns the current char value, with the full decoding of
2490 * UTF-8 if we are using this mode. It returns an int.
2491 * NEXT Skip to the next character, this does the proper decoding
2492 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2493 * It returns the pointer to the current xmlChar.
2494 */
2495
2496#define CUR (*ctxt->cur)
2497#define SKIP(val) ctxt->cur += (val)
2498#define NXT(val) ctxt->cur[(val)]
2499#define CUR_PTR ctxt->cur
2500#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2501
2502#define COPY_BUF(l,b,i,v) \
2503 if (l == 1) b[i++] = v; \
2504 else i += xmlCopyChar(l,&b[i],v)
2505
2506#define NEXTL(l) ctxt->cur += l
2507
2508#define SKIP_BLANKS \
2509 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2510
2511#define CURRENT (*ctxt->cur)
2512#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2513
2514
2515#ifndef DBL_DIG
2516#define DBL_DIG 16
2517#endif
2518#ifndef DBL_EPSILON
2519#define DBL_EPSILON 1E-9
2520#endif
2521
2522#define UPPER_DOUBLE 1E9
2523#define LOWER_DOUBLE 1E-5
2524#define LOWER_DOUBLE_EXP 5
2525
2526#define INTEGER_DIGITS DBL_DIG
2527#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2528#define EXPONENT_DIGITS (3 + 2)
2529
2530/**
2531 * xmlXPathFormatNumber:
2532 * @number: number to format
2533 * @buffer: output buffer
2534 * @buffersize: size of output buffer
2535 *
2536 * Convert the number into a string representation.
2537 */
2538static void
2539xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2540{
2541 switch (xmlXPathIsInf(number)) {
2542 case 1:
2543 if (buffersize > (int)sizeof("Infinity"))
2544 snprintf(buffer, buffersize, "Infinity");
2545 break;
2546 case -1:
2547 if (buffersize > (int)sizeof("-Infinity"))
2548 snprintf(buffer, buffersize, "-Infinity");
2549 break;
2550 default:
2551 if (xmlXPathIsNaN(number)) {
2552 if (buffersize > (int)sizeof("NaN"))
2553 snprintf(buffer, buffersize, "NaN");
2554 } else if (number == 0) {
2555 /* Omit sign for negative zero. */
2556 snprintf(buffer, buffersize, "0");
2557 } else if ((number > INT_MIN) && (number < INT_MAX) &&
2558 (number == (int) number)) {
2559 char work[30];
2560 char *ptr, *cur;
2561 int value = (int) number;
2562
2563 ptr = &buffer[0];
2564 if (value == 0) {
2565 *ptr++ = '0';
2566 } else {
2567 snprintf(work, 29, "%d", value);
2568 cur = &work[0];
2569 while ((*cur) && (ptr - buffer < buffersize)) {
2570 *ptr++ = *cur++;
2571 }
2572 }
2573 if (ptr - buffer < buffersize) {
2574 *ptr = 0;
2575 } else if (buffersize > 0) {
2576 ptr--;
2577 *ptr = 0;
2578 }
2579 } else {
2580 /*
2581 For the dimension of work,
2582 DBL_DIG is number of significant digits
2583 EXPONENT is only needed for "scientific notation"
2584 3 is sign, decimal point, and terminating zero
2585 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2586 Note that this dimension is slightly (a few characters)
2587 larger than actually necessary.
2588 */
2589 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2590 int integer_place, fraction_place;
2591 char *ptr;
2592 char *after_fraction;
2593 double absolute_value;
2594 int size;
2595
2596 absolute_value = fabs(number);
2597
2598 /*
2599 * First choose format - scientific or regular floating point.
2600 * In either case, result is in work, and after_fraction points
2601 * just past the fractional part.
2602 */
2603 if ( ((absolute_value > UPPER_DOUBLE) ||
2604 (absolute_value < LOWER_DOUBLE)) &&
2605 (absolute_value != 0.0) ) {
2606 /* Use scientific notation */
2607 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2608 fraction_place = DBL_DIG - 1;
2609 size = snprintf(work, sizeof(work),"%*.*e",
2610 integer_place, fraction_place, number);
2611 while ((size > 0) && (work[size] != 'e')) size--;
2612
2613 }
2614 else {
2615 /* Use regular notation */
2616 if (absolute_value > 0.0) {
2617 integer_place = (int)log10(absolute_value);
2618 if (integer_place > 0)
2619 fraction_place = DBL_DIG - integer_place - 1;
2620 else
2621 fraction_place = DBL_DIG - integer_place;
2622 } else {
2623 fraction_place = 1;
2624 }
2625 size = snprintf(work, sizeof(work), "%0.*f",
2626 fraction_place, number);
2627 }
2628
2629 /* Remove leading spaces sometimes inserted by snprintf */
2630 while (work[0] == ' ') {
2631 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2632 size--;
2633 }
2634
2635 /* Remove fractional trailing zeroes */
2636 after_fraction = work + size;
2637 ptr = after_fraction;
2638 while (*(--ptr) == '0')
2639 ;
2640 if (*ptr != '.')
2641 ptr++;
2642 while ((*ptr++ = *after_fraction++) != 0);
2643
2644 /* Finally copy result back to caller */
2645 size = strlen(work) + 1;
2646 if (size > buffersize) {
2647 work[buffersize - 1] = 0;
2648 size = buffersize;
2649 }
2650 memmove(buffer, work, size);
2651 }
2652 break;
2653 }
2654}
2655
2656
2657/************************************************************************
2658 * *
2659 * Routines to handle NodeSets *
2660 * *
2661 ************************************************************************/
2662
2663/**
2664 * xmlXPathOrderDocElems:
2665 * @doc: an input document
2666 *
2667 * Call this routine to speed up XPath computation on static documents.
2668 * This stamps all the element nodes with the document order
2669 * Like for line information, the order is kept in the element->content
2670 * field, the value stored is actually - the node number (starting at -1)
2671 * to be able to differentiate from line numbers.
2672 *
2673 * Returns the number of elements found in the document or -1 in case
2674 * of error.
2675 */
2676long
2677xmlXPathOrderDocElems(xmlDocPtr doc) {
2678 ptrdiff_t count = 0;
2679 xmlNodePtr cur;
2680
2681 if (doc == NULL)
2682 return(-1);
2683 cur = doc->children;
2684 while (cur != NULL) {
2685 if (cur->type == XML_ELEMENT_NODE) {
2686 cur->content = (void *) (-(++count));
2687 if (cur->children != NULL) {
2688 cur = cur->children;
2689 continue;
2690 }
2691 }
2692 if (cur->next != NULL) {
2693 cur = cur->next;
2694 continue;
2695 }
2696 do {
2697 cur = cur->parent;
2698 if (cur == NULL)
2699 break;
2700 if (cur == (xmlNodePtr) doc) {
2701 cur = NULL;
2702 break;
2703 }
2704 if (cur->next != NULL) {
2705 cur = cur->next;
2706 break;
2707 }
2708 } while (cur != NULL);
2709 }
2710 return(count);
2711}
2712
2713/**
2714 * xmlXPathCmpNodes:
2715 * @node1: the first node
2716 * @node2: the second node
2717 *
2718 * Compare two nodes w.r.t document order
2719 *
2720 * Returns -2 in case of error 1 if first point < second point, 0 if
2721 * it's the same node, -1 otherwise
2722 */
2723int
2724xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2725 int depth1, depth2;
2726 int attr1 = 0, attr2 = 0;
2727 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2728 xmlNodePtr cur, root;
2729
2730 if ((node1 == NULL) || (node2 == NULL))
2731 return(-2);
2732 /*
2733 * a couple of optimizations which will avoid computations in most cases
2734 */
2735 if (node1 == node2) /* trivial case */
2736 return(0);
2737 if (node1->type == XML_ATTRIBUTE_NODE) {
2738 attr1 = 1;
2739 attrNode1 = node1;
2740 node1 = node1->parent;
2741 }
2742 if (node2->type == XML_ATTRIBUTE_NODE) {
2743 attr2 = 1;
2744 attrNode2 = node2;
2745 node2 = node2->parent;
2746 }
2747 if (node1 == node2) {
2748 if (attr1 == attr2) {
2749 /* not required, but we keep attributes in order */
2750 if (attr1 != 0) {
2751 cur = attrNode2->prev;
2752 while (cur != NULL) {
2753 if (cur == attrNode1)
2754 return (1);
2755 cur = cur->prev;
2756 }
2757 return (-1);
2758 }
2759 return(0);
2760 }
2761 if (attr2 == 1)
2762 return(1);
2763 return(-1);
2764 }
2765 if ((node1->type == XML_NAMESPACE_DECL) ||
2766 (node2->type == XML_NAMESPACE_DECL))
2767 return(1);
2768 if (node1 == node2->prev)
2769 return(1);
2770 if (node1 == node2->next)
2771 return(-1);
2772
2773 /*
2774 * Speedup using document order if available.
2775 */
2776 if ((node1->type == XML_ELEMENT_NODE) &&
2777 (node2->type == XML_ELEMENT_NODE) &&
2778 (0 > (ptrdiff_t) node1->content) &&
2779 (0 > (ptrdiff_t) node2->content) &&
2780 (node1->doc == node2->doc)) {
2781 ptrdiff_t l1, l2;
2782
2783 l1 = -((ptrdiff_t) node1->content);
2784 l2 = -((ptrdiff_t) node2->content);
2785 if (l1 < l2)
2786 return(1);
2787 if (l1 > l2)
2788 return(-1);
2789 }
2790
2791 /*
2792 * compute depth to root
2793 */
2794 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2795 if (cur->parent == node1)
2796 return(1);
2797 depth2++;
2798 }
2799 root = cur;
2800 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2801 if (cur->parent == node2)
2802 return(-1);
2803 depth1++;
2804 }
2805 /*
2806 * Distinct document (or distinct entities :-( ) case.
2807 */
2808 if (root != cur) {
2809 return(-2);
2810 }
2811 /*
2812 * get the nearest common ancestor.
2813 */
2814 while (depth1 > depth2) {
2815 depth1--;
2816 node1 = node1->parent;
2817 }
2818 while (depth2 > depth1) {
2819 depth2--;
2820 node2 = node2->parent;
2821 }
2822 while (node1->parent != node2->parent) {
2823 node1 = node1->parent;
2824 node2 = node2->parent;
2825 /* should not happen but just in case ... */
2826 if ((node1 == NULL) || (node2 == NULL))
2827 return(-2);
2828 }
2829 /*
2830 * Find who's first.
2831 */
2832 if (node1 == node2->prev)
2833 return(1);
2834 if (node1 == node2->next)
2835 return(-1);
2836 /*
2837 * Speedup using document order if available.
2838 */
2839 if ((node1->type == XML_ELEMENT_NODE) &&
2840 (node2->type == XML_ELEMENT_NODE) &&
2841 (0 > (ptrdiff_t) node1->content) &&
2842 (0 > (ptrdiff_t) node2->content) &&
2843 (node1->doc == node2->doc)) {
2844 ptrdiff_t l1, l2;
2845
2846 l1 = -((ptrdiff_t) node1->content);
2847 l2 = -((ptrdiff_t) node2->content);
2848 if (l1 < l2)
2849 return(1);
2850 if (l1 > l2)
2851 return(-1);
2852 }
2853
2854 for (cur = node1->next;cur != NULL;cur = cur->next)
2855 if (cur == node2)
2856 return(1);
2857 return(-1); /* assume there is no sibling list corruption */
2858}
2859
2860/**
2861 * xmlXPathNodeSetSort:
2862 * @set: the node set
2863 *
2864 * Sort the node set in document order
2865 */
2866void
2867xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2868#ifndef WITH_TIM_SORT
2869 int i, j, incr, len;
2870 xmlNodePtr tmp;
2871#endif
2872
2873 if (set == NULL)
2874 return;
2875
2876#ifndef WITH_TIM_SORT
2877 /*
2878 * Use the old Shell's sort implementation to sort the node-set
2879 * Timsort ought to be quite faster
2880 */
2881 len = set->nodeNr;
2882 for (incr = len / 2; incr > 0; incr /= 2) {
2883 for (i = incr; i < len; i++) {
2884 j = i - incr;
2885 while (j >= 0) {
2886#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2887 if (xmlXPathCmpNodesExt(set->nodeTab[j],
2888 set->nodeTab[j + incr]) == -1)
2889#else
2890 if (xmlXPathCmpNodes(set->nodeTab[j],
2891 set->nodeTab[j + incr]) == -1)
2892#endif
2893 {
2894 tmp = set->nodeTab[j];
2895 set->nodeTab[j] = set->nodeTab[j + incr];
2896 set->nodeTab[j + incr] = tmp;
2897 j -= incr;
2898 } else
2899 break;
2900 }
2901 }
2902 }
2903#else /* WITH_TIM_SORT */
2904 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2905#endif /* WITH_TIM_SORT */
2906}
2907
2908#define XML_NODESET_DEFAULT 10
2909/**
2910 * xmlXPathNodeSetDupNs:
2911 * @node: the parent node of the namespace XPath node
2912 * @ns: the libxml namespace declaration node.
2913 *
2914 * Namespace node in libxml don't match the XPath semantic. In a node set
2915 * the namespace nodes are duplicated and the next pointer is set to the
2916 * parent node in the XPath semantic.
2917 *
2918 * Returns the newly created object.
2919 */
2920static xmlNodePtr
2921xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2922 xmlNsPtr cur;
2923
2924 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2925 return(NULL);
2926 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2927 return((xmlNodePtr) ns);
2928
2929 /*
2930 * Allocate a new Namespace and fill the fields.
2931 */
2932 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2933 if (cur == NULL) {
2934 xmlXPathErrMemory(NULL, "duplicating namespace\n");
2935 return(NULL);
2936 }
2937 memset(cur, 0, sizeof(xmlNs));
2938 cur->type = XML_NAMESPACE_DECL;
2939 if (ns->href != NULL)
2940 cur->href = xmlStrdup(ns->href);
2941 if (ns->prefix != NULL)
2942 cur->prefix = xmlStrdup(ns->prefix);
2943 cur->next = (xmlNsPtr) node;
2944 return((xmlNodePtr) cur);
2945}
2946
2947/**
2948 * xmlXPathNodeSetFreeNs:
2949 * @ns: the XPath namespace node found in a nodeset.
2950 *
2951 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2952 * the namespace nodes are duplicated and the next pointer is set to the
2953 * parent node in the XPath semantic. Check if such a node needs to be freed
2954 */
2955void
2956xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2957 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2958 return;
2959
2960 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2961 if (ns->href != NULL)
2962 xmlFree((xmlChar *)ns->href);
2963 if (ns->prefix != NULL)
2964 xmlFree((xmlChar *)ns->prefix);
2965 xmlFree(ns);
2966 }
2967}
2968
2969/**
2970 * xmlXPathNodeSetCreate:
2971 * @val: an initial xmlNodePtr, or NULL
2972 *
2973 * Create a new xmlNodeSetPtr of type double and of value @val
2974 *
2975 * Returns the newly created object.
2976 */
2977xmlNodeSetPtr
2978xmlXPathNodeSetCreate(xmlNodePtr val) {
2979 xmlNodeSetPtr ret;
2980
2981 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2982 if (ret == NULL) {
2983 xmlXPathErrMemory(NULL, "creating nodeset\n");
2984 return(NULL);
2985 }
2986 memset(ret, 0 , sizeof(xmlNodeSet));
2987 if (val != NULL) {
2988 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2989 sizeof(xmlNodePtr));
2990 if (ret->nodeTab == NULL) {
2991 xmlXPathErrMemory(NULL, "creating nodeset\n");
2992 xmlFree(ret);
2993 return(NULL);
2994 }
2995 memset(ret->nodeTab, 0 ,
2996 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2997 ret->nodeMax = XML_NODESET_DEFAULT;
2998 if (val->type == XML_NAMESPACE_DECL) {
2999 xmlNsPtr ns = (xmlNsPtr) val;
3000 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3001
3002 if (nsNode == NULL) {
3003 xmlXPathFreeNodeSet(ret);
3004 return(NULL);
3005 }
3006 ret->nodeTab[ret->nodeNr++] = nsNode;
3007 } else
3008 ret->nodeTab[ret->nodeNr++] = val;
3009 }
3010 return(ret);
3011}
3012
3013/**
3014 * xmlXPathNodeSetContains:
3015 * @cur: the node-set
3016 * @val: the node
3017 *
3018 * checks whether @cur contains @val
3019 *
3020 * Returns true (1) if @cur contains @val, false (0) otherwise
3021 */
3022int
3023xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3024 int i;
3025
3026 if ((cur == NULL) || (val == NULL)) return(0);
3027 if (val->type == XML_NAMESPACE_DECL) {
3028 for (i = 0; i < cur->nodeNr; i++) {
3029 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3030 xmlNsPtr ns1, ns2;
3031
3032 ns1 = (xmlNsPtr) val;
3033 ns2 = (xmlNsPtr) cur->nodeTab[i];
3034 if (ns1 == ns2)
3035 return(1);
3036 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3037 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3038 return(1);
3039 }
3040 }
3041 } else {
3042 for (i = 0; i < cur->nodeNr; i++) {
3043 if (cur->nodeTab[i] == val)
3044 return(1);
3045 }
3046 }
3047 return(0);
3048}
3049
3050/**
3051 * xmlXPathNodeSetAddNs:
3052 * @cur: the initial node set
3053 * @node: the hosting node
3054 * @ns: a the namespace node
3055 *
3056 * add a new namespace node to an existing NodeSet
3057 *
3058 * Returns 0 in case of success and -1 in case of error
3059 */
3060int
3061xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3062 int i;
3063 xmlNodePtr nsNode;
3064
3065 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3066 (ns->type != XML_NAMESPACE_DECL) ||
3067 (node->type != XML_ELEMENT_NODE))
3068 return(-1);
3069
3070 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3071 /*
3072 * prevent duplicates
3073 */
3074 for (i = 0;i < cur->nodeNr;i++) {
3075 if ((cur->nodeTab[i] != NULL) &&
3076 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3077 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3078 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3079 return(0);
3080 }
3081
3082 /*
3083 * grow the nodeTab if needed
3084 */
3085 if (cur->nodeMax == 0) {
3086 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3087 sizeof(xmlNodePtr));
3088 if (cur->nodeTab == NULL) {
3089 xmlXPathErrMemory(NULL, "growing nodeset\n");
3090 return(-1);
3091 }
3092 memset(cur->nodeTab, 0 ,
3093 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3094 cur->nodeMax = XML_NODESET_DEFAULT;
3095 } else if (cur->nodeNr == cur->nodeMax) {
3096 xmlNodePtr *temp;
3097
3098 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3099 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3100 return(-1);
3101 }
3102 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3103 sizeof(xmlNodePtr));
3104 if (temp == NULL) {
3105 xmlXPathErrMemory(NULL, "growing nodeset\n");
3106 return(-1);
3107 }
3108 cur->nodeMax *= 2;
3109 cur->nodeTab = temp;
3110 }
3111 nsNode = xmlXPathNodeSetDupNs(node, ns);
3112 if(nsNode == NULL)
3113 return(-1);
3114 cur->nodeTab[cur->nodeNr++] = nsNode;
3115 return(0);
3116}
3117
3118/**
3119 * xmlXPathNodeSetAdd:
3120 * @cur: the initial node set
3121 * @val: a new xmlNodePtr
3122 *
3123 * add a new xmlNodePtr to an existing NodeSet
3124 *
3125 * Returns 0 in case of success, and -1 in case of error
3126 */
3127int
3128xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3129 int i;
3130
3131 if ((cur == NULL) || (val == NULL)) return(-1);
3132
3133 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3134 /*
3135 * prevent duplicates
3136 */
3137 for (i = 0;i < cur->nodeNr;i++)
3138 if (cur->nodeTab[i] == val) return(0);
3139
3140 /*
3141 * grow the nodeTab if needed
3142 */
3143 if (cur->nodeMax == 0) {
3144 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3145 sizeof(xmlNodePtr));
3146 if (cur->nodeTab == NULL) {
3147 xmlXPathErrMemory(NULL, "growing nodeset\n");
3148 return(-1);
3149 }
3150 memset(cur->nodeTab, 0 ,
3151 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3152 cur->nodeMax = XML_NODESET_DEFAULT;
3153 } else if (cur->nodeNr == cur->nodeMax) {
3154 xmlNodePtr *temp;
3155
3156 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3157 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3158 return(-1);
3159 }
3160 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3161 sizeof(xmlNodePtr));
3162 if (temp == NULL) {
3163 xmlXPathErrMemory(NULL, "growing nodeset\n");
3164 return(-1);
3165 }
3166 cur->nodeMax *= 2;
3167 cur->nodeTab = temp;
3168 }
3169 if (val->type == XML_NAMESPACE_DECL) {
3170 xmlNsPtr ns = (xmlNsPtr) val;
3171 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3172
3173 if (nsNode == NULL)
3174 return(-1);
3175 cur->nodeTab[cur->nodeNr++] = nsNode;
3176 } else
3177 cur->nodeTab[cur->nodeNr++] = val;
3178 return(0);
3179}
3180
3181/**
3182 * xmlXPathNodeSetAddUnique:
3183 * @cur: the initial node set
3184 * @val: a new xmlNodePtr
3185 *
3186 * add a new xmlNodePtr to an existing NodeSet, optimized version
3187 * when we are sure the node is not already in the set.
3188 *
3189 * Returns 0 in case of success and -1 in case of failure
3190 */
3191int
3192xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3193 if ((cur == NULL) || (val == NULL)) return(-1);
3194
3195 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3196 /*
3197 * grow the nodeTab if needed
3198 */
3199 if (cur->nodeMax == 0) {
3200 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3201 sizeof(xmlNodePtr));
3202 if (cur->nodeTab == NULL) {
3203 xmlXPathErrMemory(NULL, "growing nodeset\n");
3204 return(-1);
3205 }
3206 memset(cur->nodeTab, 0 ,
3207 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3208 cur->nodeMax = XML_NODESET_DEFAULT;
3209 } else if (cur->nodeNr == cur->nodeMax) {
3210 xmlNodePtr *temp;
3211
3212 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3213 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3214 return(-1);
3215 }
3216 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3217 sizeof(xmlNodePtr));
3218 if (temp == NULL) {
3219 xmlXPathErrMemory(NULL, "growing nodeset\n");
3220 return(-1);
3221 }
3222 cur->nodeTab = temp;
3223 cur->nodeMax *= 2;
3224 }
3225 if (val->type == XML_NAMESPACE_DECL) {
3226 xmlNsPtr ns = (xmlNsPtr) val;
3227 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3228
3229 if (nsNode == NULL)
3230 return(-1);
3231 cur->nodeTab[cur->nodeNr++] = nsNode;
3232 } else
3233 cur->nodeTab[cur->nodeNr++] = val;
3234 return(0);
3235}
3236
3237/**
3238 * xmlXPathNodeSetMerge:
3239 * @val1: the first NodeSet or NULL
3240 * @val2: the second NodeSet
3241 *
3242 * Merges two nodesets, all nodes from @val2 are added to @val1
3243 * if @val1 is NULL, a new set is created and copied from @val2
3244 *
3245 * Returns @val1 once extended or NULL in case of error.
3246 *
3247 * Frees @val1 in case of error.
3248 */
3249xmlNodeSetPtr
3250xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3251 int i, j, initNr, skip;
3252 xmlNodePtr n1, n2;
3253
3254 if (val2 == NULL) return(val1);
3255 if (val1 == NULL) {
3256 val1 = xmlXPathNodeSetCreate(NULL);
3257 if (val1 == NULL)
3258 return (NULL);
3259 }
3260
3261 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3262 initNr = val1->nodeNr;
3263
3264 for (i = 0;i < val2->nodeNr;i++) {
3265 n2 = val2->nodeTab[i];
3266 /*
3267 * check against duplicates
3268 */
3269 skip = 0;
3270 for (j = 0; j < initNr; j++) {
3271 n1 = val1->nodeTab[j];
3272 if (n1 == n2) {
3273 skip = 1;
3274 break;
3275 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3276 (n2->type == XML_NAMESPACE_DECL)) {
3277 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3278 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3279 ((xmlNsPtr) n2)->prefix)))
3280 {
3281 skip = 1;
3282 break;
3283 }
3284 }
3285 }
3286 if (skip)
3287 continue;
3288
3289 /*
3290 * grow the nodeTab if needed
3291 */
3292 if (val1->nodeMax == 0) {
3293 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3294 sizeof(xmlNodePtr));
3295 if (val1->nodeTab == NULL) {
3296 xmlXPathErrMemory(NULL, "merging nodeset\n");
3297 goto error;
3298 }
3299 memset(val1->nodeTab, 0 ,
3300 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3301 val1->nodeMax = XML_NODESET_DEFAULT;
3302 } else if (val1->nodeNr == val1->nodeMax) {
3303 xmlNodePtr *temp;
3304
3305 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3306 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3307 goto error;
3308 }
3309 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3310 sizeof(xmlNodePtr));
3311 if (temp == NULL) {
3312 xmlXPathErrMemory(NULL, "merging nodeset\n");
3313 goto error;
3314 }
3315 val1->nodeTab = temp;
3316 val1->nodeMax *= 2;
3317 }
3318 if (n2->type == XML_NAMESPACE_DECL) {
3319 xmlNsPtr ns = (xmlNsPtr) n2;
3320 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3321
3322 if (nsNode == NULL)
3323 goto error;
3324 val1->nodeTab[val1->nodeNr++] = nsNode;
3325 } else
3326 val1->nodeTab[val1->nodeNr++] = n2;
3327 }
3328
3329 return(val1);
3330
3331error:
3332 xmlXPathFreeNodeSet(val1);
3333 return(NULL);
3334}
3335
3336
3337/**
3338 * xmlXPathNodeSetMergeAndClear:
3339 * @set1: the first NodeSet or NULL
3340 * @set2: the second NodeSet
3341 *
3342 * Merges two nodesets, all nodes from @set2 are added to @set1.
3343 * Checks for duplicate nodes. Clears set2.
3344 *
3345 * Returns @set1 once extended or NULL in case of error.
3346 *
3347 * Frees @set1 in case of error.
3348 */
3349static xmlNodeSetPtr
3350xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3351{
3352 {
3353 int i, j, initNbSet1;
3354 xmlNodePtr n1, n2;
3355
3356 initNbSet1 = set1->nodeNr;
3357 for (i = 0;i < set2->nodeNr;i++) {
3358 n2 = set2->nodeTab[i];
3359 /*
3360 * Skip duplicates.
3361 */
3362 for (j = 0; j < initNbSet1; j++) {
3363 n1 = set1->nodeTab[j];
3364 if (n1 == n2) {
3365 goto skip_node;
3366 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3367 (n2->type == XML_NAMESPACE_DECL))
3368 {
3369 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3370 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3371 ((xmlNsPtr) n2)->prefix)))
3372 {
3373 /*
3374 * Free the namespace node.
3375 */
3376 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3377 goto skip_node;
3378 }
3379 }
3380 }
3381 /*
3382 * grow the nodeTab if needed
3383 */
3384 if (set1->nodeMax == 0) {
3385 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3386 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3387 if (set1->nodeTab == NULL) {
3388 xmlXPathErrMemory(NULL, "merging nodeset\n");
3389 goto error;
3390 }
3391 memset(set1->nodeTab, 0,
3392 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3393 set1->nodeMax = XML_NODESET_DEFAULT;
3394 } else if (set1->nodeNr >= set1->nodeMax) {
3395 xmlNodePtr *temp;
3396
3397 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3398 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3399 goto error;
3400 }
3401 temp = (xmlNodePtr *) xmlRealloc(
3402 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3403 if (temp == NULL) {
3404 xmlXPathErrMemory(NULL, "merging nodeset\n");
3405 goto error;
3406 }
3407 set1->nodeTab = temp;
3408 set1->nodeMax *= 2;
3409 }
3410 set1->nodeTab[set1->nodeNr++] = n2;
3411skip_node:
3412 set2->nodeTab[i] = NULL;
3413 }
3414 }
3415 set2->nodeNr = 0;
3416 return(set1);
3417
3418error:
3419 xmlXPathFreeNodeSet(set1);
3420 xmlXPathNodeSetClear(set2, 1);
3421 return(NULL);
3422}
3423
3424/**
3425 * xmlXPathNodeSetMergeAndClearNoDupls:
3426 * @set1: the first NodeSet or NULL
3427 * @set2: the second NodeSet
3428 *
3429 * Merges two nodesets, all nodes from @set2 are added to @set1.
3430 * Doesn't check for duplicate nodes. Clears set2.
3431 *
3432 * Returns @set1 once extended or NULL in case of error.
3433 *
3434 * Frees @set1 in case of error.
3435 */
3436static xmlNodeSetPtr
3437xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3438{
3439 {
3440 int i;
3441 xmlNodePtr n2;
3442
3443 for (i = 0;i < set2->nodeNr;i++) {
3444 n2 = set2->nodeTab[i];
3445 if (set1->nodeMax == 0) {
3446 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3447 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3448 if (set1->nodeTab == NULL) {
3449 xmlXPathErrMemory(NULL, "merging nodeset\n");
3450 goto error;
3451 }
3452 memset(set1->nodeTab, 0,
3453 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3454 set1->nodeMax = XML_NODESET_DEFAULT;
3455 } else if (set1->nodeNr >= set1->nodeMax) {
3456 xmlNodePtr *temp;
3457
3458 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3459 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3460 goto error;
3461 }
3462 temp = (xmlNodePtr *) xmlRealloc(
3463 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3464 if (temp == NULL) {
3465 xmlXPathErrMemory(NULL, "merging nodeset\n");
3466 goto error;
3467 }
3468 set1->nodeTab = temp;
3469 set1->nodeMax *= 2;
3470 }
3471 set1->nodeTab[set1->nodeNr++] = n2;
3472 set2->nodeTab[i] = NULL;
3473 }
3474 }
3475 set2->nodeNr = 0;
3476 return(set1);
3477
3478error:
3479 xmlXPathFreeNodeSet(set1);
3480 xmlXPathNodeSetClear(set2, 1);
3481 return(NULL);
3482}
3483
3484/**
3485 * xmlXPathNodeSetDel:
3486 * @cur: the initial node set
3487 * @val: an xmlNodePtr
3488 *
3489 * Removes an xmlNodePtr from an existing NodeSet
3490 */
3491void
3492xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3493 int i;
3494
3495 if (cur == NULL) return;
3496 if (val == NULL) return;
3497
3498 /*
3499 * find node in nodeTab
3500 */
3501 for (i = 0;i < cur->nodeNr;i++)
3502 if (cur->nodeTab[i] == val) break;
3503
3504 if (i >= cur->nodeNr) { /* not found */
3505 return;
3506 }
3507 if ((cur->nodeTab[i] != NULL) &&
3508 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3509 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3510 cur->nodeNr--;
3511 for (;i < cur->nodeNr;i++)
3512 cur->nodeTab[i] = cur->nodeTab[i + 1];
3513 cur->nodeTab[cur->nodeNr] = NULL;
3514}
3515
3516/**
3517 * xmlXPathNodeSetRemove:
3518 * @cur: the initial node set
3519 * @val: the index to remove
3520 *
3521 * Removes an entry from an existing NodeSet list.
3522 */
3523void
3524xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3525 if (cur == NULL) return;
3526 if (val >= cur->nodeNr) return;
3527 if ((cur->nodeTab[val] != NULL) &&
3528 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3529 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3530 cur->nodeNr--;
3531 for (;val < cur->nodeNr;val++)
3532 cur->nodeTab[val] = cur->nodeTab[val + 1];
3533 cur->nodeTab[cur->nodeNr] = NULL;
3534}
3535
3536/**
3537 * xmlXPathFreeNodeSet:
3538 * @obj: the xmlNodeSetPtr to free
3539 *
3540 * Free the NodeSet compound (not the actual nodes !).
3541 */
3542void
3543xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3544 if (obj == NULL) return;
3545 if (obj->nodeTab != NULL) {
3546 int i;
3547
3548 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3549 for (i = 0;i < obj->nodeNr;i++)
3550 if ((obj->nodeTab[i] != NULL) &&
3551 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3552 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3553 xmlFree(obj->nodeTab);
3554 }
3555 xmlFree(obj);
3556}
3557
3558/**
3559 * xmlXPathNodeSetClearFromPos:
3560 * @set: the node set to be cleared
3561 * @pos: the start position to clear from
3562 *
3563 * Clears the list from temporary XPath objects (e.g. namespace nodes
3564 * are feed) starting with the entry at @pos, but does *not* free the list
3565 * itself. Sets the length of the list to @pos.
3566 */
3567static void
3568xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3569{
3570 if ((set == NULL) || (pos >= set->nodeNr))
3571 return;
3572 else if ((hasNsNodes)) {
3573 int i;
3574 xmlNodePtr node;
3575
3576 for (i = pos; i < set->nodeNr; i++) {
3577 node = set->nodeTab[i];
3578 if ((node != NULL) &&
3579 (node->type == XML_NAMESPACE_DECL))
3580 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3581 }
3582 }
3583 set->nodeNr = pos;
3584}
3585
3586/**
3587 * xmlXPathNodeSetClear:
3588 * @set: the node set to clear
3589 *
3590 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3591 * are feed), but does *not* free the list itself. Sets the length of the
3592 * list to 0.
3593 */
3594static void
3595xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3596{
3597 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3598}
3599
3600/**
3601 * xmlXPathNodeSetKeepLast:
3602 * @set: the node set to be cleared
3603 *
3604 * Move the last node to the first position and clear temporary XPath objects
3605 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3606 * to 1.
3607 */
3608static void
3609xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3610{
3611 int i;
3612 xmlNodePtr node;
3613
3614 if ((set == NULL) || (set->nodeNr <= 1))
3615 return;
3616 for (i = 0; i < set->nodeNr - 1; i++) {
3617 node = set->nodeTab[i];
3618 if ((node != NULL) &&
3619 (node->type == XML_NAMESPACE_DECL))
3620 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3621 }
3622 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3623 set->nodeNr = 1;
3624}
3625
3626/**
3627 * xmlXPathFreeValueTree:
3628 * @obj: the xmlNodeSetPtr to free
3629 *
3630 * Free the NodeSet compound and the actual tree, this is different
3631 * from xmlXPathFreeNodeSet()
3632 */
3633static void
3634xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
3635 int i;
3636
3637 if (obj == NULL) return;
3638
3639 if (obj->nodeTab != NULL) {
3640 for (i = 0;i < obj->nodeNr;i++) {
3641 if (obj->nodeTab[i] != NULL) {
3642 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3643 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3644 } else {
3645 xmlFreeNodeList(obj->nodeTab[i]);
3646 }
3647 }
3648 }
3649 xmlFree(obj->nodeTab);
3650 }
3651 xmlFree(obj);
3652}
3653
3654/**
3655 * xmlXPathNewNodeSet:
3656 * @val: the NodePtr value
3657 *
3658 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3659 * it with the single Node @val
3660 *
3661 * Returns the newly created object.
3662 */
3663xmlXPathObjectPtr
3664xmlXPathNewNodeSet(xmlNodePtr val) {
3665 xmlXPathObjectPtr ret;
3666
3667 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3668 if (ret == NULL) {
3669 xmlXPathErrMemory(NULL, "creating nodeset\n");
3670 return(NULL);
3671 }
3672 memset(ret, 0 , sizeof(xmlXPathObject));
3673 ret->type = XPATH_NODESET;
3674 ret->boolval = 0;
3675 /* TODO: Check memory error. */
3676 ret->nodesetval = xmlXPathNodeSetCreate(val);
3677 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3678 return(ret);
3679}
3680
3681/**
3682 * xmlXPathNewValueTree:
3683 * @val: the NodePtr value
3684 *
3685 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3686 * it with the tree root @val
3687 *
3688 * Returns the newly created object.
3689 */
3690xmlXPathObjectPtr
3691xmlXPathNewValueTree(xmlNodePtr val) {
3692 xmlXPathObjectPtr ret;
3693
3694 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3695 if (ret == NULL) {
3696 xmlXPathErrMemory(NULL, "creating result value tree\n");
3697 return(NULL);
3698 }
3699 memset(ret, 0 , sizeof(xmlXPathObject));
3700 ret->type = XPATH_XSLT_TREE;
3701 ret->boolval = 1;
3702 ret->user = (void *) val;
3703 ret->nodesetval = xmlXPathNodeSetCreate(val);
3704 return(ret);
3705}
3706
3707/**
3708 * xmlXPathNewNodeSetList:
3709 * @val: an existing NodeSet
3710 *
3711 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3712 * it with the Nodeset @val
3713 *
3714 * Returns the newly created object.
3715 */
3716xmlXPathObjectPtr
3717xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3718{
3719 xmlXPathObjectPtr ret;
3720 int i;
3721
3722 if (val == NULL)
3723 ret = NULL;
3724 else if (val->nodeTab == NULL)
3725 ret = xmlXPathNewNodeSet(NULL);
3726 else {
3727 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3728 if (ret) {
3729 for (i = 1; i < val->nodeNr; ++i) {
3730 /* TODO: Propagate memory error. */
3731 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
3732 < 0) break;
3733 }
3734 }
3735 }
3736
3737 return (ret);
3738}
3739
3740/**
3741 * xmlXPathWrapNodeSet:
3742 * @val: the NodePtr value
3743 *
3744 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3745 *
3746 * Returns the newly created object.
3747 *
3748 * In case of error the node set is destroyed and NULL is returned.
3749 */
3750xmlXPathObjectPtr
3751xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3752 xmlXPathObjectPtr ret;
3753
3754 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3755 if (ret == NULL) {
3756 xmlXPathErrMemory(NULL, "creating node set object\n");
3757 xmlXPathFreeNodeSet(val);
3758 return(NULL);
3759 }
3760 memset(ret, 0 , sizeof(xmlXPathObject));
3761 ret->type = XPATH_NODESET;
3762 ret->nodesetval = val;
3763 return(ret);
3764}
3765
3766/**
3767 * xmlXPathFreeNodeSetList:
3768 * @obj: an existing NodeSetList object
3769 *
3770 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3771 * the list contrary to xmlXPathFreeObject().
3772 */
3773void
3774xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3775 if (obj == NULL) return;
3776 xmlFree(obj);
3777}
3778
3779/**
3780 * xmlXPathDifference:
3781 * @nodes1: a node-set
3782 * @nodes2: a node-set
3783 *
3784 * Implements the EXSLT - Sets difference() function:
3785 * node-set set:difference (node-set, node-set)
3786 *
3787 * Returns the difference between the two node sets, or nodes1 if
3788 * nodes2 is empty
3789 */
3790xmlNodeSetPtr
3791xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3792 xmlNodeSetPtr ret;
3793 int i, l1;
3794 xmlNodePtr cur;
3795
3796 if (xmlXPathNodeSetIsEmpty(nodes2))
3797 return(nodes1);
3798
3799 /* TODO: Check memory error. */
3800 ret = xmlXPathNodeSetCreate(NULL);
3801 if (xmlXPathNodeSetIsEmpty(nodes1))
3802 return(ret);
3803
3804 l1 = xmlXPathNodeSetGetLength(nodes1);
3805
3806 for (i = 0; i < l1; i++) {
3807 cur = xmlXPathNodeSetItem(nodes1, i);
3808 if (!xmlXPathNodeSetContains(nodes2, cur)) {
3809 /* TODO: Propagate memory error. */
3810 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3811 break;
3812 }
3813 }
3814 return(ret);
3815}
3816
3817/**
3818 * xmlXPathIntersection:
3819 * @nodes1: a node-set
3820 * @nodes2: a node-set
3821 *
3822 * Implements the EXSLT - Sets intersection() function:
3823 * node-set set:intersection (node-set, node-set)
3824 *
3825 * Returns a node set comprising the nodes that are within both the
3826 * node sets passed as arguments
3827 */
3828xmlNodeSetPtr
3829xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3830 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3831 int i, l1;
3832 xmlNodePtr cur;
3833
3834 if (ret == NULL)
3835 return(ret);
3836 if (xmlXPathNodeSetIsEmpty(nodes1))
3837 return(ret);
3838 if (xmlXPathNodeSetIsEmpty(nodes2))
3839 return(ret);
3840
3841 l1 = xmlXPathNodeSetGetLength(nodes1);
3842
3843 for (i = 0; i < l1; i++) {
3844 cur = xmlXPathNodeSetItem(nodes1, i);
3845 if (xmlXPathNodeSetContains(nodes2, cur)) {
3846 /* TODO: Propagate memory error. */
3847 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3848 break;
3849 }
3850 }
3851 return(ret);
3852}
3853
3854/**
3855 * xmlXPathDistinctSorted:
3856 * @nodes: a node-set, sorted by document order
3857 *
3858 * Implements the EXSLT - Sets distinct() function:
3859 * node-set set:distinct (node-set)
3860 *
3861 * Returns a subset of the nodes contained in @nodes, or @nodes if
3862 * it is empty
3863 */
3864xmlNodeSetPtr
3865xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3866 xmlNodeSetPtr ret;
3867 xmlHashTablePtr hash;
3868 int i, l;
3869 xmlChar * strval;
3870 xmlNodePtr cur;
3871
3872 if (xmlXPathNodeSetIsEmpty(nodes))
3873 return(nodes);
3874
3875 ret = xmlXPathNodeSetCreate(NULL);
3876 if (ret == NULL)
3877 return(ret);
3878 l = xmlXPathNodeSetGetLength(nodes);
3879 hash = xmlHashCreate (l);
3880 for (i = 0; i < l; i++) {
3881 cur = xmlXPathNodeSetItem(nodes, i);
3882 strval = xmlXPathCastNodeToString(cur);
3883 if (xmlHashLookup(hash, strval) == NULL) {
3884 if (xmlHashAddEntry(hash, strval, strval) < 0) {
3885 xmlFree(strval);
3886 goto error;
3887 }
3888 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3889 goto error;
3890 } else {
3891 xmlFree(strval);
3892 }
3893 }
3894 xmlHashFree(hash, xmlHashDefaultDeallocator);
3895 return(ret);
3896
3897error:
3898 xmlHashFree(hash, xmlHashDefaultDeallocator);
3899 xmlXPathFreeNodeSet(ret);
3900 return(NULL);
3901}
3902
3903/**
3904 * xmlXPathDistinct:
3905 * @nodes: a node-set
3906 *
3907 * Implements the EXSLT - Sets distinct() function:
3908 * node-set set:distinct (node-set)
3909 * @nodes is sorted by document order, then #exslSetsDistinctSorted
3910 * is called with the sorted node-set
3911 *
3912 * Returns a subset of the nodes contained in @nodes, or @nodes if
3913 * it is empty
3914 */
3915xmlNodeSetPtr
3916xmlXPathDistinct (xmlNodeSetPtr nodes) {
3917 if (xmlXPathNodeSetIsEmpty(nodes))
3918 return(nodes);
3919
3920 xmlXPathNodeSetSort(nodes);
3921 return(xmlXPathDistinctSorted(nodes));
3922}
3923
3924/**
3925 * xmlXPathHasSameNodes:
3926 * @nodes1: a node-set
3927 * @nodes2: a node-set
3928 *
3929 * Implements the EXSLT - Sets has-same-nodes function:
3930 * boolean set:has-same-node(node-set, node-set)
3931 *
3932 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3933 * otherwise
3934 */
3935int
3936xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3937 int i, l;
3938 xmlNodePtr cur;
3939
3940 if (xmlXPathNodeSetIsEmpty(nodes1) ||
3941 xmlXPathNodeSetIsEmpty(nodes2))
3942 return(0);
3943
3944 l = xmlXPathNodeSetGetLength(nodes1);
3945 for (i = 0; i < l; i++) {
3946 cur = xmlXPathNodeSetItem(nodes1, i);
3947 if (xmlXPathNodeSetContains(nodes2, cur))
3948 return(1);
3949 }
3950 return(0);
3951}
3952
3953/**
3954 * xmlXPathNodeLeadingSorted:
3955 * @nodes: a node-set, sorted by document order
3956 * @node: a node
3957 *
3958 * Implements the EXSLT - Sets leading() function:
3959 * node-set set:leading (node-set, node-set)
3960 *
3961 * Returns the nodes in @nodes that precede @node in document order,
3962 * @nodes if @node is NULL or an empty node-set if @nodes
3963 * doesn't contain @node
3964 */
3965xmlNodeSetPtr
3966xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3967 int i, l;
3968 xmlNodePtr cur;
3969 xmlNodeSetPtr ret;
3970
3971 if (node == NULL)
3972 return(nodes);
3973
3974 ret = xmlXPathNodeSetCreate(NULL);
3975 if (ret == NULL)
3976 return(ret);
3977 if (xmlXPathNodeSetIsEmpty(nodes) ||
3978 (!xmlXPathNodeSetContains(nodes, node)))
3979 return(ret);
3980
3981 l = xmlXPathNodeSetGetLength(nodes);
3982 for (i = 0; i < l; i++) {
3983 cur = xmlXPathNodeSetItem(nodes, i);
3984 if (cur == node)
3985 break;
3986 /* TODO: Propagate memory error. */
3987 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3988 break;
3989 }
3990 return(ret);
3991}
3992
3993/**
3994 * xmlXPathNodeLeading:
3995 * @nodes: a node-set
3996 * @node: a node
3997 *
3998 * Implements the EXSLT - Sets leading() function:
3999 * node-set set:leading (node-set, node-set)
4000 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4001 * is called.
4002 *
4003 * Returns the nodes in @nodes that precede @node in document order,
4004 * @nodes if @node is NULL or an empty node-set if @nodes
4005 * doesn't contain @node
4006 */
4007xmlNodeSetPtr
4008xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4009 xmlXPathNodeSetSort(nodes);
4010 return(xmlXPathNodeLeadingSorted(nodes, node));
4011}
4012
4013/**
4014 * xmlXPathLeadingSorted:
4015 * @nodes1: a node-set, sorted by document order
4016 * @nodes2: a node-set, sorted by document order
4017 *
4018 * Implements the EXSLT - Sets leading() function:
4019 * node-set set:leading (node-set, node-set)
4020 *
4021 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4022 * in document order, @nodes1 if @nodes2 is NULL or empty or
4023 * an empty node-set if @nodes1 doesn't contain @nodes2
4024 */
4025xmlNodeSetPtr
4026xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4027 if (xmlXPathNodeSetIsEmpty(nodes2))
4028 return(nodes1);
4029 return(xmlXPathNodeLeadingSorted(nodes1,
4030 xmlXPathNodeSetItem(nodes2, 1)));
4031}
4032
4033/**
4034 * xmlXPathLeading:
4035 * @nodes1: a node-set
4036 * @nodes2: a node-set
4037 *
4038 * Implements the EXSLT - Sets leading() function:
4039 * node-set set:leading (node-set, node-set)
4040 * @nodes1 and @nodes2 are sorted by document order, then
4041 * #exslSetsLeadingSorted is called.
4042 *
4043 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4044 * in document order, @nodes1 if @nodes2 is NULL or empty or
4045 * an empty node-set if @nodes1 doesn't contain @nodes2
4046 */
4047xmlNodeSetPtr
4048xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4049 if (xmlXPathNodeSetIsEmpty(nodes2))
4050 return(nodes1);
4051 if (xmlXPathNodeSetIsEmpty(nodes1))
4052 return(xmlXPathNodeSetCreate(NULL));
4053 xmlXPathNodeSetSort(nodes1);
4054 xmlXPathNodeSetSort(nodes2);
4055 return(xmlXPathNodeLeadingSorted(nodes1,
4056 xmlXPathNodeSetItem(nodes2, 1)));
4057}
4058
4059/**
4060 * xmlXPathNodeTrailingSorted:
4061 * @nodes: a node-set, sorted by document order
4062 * @node: a node
4063 *
4064 * Implements the EXSLT - Sets trailing() function:
4065 * node-set set:trailing (node-set, node-set)
4066 *
4067 * Returns the nodes in @nodes that follow @node in document order,
4068 * @nodes if @node is NULL or an empty node-set if @nodes
4069 * doesn't contain @node
4070 */
4071xmlNodeSetPtr
4072xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4073 int i, l;
4074 xmlNodePtr cur;
4075 xmlNodeSetPtr ret;
4076
4077 if (node == NULL)
4078 return(nodes);
4079
4080 ret = xmlXPathNodeSetCreate(NULL);
4081 if (ret == NULL)
4082 return(ret);
4083 if (xmlXPathNodeSetIsEmpty(nodes) ||
4084 (!xmlXPathNodeSetContains(nodes, node)))
4085 return(ret);
4086
4087 l = xmlXPathNodeSetGetLength(nodes);
4088 for (i = l - 1; i >= 0; i--) {
4089 cur = xmlXPathNodeSetItem(nodes, i);
4090 if (cur == node)
4091 break;
4092 /* TODO: Propagate memory error. */
4093 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4094 break;
4095 }
4096 xmlXPathNodeSetSort(ret); /* bug 413451 */
4097 return(ret);
4098}
4099
4100/**
4101 * xmlXPathNodeTrailing:
4102 * @nodes: a node-set
4103 * @node: a node
4104 *
4105 * Implements the EXSLT - Sets trailing() function:
4106 * node-set set:trailing (node-set, node-set)
4107 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4108 * is called.
4109 *
4110 * Returns the nodes in @nodes that follow @node in document order,
4111 * @nodes if @node is NULL or an empty node-set if @nodes
4112 * doesn't contain @node
4113 */
4114xmlNodeSetPtr
4115xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4116 xmlXPathNodeSetSort(nodes);
4117 return(xmlXPathNodeTrailingSorted(nodes, node));
4118}
4119
4120/**
4121 * xmlXPathTrailingSorted:
4122 * @nodes1: a node-set, sorted by document order
4123 * @nodes2: a node-set, sorted by document order
4124 *
4125 * Implements the EXSLT - Sets trailing() function:
4126 * node-set set:trailing (node-set, node-set)
4127 *
4128 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4129 * in document order, @nodes1 if @nodes2 is NULL or empty or
4130 * an empty node-set if @nodes1 doesn't contain @nodes2
4131 */
4132xmlNodeSetPtr
4133xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4134 if (xmlXPathNodeSetIsEmpty(nodes2))
4135 return(nodes1);
4136 return(xmlXPathNodeTrailingSorted(nodes1,
4137 xmlXPathNodeSetItem(nodes2, 0)));
4138}
4139
4140/**
4141 * xmlXPathTrailing:
4142 * @nodes1: a node-set
4143 * @nodes2: a node-set
4144 *
4145 * Implements the EXSLT - Sets trailing() function:
4146 * node-set set:trailing (node-set, node-set)
4147 * @nodes1 and @nodes2 are sorted by document order, then
4148 * #xmlXPathTrailingSorted is called.
4149 *
4150 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4151 * in document order, @nodes1 if @nodes2 is NULL or empty or
4152 * an empty node-set if @nodes1 doesn't contain @nodes2
4153 */
4154xmlNodeSetPtr
4155xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4156 if (xmlXPathNodeSetIsEmpty(nodes2))
4157 return(nodes1);
4158 if (xmlXPathNodeSetIsEmpty(nodes1))
4159 return(xmlXPathNodeSetCreate(NULL));
4160 xmlXPathNodeSetSort(nodes1);
4161 xmlXPathNodeSetSort(nodes2);
4162 return(xmlXPathNodeTrailingSorted(nodes1,
4163 xmlXPathNodeSetItem(nodes2, 0)));
4164}
4165
4166/************************************************************************
4167 * *
4168 * Routines to handle extra functions *
4169 * *
4170 ************************************************************************/
4171
4172/**
4173 * xmlXPathRegisterFunc:
4174 * @ctxt: the XPath context
4175 * @name: the function name
4176 * @f: the function implementation or NULL
4177 *
4178 * Register a new function. If @f is NULL it unregisters the function
4179 *
4180 * Returns 0 in case of success, -1 in case of error
4181 */
4182int
4183xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4184 xmlXPathFunction f) {
4185 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4186}
4187
4188/**
4189 * xmlXPathRegisterFuncNS:
4190 * @ctxt: the XPath context
4191 * @name: the function name
4192 * @ns_uri: the function namespace URI
4193 * @f: the function implementation or NULL
4194 *
4195 * Register a new function. If @f is NULL it unregisters the function
4196 *
4197 * Returns 0 in case of success, -1 in case of error
4198 */
4199int
4200xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4201 const xmlChar *ns_uri, xmlXPathFunction f) {
4202 if (ctxt == NULL)
4203 return(-1);
4204 if (name == NULL)
4205 return(-1);
4206
4207 if (ctxt->funcHash == NULL)
4208 ctxt->funcHash = xmlHashCreate(0);
4209 if (ctxt->funcHash == NULL)
4210 return(-1);
4211 if (f == NULL)
4212 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4213XML_IGNORE_FPTR_CAST_WARNINGS
4214 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4215XML_POP_WARNINGS
4216}
4217
4218/**
4219 * xmlXPathRegisterFuncLookup:
4220 * @ctxt: the XPath context
4221 * @f: the lookup function
4222 * @funcCtxt: the lookup data
4223 *
4224 * Registers an external mechanism to do function lookup.
4225 */
4226void
4227xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4228 xmlXPathFuncLookupFunc f,
4229 void *funcCtxt) {
4230 if (ctxt == NULL)
4231 return;
4232 ctxt->funcLookupFunc = f;
4233 ctxt->funcLookupData = funcCtxt;
4234}
4235
4236/**
4237 * xmlXPathFunctionLookup:
4238 * @ctxt: the XPath context
4239 * @name: the function name
4240 *
4241 * Search in the Function array of the context for the given
4242 * function.
4243 *
4244 * Returns the xmlXPathFunction or NULL if not found
4245 */
4246xmlXPathFunction
4247xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4248 if (ctxt == NULL)
4249 return (NULL);
4250
4251 if (ctxt->funcLookupFunc != NULL) {
4252 xmlXPathFunction ret;
4253 xmlXPathFuncLookupFunc f;
4254
4255 f = ctxt->funcLookupFunc;
4256 ret = f(ctxt->funcLookupData, name, NULL);
4257 if (ret != NULL)
4258 return(ret);
4259 }
4260 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4261}
4262
4263/**
4264 * xmlXPathFunctionLookupNS:
4265 * @ctxt: the XPath context
4266 * @name: the function name
4267 * @ns_uri: the function namespace URI
4268 *
4269 * Search in the Function array of the context for the given
4270 * function.
4271 *
4272 * Returns the xmlXPathFunction or NULL if not found
4273 */
4274xmlXPathFunction
4275xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4276 const xmlChar *ns_uri) {
4277 xmlXPathFunction ret;
4278
4279 if (ctxt == NULL)
4280 return(NULL);
4281 if (name == NULL)
4282 return(NULL);
4283
4284 if (ctxt->funcLookupFunc != NULL) {
4285 xmlXPathFuncLookupFunc f;
4286
4287 f = ctxt->funcLookupFunc;
4288 ret = f(ctxt->funcLookupData, name, ns_uri);
4289 if (ret != NULL)
4290 return(ret);
4291 }
4292
4293 if (ctxt->funcHash == NULL)
4294 return(NULL);
4295
4296XML_IGNORE_FPTR_CAST_WARNINGS
4297 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4298XML_POP_WARNINGS
4299 return(ret);
4300}
4301
4302/**
4303 * xmlXPathRegisteredFuncsCleanup:
4304 * @ctxt: the XPath context
4305 *
4306 * Cleanup the XPath context data associated to registered functions
4307 */
4308void
4309xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4310 if (ctxt == NULL)
4311 return;
4312
4313 xmlHashFree(ctxt->funcHash, NULL);
4314 ctxt->funcHash = NULL;
4315}
4316
4317/************************************************************************
4318 * *
4319 * Routines to handle Variables *
4320 * *
4321 ************************************************************************/
4322
4323/**
4324 * xmlXPathRegisterVariable:
4325 * @ctxt: the XPath context
4326 * @name: the variable name
4327 * @value: the variable value or NULL
4328 *
4329 * Register a new variable value. If @value is NULL it unregisters
4330 * the variable
4331 *
4332 * Returns 0 in case of success, -1 in case of error
4333 */
4334int
4335xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4336 xmlXPathObjectPtr value) {
4337 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4338}
4339
4340/**
4341 * xmlXPathRegisterVariableNS:
4342 * @ctxt: the XPath context
4343 * @name: the variable name
4344 * @ns_uri: the variable namespace URI
4345 * @value: the variable value or NULL
4346 *
4347 * Register a new variable value. If @value is NULL it unregisters
4348 * the variable
4349 *
4350 * Returns 0 in case of success, -1 in case of error
4351 */
4352int
4353xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4354 const xmlChar *ns_uri,
4355 xmlXPathObjectPtr value) {
4356 if (ctxt == NULL)
4357 return(-1);
4358 if (name == NULL)
4359 return(-1);
4360
4361 if (ctxt->varHash == NULL)
4362 ctxt->varHash = xmlHashCreate(0);
4363 if (ctxt->varHash == NULL)
4364 return(-1);
4365 if (value == NULL)
4366 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4367 xmlXPathFreeObjectEntry));
4368 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4369 (void *) value, xmlXPathFreeObjectEntry));
4370}
4371
4372/**
4373 * xmlXPathRegisterVariableLookup:
4374 * @ctxt: the XPath context
4375 * @f: the lookup function
4376 * @data: the lookup data
4377 *
4378 * register an external mechanism to do variable lookup
4379 */
4380void
4381xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4382 xmlXPathVariableLookupFunc f, void *data) {
4383 if (ctxt == NULL)
4384 return;
4385 ctxt->varLookupFunc = f;
4386 ctxt->varLookupData = data;
4387}
4388
4389/**
4390 * xmlXPathVariableLookup:
4391 * @ctxt: the XPath context
4392 * @name: the variable name
4393 *
4394 * Search in the Variable array of the context for the given
4395 * variable value.
4396 *
4397 * Returns a copy of the value or NULL if not found
4398 */
4399xmlXPathObjectPtr
4400xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4401 if (ctxt == NULL)
4402 return(NULL);
4403
4404 if (ctxt->varLookupFunc != NULL) {
4405 xmlXPathObjectPtr ret;
4406
4407 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4408 (ctxt->varLookupData, name, NULL);
4409 return(ret);
4410 }
4411 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4412}
4413
4414/**
4415 * xmlXPathVariableLookupNS:
4416 * @ctxt: the XPath context
4417 * @name: the variable name
4418 * @ns_uri: the variable namespace URI
4419 *
4420 * Search in the Variable array of the context for the given
4421 * variable value.
4422 *
4423 * Returns the a copy of the value or NULL if not found
4424 */
4425xmlXPathObjectPtr
4426xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4427 const xmlChar *ns_uri) {
4428 if (ctxt == NULL)
4429 return(NULL);
4430
4431 if (ctxt->varLookupFunc != NULL) {
4432 xmlXPathObjectPtr ret;
4433
4434 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4435 (ctxt->varLookupData, name, ns_uri);
4436 if (ret != NULL) return(ret);
4437 }
4438
4439 if (ctxt->varHash == NULL)
4440 return(NULL);
4441 if (name == NULL)
4442 return(NULL);
4443
4444 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4445 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4446}
4447
4448/**
4449 * xmlXPathRegisteredVariablesCleanup:
4450 * @ctxt: the XPath context
4451 *
4452 * Cleanup the XPath context data associated to registered variables
4453 */
4454void
4455xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4456 if (ctxt == NULL)
4457 return;
4458
4459 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4460 ctxt->varHash = NULL;
4461}
4462
4463/**
4464 * xmlXPathRegisterNs:
4465 * @ctxt: the XPath context
4466 * @prefix: the namespace prefix cannot be NULL or empty string
4467 * @ns_uri: the namespace name
4468 *
4469 * Register a new namespace. If @ns_uri is NULL it unregisters
4470 * the namespace
4471 *
4472 * Returns 0 in case of success, -1 in case of error
4473 */
4474int
4475xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4476 const xmlChar *ns_uri) {
4477 xmlChar *copy;
4478
4479 if (ctxt == NULL)
4480 return(-1);
4481 if (prefix == NULL)
4482 return(-1);
4483 if (prefix[0] == 0)
4484 return(-1);
4485
4486 if (ctxt->nsHash == NULL)
4487 ctxt->nsHash = xmlHashCreate(10);
4488 if (ctxt->nsHash == NULL)
4489 return(-1);
4490 if (ns_uri == NULL)
4491 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4492 xmlHashDefaultDeallocator));
4493
4494 copy = xmlStrdup(ns_uri);
4495 if (copy == NULL)
4496 return(-1);
4497 if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4498 xmlHashDefaultDeallocator) < 0) {
4499 xmlFree(copy);
4500 return(-1);
4501 }
4502
4503 return(0);
4504}
4505
4506/**
4507 * xmlXPathNsLookup:
4508 * @ctxt: the XPath context
4509 * @prefix: the namespace prefix value
4510 *
4511 * Search in the namespace declaration array of the context for the given
4512 * namespace name associated to the given prefix
4513 *
4514 * Returns the value or NULL if not found
4515 */
4516const xmlChar *
4517xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4518 if (ctxt == NULL)
4519 return(NULL);
4520 if (prefix == NULL)
4521 return(NULL);
4522
4523#ifdef XML_XML_NAMESPACE
4524 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4525 return(XML_XML_NAMESPACE);
4526#endif
4527
4528 if (ctxt->namespaces != NULL) {
4529 int i;
4530
4531 for (i = 0;i < ctxt->nsNr;i++) {
4532 if ((ctxt->namespaces[i] != NULL) &&
4533 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4534 return(ctxt->namespaces[i]->href);
4535 }
4536 }
4537
4538 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4539}
4540
4541/**
4542 * xmlXPathRegisteredNsCleanup:
4543 * @ctxt: the XPath context
4544 *
4545 * Cleanup the XPath context data associated to registered variables
4546 */
4547void
4548xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4549 if (ctxt == NULL)
4550 return;
4551
4552 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4553 ctxt->nsHash = NULL;
4554}
4555
4556/************************************************************************
4557 * *
4558 * Routines to handle Values *
4559 * *
4560 ************************************************************************/
4561
4562/* Allocations are terrible, one needs to optimize all this !!! */
4563
4564/**
4565 * xmlXPathNewFloat:
4566 * @val: the double value
4567 *
4568 * Create a new xmlXPathObjectPtr of type double and of value @val
4569 *
4570 * Returns the newly created object.
4571 */
4572xmlXPathObjectPtr
4573xmlXPathNewFloat(double val) {
4574 xmlXPathObjectPtr ret;
4575
4576 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4577 if (ret == NULL) {
4578 xmlXPathErrMemory(NULL, "creating float object\n");
4579 return(NULL);
4580 }
4581 memset(ret, 0 , sizeof(xmlXPathObject));
4582 ret->type = XPATH_NUMBER;
4583 ret->floatval = val;
4584 return(ret);
4585}
4586
4587/**
4588 * xmlXPathNewBoolean:
4589 * @val: the boolean value
4590 *
4591 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4592 *
4593 * Returns the newly created object.
4594 */
4595xmlXPathObjectPtr
4596xmlXPathNewBoolean(int val) {
4597 xmlXPathObjectPtr ret;
4598
4599 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4600 if (ret == NULL) {
4601 xmlXPathErrMemory(NULL, "creating boolean object\n");
4602 return(NULL);
4603 }
4604 memset(ret, 0 , sizeof(xmlXPathObject));
4605 ret->type = XPATH_BOOLEAN;
4606 ret->boolval = (val != 0);
4607 return(ret);
4608}
4609
4610/**
4611 * xmlXPathNewString:
4612 * @val: the xmlChar * value
4613 *
4614 * Create a new xmlXPathObjectPtr of type string and of value @val
4615 *
4616 * Returns the newly created object.
4617 */
4618xmlXPathObjectPtr
4619xmlXPathNewString(const xmlChar *val) {
4620 xmlXPathObjectPtr ret;
4621
4622 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4623 if (ret == NULL) {
4624 xmlXPathErrMemory(NULL, "creating string object\n");
4625 return(NULL);
4626 }
4627 memset(ret, 0 , sizeof(xmlXPathObject));
4628 ret->type = XPATH_STRING;
4629 if (val == NULL)
4630 val = BAD_CAST "";
4631 ret->stringval = xmlStrdup(val);
4632 if (ret->stringval == NULL) {
4633 xmlFree(ret);
4634 return(NULL);
4635 }
4636 return(ret);
4637}
4638
4639/**
4640 * xmlXPathWrapString:
4641 * @val: the xmlChar * value
4642 *
4643 * Wraps the @val string into an XPath object.
4644 *
4645 * Returns the newly created object.
4646 *
4647 * Frees @val in case of error.
4648 */
4649xmlXPathObjectPtr
4650xmlXPathWrapString (xmlChar *val) {
4651 xmlXPathObjectPtr ret;
4652
4653 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4654 if (ret == NULL) {
4655 xmlXPathErrMemory(NULL, "creating string object\n");
4656 xmlFree(val);
4657 return(NULL);
4658 }
4659 memset(ret, 0 , sizeof(xmlXPathObject));
4660 ret->type = XPATH_STRING;
4661 ret->stringval = val;
4662 return(ret);
4663}
4664
4665/**
4666 * xmlXPathNewCString:
4667 * @val: the char * value
4668 *
4669 * Create a new xmlXPathObjectPtr of type string and of value @val
4670 *
4671 * Returns the newly created object.
4672 */
4673xmlXPathObjectPtr
4674xmlXPathNewCString(const char *val) {
4675 return(xmlXPathNewString(BAD_CAST val));
4676}
4677
4678/**
4679 * xmlXPathWrapCString:
4680 * @val: the char * value
4681 *
4682 * Wraps a string into an XPath object.
4683 *
4684 * Returns the newly created object.
4685 */
4686xmlXPathObjectPtr
4687xmlXPathWrapCString (char * val) {
4688 return(xmlXPathWrapString((xmlChar *)(val)));
4689}
4690
4691/**
4692 * xmlXPathWrapExternal:
4693 * @val: the user data
4694 *
4695 * Wraps the @val data into an XPath object.
4696 *
4697 * Returns the newly created object.
4698 */
4699xmlXPathObjectPtr
4700xmlXPathWrapExternal (void *val) {
4701 xmlXPathObjectPtr ret;
4702
4703 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4704 if (ret == NULL) {
4705 xmlXPathErrMemory(NULL, "creating user object\n");
4706 return(NULL);
4707 }
4708 memset(ret, 0 , sizeof(xmlXPathObject));
4709 ret->type = XPATH_USERS;
4710 ret->user = val;
4711 return(ret);
4712}
4713
4714/**
4715 * xmlXPathObjectCopy:
4716 * @val: the original object
4717 *
4718 * allocate a new copy of a given object
4719 *
4720 * Returns the newly created object.
4721 */
4722xmlXPathObjectPtr
4723xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4724 xmlXPathObjectPtr ret;
4725
4726 if (val == NULL)
4727 return(NULL);
4728
4729 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4730 if (ret == NULL) {
4731 xmlXPathErrMemory(NULL, "copying object\n");
4732 return(NULL);
4733 }
4734 memcpy(ret, val , sizeof(xmlXPathObject));
4735 switch (val->type) {
4736 case XPATH_BOOLEAN:
4737 case XPATH_NUMBER:
4738#ifdef LIBXML_XPTR_LOCS_ENABLED
4739 case XPATH_POINT:
4740 case XPATH_RANGE:
4741#endif /* LIBXML_XPTR_LOCS_ENABLED */
4742 break;
4743 case XPATH_STRING:
4744 ret->stringval = xmlStrdup(val->stringval);
4745 if (ret->stringval == NULL) {
4746 xmlFree(ret);
4747 return(NULL);
4748 }
4749 break;
4750 case XPATH_XSLT_TREE:
4751#if 0
4752/*
4753 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
4754 this previous handling is no longer correct, and can cause some serious
4755 problems (ref. bug 145547)
4756*/
4757 if ((val->nodesetval != NULL) &&
4758 (val->nodesetval->nodeTab != NULL)) {
4759 xmlNodePtr cur, tmp;
4760 xmlDocPtr top;
4761
4762 ret->boolval = 1;
4763 top = xmlNewDoc(NULL);
4764 top->name = (char *)
4765 xmlStrdup(val->nodesetval->nodeTab[0]->name);
4766 ret->user = top;
4767 if (top != NULL) {
4768 top->doc = top;
4769 cur = val->nodesetval->nodeTab[0]->children;
4770 while (cur != NULL) {
4771 tmp = xmlDocCopyNode(cur, top, 1);
4772 xmlAddChild((xmlNodePtr) top, tmp);
4773 cur = cur->next;
4774 }
4775 }
4776
4777 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
4778 } else
4779 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
4780 /* Deallocate the copied tree value */
4781 break;
4782#endif
4783 case XPATH_NODESET:
4784 /* TODO: Check memory error. */
4785 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4786 /* Do not deallocate the copied tree value */
4787 ret->boolval = 0;
4788 break;
4789#ifdef LIBXML_XPTR_LOCS_ENABLED
4790 case XPATH_LOCATIONSET:
4791 {
4792 xmlLocationSetPtr loc = val->user;
4793 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
4794 break;
4795 }
4796#endif
4797 case XPATH_USERS:
4798 ret->user = val->user;
4799 break;
4800 case XPATH_UNDEFINED:
4801 xmlGenericError(xmlGenericErrorContext,
4802 "xmlXPathObjectCopy: unsupported type %d\n",
4803 val->type);
4804 break;
4805 }
4806 return(ret);
4807}
4808
4809/**
4810 * xmlXPathFreeObject:
4811 * @obj: the object to free
4812 *
4813 * Free up an xmlXPathObjectPtr object.
4814 */
4815void
4816xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4817 if (obj == NULL) return;
4818 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4819 if (obj->boolval) {
4820#if 0
4821 if (obj->user != NULL) {
4822 xmlXPathFreeNodeSet(obj->nodesetval);
4823 xmlFreeNodeList((xmlNodePtr) obj->user);
4824 } else
4825#endif
4826 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
4827 if (obj->nodesetval != NULL)
4828 xmlXPathFreeValueTree(obj->nodesetval);
4829 } else {
4830 if (obj->nodesetval != NULL)
4831 xmlXPathFreeNodeSet(obj->nodesetval);
4832 }
4833#ifdef LIBXML_XPTR_LOCS_ENABLED
4834 } else if (obj->type == XPATH_LOCATIONSET) {
4835 if (obj->user != NULL)
4836 xmlXPtrFreeLocationSet(obj->user);
4837#endif
4838 } else if (obj->type == XPATH_STRING) {
4839 if (obj->stringval != NULL)
4840 xmlFree(obj->stringval);
4841 }
4842 xmlFree(obj);
4843}
4844
4845static void
4846xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4847 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4848}
4849
4850/**
4851 * xmlXPathReleaseObject:
4852 * @obj: the xmlXPathObjectPtr to free or to cache
4853 *
4854 * Depending on the state of the cache this frees the given
4855 * XPath object or stores it in the cache.
4856 */
4857static void
4858xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4859{
4860#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
4861 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
4862 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
4863
4864#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
4865
4866 if (obj == NULL)
4867 return;
4868 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4869 xmlXPathFreeObject(obj);
4870 } else {
4871 xmlXPathContextCachePtr cache =
4872 (xmlXPathContextCachePtr) ctxt->cache;
4873
4874 switch (obj->type) {
4875 case XPATH_NODESET:
4876 case XPATH_XSLT_TREE:
4877 if (obj->nodesetval != NULL) {
4878 if (obj->boolval) {
4879 /*
4880 * It looks like the @boolval is used for
4881 * evaluation if this an XSLT Result Tree Fragment.
4882 * TODO: Check if this assumption is correct.
4883 */
4884 obj->type = XPATH_XSLT_TREE; /* just for debugging */
4885 xmlXPathFreeValueTree(obj->nodesetval);
4886 obj->nodesetval = NULL;
4887 } else if ((obj->nodesetval->nodeMax <= 40) &&
4888 (XP_CACHE_WANTS(cache->nodesetObjs,
4889 cache->maxNodeset)))
4890 {
4891 XP_CACHE_ADD(cache->nodesetObjs, obj);
4892 goto obj_cached;
4893 } else {
4894 xmlXPathFreeNodeSet(obj->nodesetval);
4895 obj->nodesetval = NULL;
4896 }
4897 }
4898 break;
4899 case XPATH_STRING:
4900 if (obj->stringval != NULL)
4901 xmlFree(obj->stringval);
4902
4903 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
4904 XP_CACHE_ADD(cache->stringObjs, obj);
4905 goto obj_cached;
4906 }
4907 break;
4908 case XPATH_BOOLEAN:
4909 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
4910 XP_CACHE_ADD(cache->booleanObjs, obj);
4911 goto obj_cached;
4912 }
4913 break;
4914 case XPATH_NUMBER:
4915 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
4916 XP_CACHE_ADD(cache->numberObjs, obj);
4917 goto obj_cached;
4918 }
4919 break;
4920#ifdef LIBXML_XPTR_LOCS_ENABLED
4921 case XPATH_LOCATIONSET:
4922 if (obj->user != NULL) {
4923 xmlXPtrFreeLocationSet(obj->user);
4924 }
4925 goto free_obj;
4926#endif
4927 default:
4928 goto free_obj;
4929 }
4930
4931 /*
4932 * Fallback to adding to the misc-objects slot.
4933 */
4934 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
4935 XP_CACHE_ADD(cache->miscObjs, obj);
4936 } else
4937 goto free_obj;
4938
4939obj_cached:
4940 if (obj->nodesetval != NULL) {
4941 xmlNodeSetPtr tmpset = obj->nodesetval;
4942
4943 /*
4944 * TODO: Due to those nasty ns-nodes, we need to traverse
4945 * the list and free the ns-nodes.
4946 * URGENT TODO: Check if it's actually slowing things down.
4947 * Maybe we shouldn't try to preserve the list.
4948 */
4949 if (tmpset->nodeNr > 1) {
4950 int i;
4951 xmlNodePtr node;
4952
4953 for (i = 0; i < tmpset->nodeNr; i++) {
4954 node = tmpset->nodeTab[i];
4955 if ((node != NULL) &&
4956 (node->type == XML_NAMESPACE_DECL))
4957 {
4958 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4959 }
4960 }
4961 } else if (tmpset->nodeNr == 1) {
4962 if ((tmpset->nodeTab[0] != NULL) &&
4963 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
4964 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
4965 }
4966 tmpset->nodeNr = 0;
4967 memset(obj, 0, sizeof(xmlXPathObject));
4968 obj->nodesetval = tmpset;
4969 } else
4970 memset(obj, 0, sizeof(xmlXPathObject));
4971
4972 return;
4973
4974free_obj:
4975 /*
4976 * Cache is full; free the object.
4977 */
4978 if (obj->nodesetval != NULL)
4979 xmlXPathFreeNodeSet(obj->nodesetval);
4980 xmlFree(obj);
4981 }
4982 return;
4983}
4984
4985
4986/************************************************************************
4987 * *
4988 * Type Casting Routines *
4989 * *
4990 ************************************************************************/
4991
4992/**
4993 * xmlXPathCastBooleanToString:
4994 * @val: a boolean
4995 *
4996 * Converts a boolean to its string value.
4997 *
4998 * Returns a newly allocated string.
4999 */
5000xmlChar *
5001xmlXPathCastBooleanToString (int val) {
5002 xmlChar *ret;
5003 if (val)
5004 ret = xmlStrdup((const xmlChar *) "true");
5005 else
5006 ret = xmlStrdup((const xmlChar *) "false");
5007 return(ret);
5008}
5009
5010/**
5011 * xmlXPathCastNumberToString:
5012 * @val: a number
5013 *
5014 * Converts a number to its string value.
5015 *
5016 * Returns a newly allocated string.
5017 */
5018xmlChar *
5019xmlXPathCastNumberToString (double val) {
5020 xmlChar *ret;
5021 switch (xmlXPathIsInf(val)) {
5022 case 1:
5023 ret = xmlStrdup((const xmlChar *) "Infinity");
5024 break;
5025 case -1:
5026 ret = xmlStrdup((const xmlChar *) "-Infinity");
5027 break;
5028 default:
5029 if (xmlXPathIsNaN(val)) {
5030 ret = xmlStrdup((const xmlChar *) "NaN");
5031 } else if (val == 0) {
5032 /* Omit sign for negative zero. */
5033 ret = xmlStrdup((const xmlChar *) "0");
5034 } else {
5035 /* could be improved */
5036 char buf[100];
5037 xmlXPathFormatNumber(val, buf, 99);
5038 buf[99] = 0;
5039 ret = xmlStrdup((const xmlChar *) buf);
5040 }
5041 }
5042 return(ret);
5043}
5044
5045/**
5046 * xmlXPathCastNodeToString:
5047 * @node: a node
5048 *
5049 * Converts a node to its string value.
5050 *
5051 * Returns a newly allocated string.
5052 */
5053xmlChar *
5054xmlXPathCastNodeToString (xmlNodePtr node) {
5055xmlChar *ret;
5056 if ((ret = xmlNodeGetContent(node)) == NULL)
5057 ret = xmlStrdup((const xmlChar *) "");
5058 return(ret);
5059}
5060
5061/**
5062 * xmlXPathCastNodeSetToString:
5063 * @ns: a node-set
5064 *
5065 * Converts a node-set to its string value.
5066 *
5067 * Returns a newly allocated string.
5068 */
5069xmlChar *
5070xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5071 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5072 return(xmlStrdup((const xmlChar *) ""));
5073
5074 if (ns->nodeNr > 1)
5075 xmlXPathNodeSetSort(ns);
5076 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5077}
5078
5079/**
5080 * xmlXPathCastToString:
5081 * @val: an XPath object
5082 *
5083 * Converts an existing object to its string() equivalent
5084 *
5085 * Returns the allocated string value of the object, NULL in case of error.
5086 * It's up to the caller to free the string memory with xmlFree().
5087 */
5088xmlChar *
5089xmlXPathCastToString(xmlXPathObjectPtr val) {
5090 xmlChar *ret = NULL;
5091
5092 if (val == NULL)
5093 return(xmlStrdup((const xmlChar *) ""));
5094 switch (val->type) {
5095 case XPATH_UNDEFINED:
5096 ret = xmlStrdup((const xmlChar *) "");
5097 break;
5098 case XPATH_NODESET:
5099 case XPATH_XSLT_TREE:
5100 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5101 break;
5102 case XPATH_STRING:
5103 return(xmlStrdup(val->stringval));
5104 case XPATH_BOOLEAN:
5105 ret = xmlXPathCastBooleanToString(val->boolval);
5106 break;
5107 case XPATH_NUMBER: {
5108 ret = xmlXPathCastNumberToString(val->floatval);
5109 break;
5110 }
5111 case XPATH_USERS:
5112#ifdef LIBXML_XPTR_LOCS_ENABLED
5113 case XPATH_POINT:
5114 case XPATH_RANGE:
5115 case XPATH_LOCATIONSET:
5116#endif /* LIBXML_XPTR_LOCS_ENABLED */
5117 TODO
5118 ret = xmlStrdup((const xmlChar *) "");
5119 break;
5120 }
5121 return(ret);
5122}
5123
5124/**
5125 * xmlXPathConvertString:
5126 * @val: an XPath object
5127 *
5128 * Converts an existing object to its string() equivalent
5129 *
5130 * Returns the new object, the old one is freed (or the operation
5131 * is done directly on @val)
5132 */
5133xmlXPathObjectPtr
5134xmlXPathConvertString(xmlXPathObjectPtr val) {
5135 xmlChar *res = NULL;
5136
5137 if (val == NULL)
5138 return(xmlXPathNewCString(""));
5139
5140 switch (val->type) {
5141 case XPATH_UNDEFINED:
5142 break;
5143 case XPATH_NODESET:
5144 case XPATH_XSLT_TREE:
5145 res = xmlXPathCastNodeSetToString(val->nodesetval);
5146 break;
5147 case XPATH_STRING:
5148 return(val);
5149 case XPATH_BOOLEAN:
5150 res = xmlXPathCastBooleanToString(val->boolval);
5151 break;
5152 case XPATH_NUMBER:
5153 res = xmlXPathCastNumberToString(val->floatval);
5154 break;
5155 case XPATH_USERS:
5156#ifdef LIBXML_XPTR_LOCS_ENABLED
5157 case XPATH_POINT:
5158 case XPATH_RANGE:
5159 case XPATH_LOCATIONSET:
5160#endif /* LIBXML_XPTR_LOCS_ENABLED */
5161 TODO;
5162 break;
5163 }
5164 xmlXPathFreeObject(val);
5165 if (res == NULL)
5166 return(xmlXPathNewCString(""));
5167 return(xmlXPathWrapString(res));
5168}
5169
5170/**
5171 * xmlXPathCastBooleanToNumber:
5172 * @val: a boolean
5173 *
5174 * Converts a boolean to its number value
5175 *
5176 * Returns the number value
5177 */
5178double
5179xmlXPathCastBooleanToNumber(int val) {
5180 if (val)
5181 return(1.0);
5182 return(0.0);
5183}
5184
5185/**
5186 * xmlXPathCastStringToNumber:
5187 * @val: a string
5188 *
5189 * Converts a string to its number value
5190 *
5191 * Returns the number value
5192 */
5193double
5194xmlXPathCastStringToNumber(const xmlChar * val) {
5195 return(xmlXPathStringEvalNumber(val));
5196}
5197
5198/**
5199 * xmlXPathCastNodeToNumber:
5200 * @node: a node
5201 *
5202 * Converts a node to its number value
5203 *
5204 * Returns the number value
5205 */
5206double
5207xmlXPathCastNodeToNumber (xmlNodePtr node) {
5208 xmlChar *strval;
5209 double ret;
5210
5211 if (node == NULL)
5212 return(xmlXPathNAN);
5213 strval = xmlXPathCastNodeToString(node);
5214 if (strval == NULL)
5215 return(xmlXPathNAN);
5216 ret = xmlXPathCastStringToNumber(strval);
5217 xmlFree(strval);
5218
5219 return(ret);
5220}
5221
5222/**
5223 * xmlXPathCastNodeSetToNumber:
5224 * @ns: a node-set
5225 *
5226 * Converts a node-set to its number value
5227 *
5228 * Returns the number value
5229 */
5230double
5231xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5232 xmlChar *str;
5233 double ret;
5234
5235 if (ns == NULL)
5236 return(xmlXPathNAN);
5237 str = xmlXPathCastNodeSetToString(ns);
5238 ret = xmlXPathCastStringToNumber(str);
5239 xmlFree(str);
5240 return(ret);
5241}
5242
5243/**
5244 * xmlXPathCastToNumber:
5245 * @val: an XPath object
5246 *
5247 * Converts an XPath object to its number value
5248 *
5249 * Returns the number value
5250 */
5251double
5252xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5253 double ret = 0.0;
5254
5255 if (val == NULL)
5256 return(xmlXPathNAN);
5257 switch (val->type) {
5258 case XPATH_UNDEFINED:
5259 ret = xmlXPathNAN;
5260 break;
5261 case XPATH_NODESET:
5262 case XPATH_XSLT_TREE:
5263 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5264 break;
5265 case XPATH_STRING:
5266 ret = xmlXPathCastStringToNumber(val->stringval);
5267 break;
5268 case XPATH_NUMBER:
5269 ret = val->floatval;
5270 break;
5271 case XPATH_BOOLEAN:
5272 ret = xmlXPathCastBooleanToNumber(val->boolval);
5273 break;
5274 case XPATH_USERS:
5275#ifdef LIBXML_XPTR_LOCS_ENABLED
5276 case XPATH_POINT:
5277 case XPATH_RANGE:
5278 case XPATH_LOCATIONSET:
5279#endif /* LIBXML_XPTR_LOCS_ENABLED */
5280 TODO;
5281 ret = xmlXPathNAN;
5282 break;
5283 }
5284 return(ret);
5285}
5286
5287/**
5288 * xmlXPathConvertNumber:
5289 * @val: an XPath object
5290 *
5291 * Converts an existing object to its number() equivalent
5292 *
5293 * Returns the new object, the old one is freed (or the operation
5294 * is done directly on @val)
5295 */
5296xmlXPathObjectPtr
5297xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5298 xmlXPathObjectPtr ret;
5299
5300 if (val == NULL)
5301 return(xmlXPathNewFloat(0.0));
5302 if (val->type == XPATH_NUMBER)
5303 return(val);
5304 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5305 xmlXPathFreeObject(val);
5306 return(ret);
5307}
5308
5309/**
5310 * xmlXPathCastNumberToBoolean:
5311 * @val: a number
5312 *
5313 * Converts a number to its boolean value
5314 *
5315 * Returns the boolean value
5316 */
5317int
5318xmlXPathCastNumberToBoolean (double val) {
5319 if (xmlXPathIsNaN(val) || (val == 0.0))
5320 return(0);
5321 return(1);
5322}
5323
5324/**
5325 * xmlXPathCastStringToBoolean:
5326 * @val: a string
5327 *
5328 * Converts a string to its boolean value
5329 *
5330 * Returns the boolean value
5331 */
5332int
5333xmlXPathCastStringToBoolean (const xmlChar *val) {
5334 if ((val == NULL) || (xmlStrlen(val) == 0))
5335 return(0);
5336 return(1);
5337}
5338
5339/**
5340 * xmlXPathCastNodeSetToBoolean:
5341 * @ns: a node-set
5342 *
5343 * Converts a node-set to its boolean value
5344 *
5345 * Returns the boolean value
5346 */
5347int
5348xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5349 if ((ns == NULL) || (ns->nodeNr == 0))
5350 return(0);
5351 return(1);
5352}
5353
5354/**
5355 * xmlXPathCastToBoolean:
5356 * @val: an XPath object
5357 *
5358 * Converts an XPath object to its boolean value
5359 *
5360 * Returns the boolean value
5361 */
5362int
5363xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5364 int ret = 0;
5365
5366 if (val == NULL)
5367 return(0);
5368 switch (val->type) {
5369 case XPATH_UNDEFINED:
5370 ret = 0;
5371 break;
5372 case XPATH_NODESET:
5373 case XPATH_XSLT_TREE:
5374 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5375 break;
5376 case XPATH_STRING:
5377 ret = xmlXPathCastStringToBoolean(val->stringval);
5378 break;
5379 case XPATH_NUMBER:
5380 ret = xmlXPathCastNumberToBoolean(val->floatval);
5381 break;
5382 case XPATH_BOOLEAN:
5383 ret = val->boolval;
5384 break;
5385 case XPATH_USERS:
5386#ifdef LIBXML_XPTR_LOCS_ENABLED
5387 case XPATH_POINT:
5388 case XPATH_RANGE:
5389 case XPATH_LOCATIONSET:
5390#endif /* LIBXML_XPTR_LOCS_ENABLED */
5391 TODO;
5392 ret = 0;
5393 break;
5394 }
5395 return(ret);
5396}
5397
5398
5399/**
5400 * xmlXPathConvertBoolean:
5401 * @val: an XPath object
5402 *
5403 * Converts an existing object to its boolean() equivalent
5404 *
5405 * Returns the new object, the old one is freed (or the operation
5406 * is done directly on @val)
5407 */
5408xmlXPathObjectPtr
5409xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5410 xmlXPathObjectPtr ret;
5411
5412 if (val == NULL)
5413 return(xmlXPathNewBoolean(0));
5414 if (val->type == XPATH_BOOLEAN)
5415 return(val);
5416 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5417 xmlXPathFreeObject(val);
5418 return(ret);
5419}
5420
5421/************************************************************************
5422 * *
5423 * Routines to handle XPath contexts *
5424 * *
5425 ************************************************************************/
5426
5427/**
5428 * xmlXPathNewContext:
5429 * @doc: the XML document
5430 *
5431 * Create a new xmlXPathContext
5432 *
5433 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5434 */
5435xmlXPathContextPtr
5436xmlXPathNewContext(xmlDocPtr doc) {
5437 xmlXPathContextPtr ret;
5438
5439 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5440 if (ret == NULL) {
5441 xmlXPathErrMemory(NULL, "creating context\n");
5442 return(NULL);
5443 }
5444 memset(ret, 0 , sizeof(xmlXPathContext));
5445 ret->doc = doc;
5446 ret->node = NULL;
5447
5448 ret->varHash = NULL;
5449
5450 ret->nb_types = 0;
5451 ret->max_types = 0;
5452 ret->types = NULL;
5453
5454 ret->funcHash = xmlHashCreate(0);
5455
5456 ret->nb_axis = 0;
5457 ret->max_axis = 0;
5458 ret->axis = NULL;
5459
5460 ret->nsHash = NULL;
5461 ret->user = NULL;
5462
5463 ret->contextSize = -1;
5464 ret->proximityPosition = -1;
5465
5466#ifdef XP_DEFAULT_CACHE_ON
5467 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5468 xmlXPathFreeContext(ret);
5469 return(NULL);
5470 }
5471#endif
5472
5473 xmlXPathRegisterAllFunctions(ret);
5474
5475 return(ret);
5476}
5477
5478/**
5479 * xmlXPathFreeContext:
5480 * @ctxt: the context to free
5481 *
5482 * Free up an xmlXPathContext
5483 */
5484void
5485xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5486 if (ctxt == NULL) return;
5487
5488 if (ctxt->cache != NULL)
5489 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5490 xmlXPathRegisteredNsCleanup(ctxt);
5491 xmlXPathRegisteredFuncsCleanup(ctxt);
5492 xmlXPathRegisteredVariablesCleanup(ctxt);
5493 xmlResetError(&ctxt->lastError);
5494 xmlFree(ctxt);
5495}
5496
5497/************************************************************************
5498 * *
5499 * Routines to handle XPath parser contexts *
5500 * *
5501 ************************************************************************/
5502
5503#define CHECK_CTXT(ctxt) \
5504 if (ctxt == NULL) { \
5505 __xmlRaiseError(NULL, NULL, NULL, \
5506 NULL, NULL, XML_FROM_XPATH, \
5507 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
5508 __FILE__, __LINE__, \
5509 NULL, NULL, NULL, 0, 0, \
5510 "NULL context pointer\n"); \
5511 return(NULL); \
5512 } \
5513
5514#define CHECK_CTXT_NEG(ctxt) \
5515 if (ctxt == NULL) { \
5516 __xmlRaiseError(NULL, NULL, NULL, \
5517 NULL, NULL, XML_FROM_XPATH, \
5518 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
5519 __FILE__, __LINE__, \
5520 NULL, NULL, NULL, 0, 0, \
5521 "NULL context pointer\n"); \
5522 return(-1); \
5523 } \
5524
5525
5526#define CHECK_CONTEXT(ctxt) \
5527 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
5528 (ctxt->doc->children == NULL)) { \
5529 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
5530 return(NULL); \
5531 }
5532
5533
5534/**
5535 * xmlXPathNewParserContext:
5536 * @str: the XPath expression
5537 * @ctxt: the XPath context
5538 *
5539 * Create a new xmlXPathParserContext
5540 *
5541 * Returns the xmlXPathParserContext just allocated.
5542 */
5543xmlXPathParserContextPtr
5544xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5545 xmlXPathParserContextPtr ret;
5546
5547 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5548 if (ret == NULL) {
5549 xmlXPathErrMemory(ctxt, "creating parser context\n");
5550 return(NULL);
5551 }
5552 memset(ret, 0 , sizeof(xmlXPathParserContext));
5553 ret->cur = ret->base = str;
5554 ret->context = ctxt;
5555
5556 ret->comp = xmlXPathNewCompExpr();
5557 if (ret->comp == NULL) {
5558 xmlFree(ret->valueTab);
5559 xmlFree(ret);
5560 return(NULL);
5561 }
5562 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5563 ret->comp->dict = ctxt->dict;
5564 xmlDictReference(ret->comp->dict);
5565 }
5566
5567 return(ret);
5568}
5569
5570/**
5571 * xmlXPathCompParserContext:
5572 * @comp: the XPath compiled expression
5573 * @ctxt: the XPath context
5574 *
5575 * Create a new xmlXPathParserContext when processing a compiled expression
5576 *
5577 * Returns the xmlXPathParserContext just allocated.
5578 */
5579static xmlXPathParserContextPtr
5580xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5581 xmlXPathParserContextPtr ret;
5582
5583 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5584 if (ret == NULL) {
5585 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
5586 return(NULL);
5587 }
5588 memset(ret, 0 , sizeof(xmlXPathParserContext));
5589
5590 /* Allocate the value stack */
5591 ret->valueTab = (xmlXPathObjectPtr *)
5592 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5593 if (ret->valueTab == NULL) {
5594 xmlFree(ret);
5595 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
5596 return(NULL);
5597 }
5598 ret->valueNr = 0;
5599 ret->valueMax = 10;
5600 ret->value = NULL;
5601
5602 ret->context = ctxt;
5603 ret->comp = comp;
5604
5605 return(ret);
5606}
5607
5608/**
5609 * xmlXPathFreeParserContext:
5610 * @ctxt: the context to free
5611 *
5612 * Free up an xmlXPathParserContext
5613 */
5614void
5615xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5616 int i;
5617
5618 if (ctxt->valueTab != NULL) {
5619 for (i = 0; i < ctxt->valueNr; i++) {
5620 if (ctxt->context)
5621 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5622 else
5623 xmlXPathFreeObject(ctxt->valueTab[i]);
5624 }
5625 xmlFree(ctxt->valueTab);
5626 }
5627 if (ctxt->comp != NULL) {
5628#ifdef XPATH_STREAMING
5629 if (ctxt->comp->stream != NULL) {
5630 xmlFreePatternList(ctxt->comp->stream);
5631 ctxt->comp->stream = NULL;
5632 }
5633#endif
5634 xmlXPathFreeCompExpr(ctxt->comp);
5635 }
5636 xmlFree(ctxt);
5637}
5638
5639/************************************************************************
5640 * *
5641 * The implicit core function library *
5642 * *
5643 ************************************************************************/
5644
5645/**
5646 * xmlXPathNodeValHash:
5647 * @node: a node pointer
5648 *
5649 * Function computing the beginning of the string value of the node,
5650 * used to speed up comparisons
5651 *
5652 * Returns an int usable as a hash
5653 */
5654static unsigned int
5655xmlXPathNodeValHash(xmlNodePtr node) {
5656 int len = 2;
5657 const xmlChar * string = NULL;
5658 xmlNodePtr tmp = NULL;
5659 unsigned int ret = 0;
5660
5661 if (node == NULL)
5662 return(0);
5663
5664 if (node->type == XML_DOCUMENT_NODE) {
5665 tmp = xmlDocGetRootElement((xmlDocPtr) node);
5666 if (tmp == NULL)
5667 node = node->children;
5668 else
5669 node = tmp;
5670
5671 if (node == NULL)
5672 return(0);
5673 }
5674
5675 switch (node->type) {
5676 case XML_COMMENT_NODE:
5677 case XML_PI_NODE:
5678 case XML_CDATA_SECTION_NODE:
5679 case XML_TEXT_NODE:
5680 string = node->content;
5681 if (string == NULL)
5682 return(0);
5683 if (string[0] == 0)
5684 return(0);
5685 return(string[0] + (string[1] << 8));
5686 case XML_NAMESPACE_DECL:
5687 string = ((xmlNsPtr)node)->href;
5688 if (string == NULL)
5689 return(0);
5690 if (string[0] == 0)
5691 return(0);
5692 return(string[0] + (string[1] << 8));
5693 case XML_ATTRIBUTE_NODE:
5694 tmp = ((xmlAttrPtr) node)->children;
5695 break;
5696 case XML_ELEMENT_NODE:
5697 tmp = node->children;
5698 break;
5699 default:
5700 return(0);
5701 }
5702 while (tmp != NULL) {
5703 switch (tmp->type) {
5704 case XML_CDATA_SECTION_NODE:
5705 case XML_TEXT_NODE:
5706 string = tmp->content;
5707 break;
5708 default:
5709 string = NULL;
5710 break;
5711 }
5712 if ((string != NULL) && (string[0] != 0)) {
5713 if (len == 1) {
5714 return(ret + (string[0] << 8));
5715 }
5716 if (string[1] == 0) {
5717 len = 1;
5718 ret = string[0];
5719 } else {
5720 return(string[0] + (string[1] << 8));
5721 }
5722 }
5723 /*
5724 * Skip to next node
5725 */
5726 if ((tmp->children != NULL) &&
5727 (tmp->type != XML_DTD_NODE) &&
5728 (tmp->type != XML_ENTITY_REF_NODE) &&
5729 (tmp->children->type != XML_ENTITY_DECL)) {
5730 tmp = tmp->children;
5731 continue;
5732 }
5733 if (tmp == node)
5734 break;
5735
5736 if (tmp->next != NULL) {
5737 tmp = tmp->next;
5738 continue;
5739 }
5740
5741 do {
5742 tmp = tmp->parent;
5743 if (tmp == NULL)
5744 break;
5745 if (tmp == node) {
5746 tmp = NULL;
5747 break;
5748 }
5749 if (tmp->next != NULL) {
5750 tmp = tmp->next;
5751 break;
5752 }
5753 } while (tmp != NULL);
5754 }
5755 return(ret);
5756}
5757
5758/**
5759 * xmlXPathStringHash:
5760 * @string: a string
5761 *
5762 * Function computing the beginning of the string value of the node,
5763 * used to speed up comparisons
5764 *
5765 * Returns an int usable as a hash
5766 */
5767static unsigned int
5768xmlXPathStringHash(const xmlChar * string) {
5769 if (string == NULL)
5770 return(0);
5771 if (string[0] == 0)
5772 return(0);
5773 return(string[0] + (string[1] << 8));
5774}
5775
5776/**
5777 * xmlXPathCompareNodeSetFloat:
5778 * @ctxt: the XPath Parser context
5779 * @inf: less than (1) or greater than (0)
5780 * @strict: is the comparison strict
5781 * @arg: the node set
5782 * @f: the value
5783 *
5784 * Implement the compare operation between a nodeset and a number
5785 * @ns < @val (1, 1, ...
5786 * @ns <= @val (1, 0, ...
5787 * @ns > @val (0, 1, ...
5788 * @ns >= @val (0, 0, ...
5789 *
5790 * If one object to be compared is a node-set and the other is a number,
5791 * then the comparison will be true if and only if there is a node in the
5792 * node-set such that the result of performing the comparison on the number
5793 * to be compared and on the result of converting the string-value of that
5794 * node to a number using the number function is true.
5795 *
5796 * Returns 0 or 1 depending on the results of the test.
5797 */
5798static int
5799xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5800 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5801 int i, ret = 0;
5802 xmlNodeSetPtr ns;
5803 xmlChar *str2;
5804
5805 if ((f == NULL) || (arg == NULL) ||
5806 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5807 xmlXPathReleaseObject(ctxt->context, arg);
5808 xmlXPathReleaseObject(ctxt->context, f);
5809 return(0);
5810 }
5811 ns = arg->nodesetval;
5812 if (ns != NULL) {
5813 for (i = 0;i < ns->nodeNr;i++) {
5814 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5815 if (str2 != NULL) {
5816 valuePush(ctxt,
5817 xmlXPathCacheNewString(ctxt->context, str2));
5818 xmlFree(str2);
5819 xmlXPathNumberFunction(ctxt, 1);
5820 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
5821 ret = xmlXPathCompareValues(ctxt, inf, strict);
5822 if (ret)
5823 break;
5824 }
5825 }
5826 }
5827 xmlXPathReleaseObject(ctxt->context, arg);
5828 xmlXPathReleaseObject(ctxt->context, f);
5829 return(ret);
5830}
5831
5832/**
5833 * xmlXPathCompareNodeSetString:
5834 * @ctxt: the XPath Parser context
5835 * @inf: less than (1) or greater than (0)
5836 * @strict: is the comparison strict
5837 * @arg: the node set
5838 * @s: the value
5839 *
5840 * Implement the compare operation between a nodeset and a string
5841 * @ns < @val (1, 1, ...
5842 * @ns <= @val (1, 0, ...
5843 * @ns > @val (0, 1, ...
5844 * @ns >= @val (0, 0, ...
5845 *
5846 * If one object to be compared is a node-set and the other is a string,
5847 * then the comparison will be true if and only if there is a node in
5848 * the node-set such that the result of performing the comparison on the
5849 * string-value of the node and the other string is true.
5850 *
5851 * Returns 0 or 1 depending on the results of the test.
5852 */
5853static int
5854xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5855 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5856 int i, ret = 0;
5857 xmlNodeSetPtr ns;
5858 xmlChar *str2;
5859
5860 if ((s == NULL) || (arg == NULL) ||
5861 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5862 xmlXPathReleaseObject(ctxt->context, arg);
5863 xmlXPathReleaseObject(ctxt->context, s);
5864 return(0);
5865 }
5866 ns = arg->nodesetval;
5867 if (ns != NULL) {
5868 for (i = 0;i < ns->nodeNr;i++) {
5869 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5870 if (str2 != NULL) {
5871 valuePush(ctxt,
5872 xmlXPathCacheNewString(ctxt->context, str2));
5873 xmlFree(str2);
5874 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
5875 ret = xmlXPathCompareValues(ctxt, inf, strict);
5876 if (ret)
5877 break;
5878 }
5879 }
5880 }
5881 xmlXPathReleaseObject(ctxt->context, arg);
5882 xmlXPathReleaseObject(ctxt->context, s);
5883 return(ret);
5884}
5885
5886/**
5887 * xmlXPathCompareNodeSets:
5888 * @inf: less than (1) or greater than (0)
5889 * @strict: is the comparison strict
5890 * @arg1: the first node set object
5891 * @arg2: the second node set object
5892 *
5893 * Implement the compare operation on nodesets:
5894 *
5895 * If both objects to be compared are node-sets, then the comparison
5896 * will be true if and only if there is a node in the first node-set
5897 * and a node in the second node-set such that the result of performing
5898 * the comparison on the string-values of the two nodes is true.
5899 * ....
5900 * When neither object to be compared is a node-set and the operator
5901 * is <=, <, >= or >, then the objects are compared by converting both
5902 * objects to numbers and comparing the numbers according to IEEE 754.
5903 * ....
5904 * The number function converts its argument to a number as follows:
5905 * - a string that consists of optional whitespace followed by an
5906 * optional minus sign followed by a Number followed by whitespace
5907 * is converted to the IEEE 754 number that is nearest (according
5908 * to the IEEE 754 round-to-nearest rule) to the mathematical value
5909 * represented by the string; any other string is converted to NaN
5910 *
5911 * Conclusion all nodes need to be converted first to their string value
5912 * and then the comparison must be done when possible
5913 */
5914static int
5915xmlXPathCompareNodeSets(int inf, int strict,
5916 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5917 int i, j, init = 0;
5918 double val1;
5919 double *values2;
5920 int ret = 0;
5921 xmlNodeSetPtr ns1;
5922 xmlNodeSetPtr ns2;
5923
5924 if ((arg1 == NULL) ||
5925 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5926 xmlXPathFreeObject(arg2);
5927 return(0);
5928 }
5929 if ((arg2 == NULL) ||
5930 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5931 xmlXPathFreeObject(arg1);
5932 xmlXPathFreeObject(arg2);
5933 return(0);
5934 }
5935
5936 ns1 = arg1->nodesetval;
5937 ns2 = arg2->nodesetval;
5938
5939 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5940 xmlXPathFreeObject(arg1);
5941 xmlXPathFreeObject(arg2);
5942 return(0);
5943 }
5944 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5945 xmlXPathFreeObject(arg1);
5946 xmlXPathFreeObject(arg2);
5947 return(0);
5948 }
5949
5950 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5951 if (values2 == NULL) {
5952 /* TODO: Propagate memory error. */
5953 xmlXPathErrMemory(NULL, "comparing nodesets\n");
5954 xmlXPathFreeObject(arg1);
5955 xmlXPathFreeObject(arg2);
5956 return(0);
5957 }
5958 for (i = 0;i < ns1->nodeNr;i++) {
5959 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
5960 if (xmlXPathIsNaN(val1))
5961 continue;
5962 for (j = 0;j < ns2->nodeNr;j++) {
5963 if (init == 0) {
5964 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
5965 }
5966 if (xmlXPathIsNaN(values2[j]))
5967 continue;
5968 if (inf && strict)
5969 ret = (val1 < values2[j]);
5970 else if (inf && !strict)
5971 ret = (val1 <= values2[j]);
5972 else if (!inf && strict)
5973 ret = (val1 > values2[j]);
5974 else if (!inf && !strict)
5975 ret = (val1 >= values2[j]);
5976 if (ret)
5977 break;
5978 }
5979 if (ret)
5980 break;
5981 init = 1;
5982 }
5983 xmlFree(values2);
5984 xmlXPathFreeObject(arg1);
5985 xmlXPathFreeObject(arg2);
5986 return(ret);
5987}
5988
5989/**
5990 * xmlXPathCompareNodeSetValue:
5991 * @ctxt: the XPath Parser context
5992 * @inf: less than (1) or greater than (0)
5993 * @strict: is the comparison strict
5994 * @arg: the node set
5995 * @val: the value
5996 *
5997 * Implement the compare operation between a nodeset and a value
5998 * @ns < @val (1, 1, ...
5999 * @ns <= @val (1, 0, ...
6000 * @ns > @val (0, 1, ...
6001 * @ns >= @val (0, 0, ...
6002 *
6003 * If one object to be compared is a node-set and the other is a boolean,
6004 * then the comparison will be true if and only if the result of performing
6005 * the comparison on the boolean and on the result of converting
6006 * the node-set to a boolean using the boolean function is true.
6007 *
6008 * Returns 0 or 1 depending on the results of the test.
6009 */
6010static int
6011xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6012 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6013 if ((val == NULL) || (arg == NULL) ||
6014 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6015 return(0);
6016
6017 switch(val->type) {
6018 case XPATH_NUMBER:
6019 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6020 case XPATH_NODESET:
6021 case XPATH_XSLT_TREE:
6022 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6023 case XPATH_STRING:
6024 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6025 case XPATH_BOOLEAN:
6026 valuePush(ctxt, arg);
6027 xmlXPathBooleanFunction(ctxt, 1);
6028 valuePush(ctxt, val);
6029 return(xmlXPathCompareValues(ctxt, inf, strict));
6030 default:
6031 xmlGenericError(xmlGenericErrorContext,
6032 "xmlXPathCompareNodeSetValue: Can't compare node set "
6033 "and object of type %d\n",
6034 val->type);
6035 xmlXPathReleaseObject(ctxt->context, arg);
6036 xmlXPathReleaseObject(ctxt->context, val);
6037 XP_ERROR0(XPATH_INVALID_TYPE);
6038 }
6039 return(0);
6040}
6041
6042/**
6043 * xmlXPathEqualNodeSetString:
6044 * @arg: the nodeset object argument
6045 * @str: the string to compare to.
6046 * @neq: flag to show whether for '=' (0) or '!=' (1)
6047 *
6048 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6049 * If one object to be compared is a node-set and the other is a string,
6050 * then the comparison will be true if and only if there is a node in
6051 * the node-set such that the result of performing the comparison on the
6052 * string-value of the node and the other string is true.
6053 *
6054 * Returns 0 or 1 depending on the results of the test.
6055 */
6056static int
6057xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6058{
6059 int i;
6060 xmlNodeSetPtr ns;
6061 xmlChar *str2;
6062 unsigned int hash;
6063
6064 if ((str == NULL) || (arg == NULL) ||
6065 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6066 return (0);
6067 ns = arg->nodesetval;
6068 /*
6069 * A NULL nodeset compared with a string is always false
6070 * (since there is no node equal, and no node not equal)
6071 */
6072 if ((ns == NULL) || (ns->nodeNr <= 0) )
6073 return (0);
6074 hash = xmlXPathStringHash(str);
6075 for (i = 0; i < ns->nodeNr; i++) {
6076 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6077 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6078 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6079 xmlFree(str2);
6080 if (neq)
6081 continue;
6082 return (1);
6083 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6084 if (neq)
6085 continue;
6086 return (1);
6087 } else if (neq) {
6088 if (str2 != NULL)
6089 xmlFree(str2);
6090 return (1);
6091 }
6092 if (str2 != NULL)
6093 xmlFree(str2);
6094 } else if (neq)
6095 return (1);
6096 }
6097 return (0);
6098}
6099
6100/**
6101 * xmlXPathEqualNodeSetFloat:
6102 * @arg: the nodeset object argument
6103 * @f: the float to compare to
6104 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6105 *
6106 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6107 * If one object to be compared is a node-set and the other is a number,
6108 * then the comparison will be true if and only if there is a node in
6109 * the node-set such that the result of performing the comparison on the
6110 * number to be compared and on the result of converting the string-value
6111 * of that node to a number using the number function is true.
6112 *
6113 * Returns 0 or 1 depending on the results of the test.
6114 */
6115static int
6116xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6117 xmlXPathObjectPtr arg, double f, int neq) {
6118 int i, ret=0;
6119 xmlNodeSetPtr ns;
6120 xmlChar *str2;
6121 xmlXPathObjectPtr val;
6122 double v;
6123
6124 if ((arg == NULL) ||
6125 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6126 return(0);
6127
6128 ns = arg->nodesetval;
6129 if (ns != NULL) {
6130 for (i=0;i<ns->nodeNr;i++) {
6131 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6132 if (str2 != NULL) {
6133 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6134 xmlFree(str2);
6135 xmlXPathNumberFunction(ctxt, 1);
6136 CHECK_ERROR0;
6137 val = valuePop(ctxt);
6138 v = val->floatval;
6139 xmlXPathReleaseObject(ctxt->context, val);
6140 if (!xmlXPathIsNaN(v)) {
6141 if ((!neq) && (v==f)) {
6142 ret = 1;
6143 break;
6144 } else if ((neq) && (v!=f)) {
6145 ret = 1;
6146 break;
6147 }
6148 } else { /* NaN is unequal to any value */
6149 if (neq)
6150 ret = 1;
6151 }
6152 }
6153 }
6154 }
6155
6156 return(ret);
6157}
6158
6159
6160/**
6161 * xmlXPathEqualNodeSets:
6162 * @arg1: first nodeset object argument
6163 * @arg2: second nodeset object argument
6164 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6165 *
6166 * Implement the equal / not equal operation on XPath nodesets:
6167 * @arg1 == @arg2 or @arg1 != @arg2
6168 * If both objects to be compared are node-sets, then the comparison
6169 * will be true if and only if there is a node in the first node-set and
6170 * a node in the second node-set such that the result of performing the
6171 * comparison on the string-values of the two nodes is true.
6172 *
6173 * (needless to say, this is a costly operation)
6174 *
6175 * Returns 0 or 1 depending on the results of the test.
6176 */
6177static int
6178xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6179 int i, j;
6180 unsigned int *hashs1;
6181 unsigned int *hashs2;
6182 xmlChar **values1;
6183 xmlChar **values2;
6184 int ret = 0;
6185 xmlNodeSetPtr ns1;
6186 xmlNodeSetPtr ns2;
6187
6188 if ((arg1 == NULL) ||
6189 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6190 return(0);
6191 if ((arg2 == NULL) ||
6192 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6193 return(0);
6194
6195 ns1 = arg1->nodesetval;
6196 ns2 = arg2->nodesetval;
6197
6198 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6199 return(0);
6200 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6201 return(0);
6202
6203 /*
6204 * for equal, check if there is a node pertaining to both sets
6205 */
6206 if (neq == 0)
6207 for (i = 0;i < ns1->nodeNr;i++)
6208 for (j = 0;j < ns2->nodeNr;j++)
6209 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6210 return(1);
6211
6212 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6213 if (values1 == NULL) {
6214 /* TODO: Propagate memory error. */
6215 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6216 return(0);
6217 }
6218 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6219 if (hashs1 == NULL) {
6220 /* TODO: Propagate memory error. */
6221 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6222 xmlFree(values1);
6223 return(0);
6224 }
6225 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6226 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6227 if (values2 == NULL) {
6228 /* TODO: Propagate memory error. */
6229 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6230 xmlFree(hashs1);
6231 xmlFree(values1);
6232 return(0);
6233 }
6234 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6235 if (hashs2 == NULL) {
6236 /* TODO: Propagate memory error. */
6237 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6238 xmlFree(hashs1);
6239 xmlFree(values1);
6240 xmlFree(values2);
6241 return(0);
6242 }
6243 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6244 for (i = 0;i < ns1->nodeNr;i++) {
6245 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6246 for (j = 0;j < ns2->nodeNr;j++) {
6247 if (i == 0)
6248 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6249 if (hashs1[i] != hashs2[j]) {
6250 if (neq) {
6251 ret = 1;
6252 break;
6253 }
6254 }
6255 else {
6256 if (values1[i] == NULL)
6257 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6258 if (values2[j] == NULL)
6259 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6260 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6261 if (ret)
6262 break;
6263 }
6264 }
6265 if (ret)
6266 break;
6267 }
6268 for (i = 0;i < ns1->nodeNr;i++)
6269 if (values1[i] != NULL)
6270 xmlFree(values1[i]);
6271 for (j = 0;j < ns2->nodeNr;j++)
6272 if (values2[j] != NULL)
6273 xmlFree(values2[j]);
6274 xmlFree(values1);
6275 xmlFree(values2);
6276 xmlFree(hashs1);
6277 xmlFree(hashs2);
6278 return(ret);
6279}
6280
6281static int
6282xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6283 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6284 int ret = 0;
6285 /*
6286 *At this point we are assured neither arg1 nor arg2
6287 *is a nodeset, so we can just pick the appropriate routine.
6288 */
6289 switch (arg1->type) {
6290 case XPATH_UNDEFINED:
6291 break;
6292 case XPATH_BOOLEAN:
6293 switch (arg2->type) {
6294 case XPATH_UNDEFINED:
6295 break;
6296 case XPATH_BOOLEAN:
6297 ret = (arg1->boolval == arg2->boolval);
6298 break;
6299 case XPATH_NUMBER:
6300 ret = (arg1->boolval ==
6301 xmlXPathCastNumberToBoolean(arg2->floatval));
6302 break;
6303 case XPATH_STRING:
6304 if ((arg2->stringval == NULL) ||
6305 (arg2->stringval[0] == 0)) ret = 0;
6306 else
6307 ret = 1;
6308 ret = (arg1->boolval == ret);
6309 break;
6310 case XPATH_USERS:
6311#ifdef LIBXML_XPTR_LOCS_ENABLED
6312 case XPATH_POINT:
6313 case XPATH_RANGE:
6314 case XPATH_LOCATIONSET:
6315#endif /* LIBXML_XPTR_LOCS_ENABLED */
6316 TODO
6317 break;
6318 case XPATH_NODESET:
6319 case XPATH_XSLT_TREE:
6320 break;
6321 }
6322 break;
6323 case XPATH_NUMBER:
6324 switch (arg2->type) {
6325 case XPATH_UNDEFINED:
6326 break;
6327 case XPATH_BOOLEAN:
6328 ret = (arg2->boolval==
6329 xmlXPathCastNumberToBoolean(arg1->floatval));
6330 break;
6331 case XPATH_STRING:
6332 valuePush(ctxt, arg2);
6333 xmlXPathNumberFunction(ctxt, 1);
6334 arg2 = valuePop(ctxt);
6335 if (ctxt->error)
6336 break;
6337 /* Falls through. */
6338 case XPATH_NUMBER:
6339 /* Hand check NaN and Infinity equalities */
6340 if (xmlXPathIsNaN(arg1->floatval) ||
6341 xmlXPathIsNaN(arg2->floatval)) {
6342 ret = 0;
6343 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6344 if (xmlXPathIsInf(arg2->floatval) == 1)
6345 ret = 1;
6346 else
6347 ret = 0;
6348 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6349 if (xmlXPathIsInf(arg2->floatval) == -1)
6350 ret = 1;
6351 else
6352 ret = 0;
6353 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6354 if (xmlXPathIsInf(arg1->floatval) == 1)
6355 ret = 1;
6356 else
6357 ret = 0;
6358 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6359 if (xmlXPathIsInf(arg1->floatval) == -1)
6360 ret = 1;
6361 else
6362 ret = 0;
6363 } else {
6364 ret = (arg1->floatval == arg2->floatval);
6365 }
6366 break;
6367 case XPATH_USERS:
6368#ifdef LIBXML_XPTR_LOCS_ENABLED
6369 case XPATH_POINT:
6370 case XPATH_RANGE:
6371 case XPATH_LOCATIONSET:
6372#endif /* LIBXML_XPTR_LOCS_ENABLED */
6373 TODO
6374 break;
6375 case XPATH_NODESET:
6376 case XPATH_XSLT_TREE:
6377 break;
6378 }
6379 break;
6380 case XPATH_STRING:
6381 switch (arg2->type) {
6382 case XPATH_UNDEFINED:
6383 break;
6384 case XPATH_BOOLEAN:
6385 if ((arg1->stringval == NULL) ||
6386 (arg1->stringval[0] == 0)) ret = 0;
6387 else
6388 ret = 1;
6389 ret = (arg2->boolval == ret);
6390 break;
6391 case XPATH_STRING:
6392 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6393 break;
6394 case XPATH_NUMBER:
6395 valuePush(ctxt, arg1);
6396 xmlXPathNumberFunction(ctxt, 1);
6397 arg1 = valuePop(ctxt);
6398 if (ctxt->error)
6399 break;
6400 /* Hand check NaN and Infinity equalities */
6401 if (xmlXPathIsNaN(arg1->floatval) ||
6402 xmlXPathIsNaN(arg2->floatval)) {
6403 ret = 0;
6404 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6405 if (xmlXPathIsInf(arg2->floatval) == 1)
6406 ret = 1;
6407 else
6408 ret = 0;
6409 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6410 if (xmlXPathIsInf(arg2->floatval) == -1)
6411 ret = 1;
6412 else
6413 ret = 0;
6414 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6415 if (xmlXPathIsInf(arg1->floatval) == 1)
6416 ret = 1;
6417 else
6418 ret = 0;
6419 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6420 if (xmlXPathIsInf(arg1->floatval) == -1)
6421 ret = 1;
6422 else
6423 ret = 0;
6424 } else {
6425 ret = (arg1->floatval == arg2->floatval);
6426 }
6427 break;
6428 case XPATH_USERS:
6429#ifdef LIBXML_XPTR_LOCS_ENABLED
6430 case XPATH_POINT:
6431 case XPATH_RANGE:
6432 case XPATH_LOCATIONSET:
6433#endif /* LIBXML_XPTR_LOCS_ENABLED */
6434 TODO
6435 break;
6436 case XPATH_NODESET:
6437 case XPATH_XSLT_TREE:
6438 break;
6439 }
6440 break;
6441 case XPATH_USERS:
6442#ifdef LIBXML_XPTR_LOCS_ENABLED
6443 case XPATH_POINT:
6444 case XPATH_RANGE:
6445 case XPATH_LOCATIONSET:
6446#endif /* LIBXML_XPTR_LOCS_ENABLED */
6447 TODO
6448 break;
6449 case XPATH_NODESET:
6450 case XPATH_XSLT_TREE:
6451 break;
6452 }
6453 xmlXPathReleaseObject(ctxt->context, arg1);
6454 xmlXPathReleaseObject(ctxt->context, arg2);
6455 return(ret);
6456}
6457
6458/**
6459 * xmlXPathEqualValues:
6460 * @ctxt: the XPath Parser context
6461 *
6462 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6463 *
6464 * Returns 0 or 1 depending on the results of the test.
6465 */
6466int
6467xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6468 xmlXPathObjectPtr arg1, arg2, argtmp;
6469 int ret = 0;
6470
6471 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6472 arg2 = valuePop(ctxt);
6473 arg1 = valuePop(ctxt);
6474 if ((arg1 == NULL) || (arg2 == NULL)) {
6475 if (arg1 != NULL)
6476 xmlXPathReleaseObject(ctxt->context, arg1);
6477 else
6478 xmlXPathReleaseObject(ctxt->context, arg2);
6479 XP_ERROR0(XPATH_INVALID_OPERAND);
6480 }
6481
6482 if (arg1 == arg2) {
6483 xmlXPathFreeObject(arg1);
6484 return(1);
6485 }
6486
6487 /*
6488 *If either argument is a nodeset, it's a 'special case'
6489 */
6490 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6491 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6492 /*
6493 *Hack it to assure arg1 is the nodeset
6494 */
6495 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6496 argtmp = arg2;
6497 arg2 = arg1;
6498 arg1 = argtmp;
6499 }
6500 switch (arg2->type) {
6501 case XPATH_UNDEFINED:
6502 break;
6503 case XPATH_NODESET:
6504 case XPATH_XSLT_TREE:
6505 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
6506 break;
6507 case XPATH_BOOLEAN:
6508 if ((arg1->nodesetval == NULL) ||
6509 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6510 else
6511 ret = 1;
6512 ret = (ret == arg2->boolval);
6513 break;
6514 case XPATH_NUMBER:
6515 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6516 break;
6517 case XPATH_STRING:
6518 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
6519 break;
6520 case XPATH_USERS:
6521#ifdef LIBXML_XPTR_LOCS_ENABLED
6522 case XPATH_POINT:
6523 case XPATH_RANGE:
6524 case XPATH_LOCATIONSET:
6525#endif /* LIBXML_XPTR_LOCS_ENABLED */
6526 TODO
6527 break;
6528 }
6529 xmlXPathReleaseObject(ctxt->context, arg1);
6530 xmlXPathReleaseObject(ctxt->context, arg2);
6531 return(ret);
6532 }
6533
6534 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6535}
6536
6537/**
6538 * xmlXPathNotEqualValues:
6539 * @ctxt: the XPath Parser context
6540 *
6541 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6542 *
6543 * Returns 0 or 1 depending on the results of the test.
6544 */
6545int
6546xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6547 xmlXPathObjectPtr arg1, arg2, argtmp;
6548 int ret = 0;
6549
6550 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6551 arg2 = valuePop(ctxt);
6552 arg1 = valuePop(ctxt);
6553 if ((arg1 == NULL) || (arg2 == NULL)) {
6554 if (arg1 != NULL)
6555 xmlXPathReleaseObject(ctxt->context, arg1);
6556 else
6557 xmlXPathReleaseObject(ctxt->context, arg2);
6558 XP_ERROR0(XPATH_INVALID_OPERAND);
6559 }
6560
6561 if (arg1 == arg2) {
6562 xmlXPathReleaseObject(ctxt->context, arg1);
6563 return(0);
6564 }
6565
6566 /*
6567 *If either argument is a nodeset, it's a 'special case'
6568 */
6569 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6570 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6571 /*
6572 *Hack it to assure arg1 is the nodeset
6573 */
6574 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6575 argtmp = arg2;
6576 arg2 = arg1;
6577 arg1 = argtmp;
6578 }
6579 switch (arg2->type) {
6580 case XPATH_UNDEFINED:
6581 break;
6582 case XPATH_NODESET:
6583 case XPATH_XSLT_TREE:
6584 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
6585 break;
6586 case XPATH_BOOLEAN:
6587 if ((arg1->nodesetval == NULL) ||
6588 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6589 else
6590 ret = 1;
6591 ret = (ret != arg2->boolval);
6592 break;
6593 case XPATH_NUMBER:
6594 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6595 break;
6596 case XPATH_STRING:
6597 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
6598 break;
6599 case XPATH_USERS:
6600#ifdef LIBXML_XPTR_LOCS_ENABLED
6601 case XPATH_POINT:
6602 case XPATH_RANGE:
6603 case XPATH_LOCATIONSET:
6604#endif /* LIBXML_XPTR_LOCS_ENABLED */
6605 TODO
6606 break;
6607 }
6608 xmlXPathReleaseObject(ctxt->context, arg1);
6609 xmlXPathReleaseObject(ctxt->context, arg2);
6610 return(ret);
6611 }
6612
6613 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6614}
6615
6616/**
6617 * xmlXPathCompareValues:
6618 * @ctxt: the XPath Parser context
6619 * @inf: less than (1) or greater than (0)
6620 * @strict: is the comparison strict
6621 *
6622 * Implement the compare operation on XPath objects:
6623 * @arg1 < @arg2 (1, 1, ...
6624 * @arg1 <= @arg2 (1, 0, ...
6625 * @arg1 > @arg2 (0, 1, ...
6626 * @arg1 >= @arg2 (0, 0, ...
6627 *
6628 * When neither object to be compared is a node-set and the operator is
6629 * <=, <, >=, >, then the objects are compared by converted both objects
6630 * to numbers and comparing the numbers according to IEEE 754. The <
6631 * comparison will be true if and only if the first number is less than the
6632 * second number. The <= comparison will be true if and only if the first
6633 * number is less than or equal to the second number. The > comparison
6634 * will be true if and only if the first number is greater than the second
6635 * number. The >= comparison will be true if and only if the first number
6636 * is greater than or equal to the second number.
6637 *
6638 * Returns 1 if the comparison succeeded, 0 if it failed
6639 */
6640int
6641xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6642 int ret = 0, arg1i = 0, arg2i = 0;
6643 xmlXPathObjectPtr arg1, arg2;
6644
6645 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6646 arg2 = valuePop(ctxt);
6647 arg1 = valuePop(ctxt);
6648 if ((arg1 == NULL) || (arg2 == NULL)) {
6649 if (arg1 != NULL)
6650 xmlXPathReleaseObject(ctxt->context, arg1);
6651 else
6652 xmlXPathReleaseObject(ctxt->context, arg2);
6653 XP_ERROR0(XPATH_INVALID_OPERAND);
6654 }
6655
6656 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6657 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6658 /*
6659 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6660 * are not freed from within this routine; they will be freed from the
6661 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6662 */
6663 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6664 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6665 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
6666 } else {
6667 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6668 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6669 arg1, arg2);
6670 } else {
6671 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6672 arg2, arg1);
6673 }
6674 }
6675 return(ret);
6676 }
6677
6678 if (arg1->type != XPATH_NUMBER) {
6679 valuePush(ctxt, arg1);
6680 xmlXPathNumberFunction(ctxt, 1);
6681 arg1 = valuePop(ctxt);
6682 }
6683 if (arg2->type != XPATH_NUMBER) {
6684 valuePush(ctxt, arg2);
6685 xmlXPathNumberFunction(ctxt, 1);
6686 arg2 = valuePop(ctxt);
6687 }
6688 if (ctxt->error)
6689 goto error;
6690 /*
6691 * Add tests for infinity and nan
6692 * => feedback on 3.4 for Inf and NaN
6693 */
6694 /* Hand check NaN and Infinity comparisons */
6695 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6696 ret=0;
6697 } else {
6698 arg1i=xmlXPathIsInf(arg1->floatval);
6699 arg2i=xmlXPathIsInf(arg2->floatval);
6700 if (inf && strict) {
6701 if ((arg1i == -1 && arg2i != -1) ||
6702 (arg2i == 1 && arg1i != 1)) {
6703 ret = 1;
6704 } else if (arg1i == 0 && arg2i == 0) {
6705 ret = (arg1->floatval < arg2->floatval);
6706 } else {
6707 ret = 0;
6708 }
6709 }
6710 else if (inf && !strict) {
6711 if (arg1i == -1 || arg2i == 1) {
6712 ret = 1;
6713 } else if (arg1i == 0 && arg2i == 0) {
6714 ret = (arg1->floatval <= arg2->floatval);
6715 } else {
6716 ret = 0;
6717 }
6718 }
6719 else if (!inf && strict) {
6720 if ((arg1i == 1 && arg2i != 1) ||
6721 (arg2i == -1 && arg1i != -1)) {
6722 ret = 1;
6723 } else if (arg1i == 0 && arg2i == 0) {
6724 ret = (arg1->floatval > arg2->floatval);
6725 } else {
6726 ret = 0;
6727 }
6728 }
6729 else if (!inf && !strict) {
6730 if (arg1i == 1 || arg2i == -1) {
6731 ret = 1;
6732 } else if (arg1i == 0 && arg2i == 0) {
6733 ret = (arg1->floatval >= arg2->floatval);
6734 } else {
6735 ret = 0;
6736 }
6737 }
6738 }
6739error:
6740 xmlXPathReleaseObject(ctxt->context, arg1);
6741 xmlXPathReleaseObject(ctxt->context, arg2);
6742 return(ret);
6743}
6744
6745/**
6746 * xmlXPathValueFlipSign:
6747 * @ctxt: the XPath Parser context
6748 *
6749 * Implement the unary - operation on an XPath object
6750 * The numeric operators convert their operands to numbers as if
6751 * by calling the number function.
6752 */
6753void
6754xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6755 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6756 CAST_TO_NUMBER;
6757 CHECK_TYPE(XPATH_NUMBER);
6758 ctxt->value->floatval = -ctxt->value->floatval;
6759}
6760
6761/**
6762 * xmlXPathAddValues:
6763 * @ctxt: the XPath Parser context
6764 *
6765 * Implement the add operation on XPath objects:
6766 * The numeric operators convert their operands to numbers as if
6767 * by calling the number function.
6768 */
6769void
6770xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6771 xmlXPathObjectPtr arg;
6772 double val;
6773
6774 arg = valuePop(ctxt);
6775 if (arg == NULL)
6776 XP_ERROR(XPATH_INVALID_OPERAND);
6777 val = xmlXPathCastToNumber(arg);
6778 xmlXPathReleaseObject(ctxt->context, arg);
6779 CAST_TO_NUMBER;
6780 CHECK_TYPE(XPATH_NUMBER);
6781 ctxt->value->floatval += val;
6782}
6783
6784/**
6785 * xmlXPathSubValues:
6786 * @ctxt: the XPath Parser context
6787 *
6788 * Implement the subtraction operation on XPath objects:
6789 * The numeric operators convert their operands to numbers as if
6790 * by calling the number function.
6791 */
6792void
6793xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6794 xmlXPathObjectPtr arg;
6795 double val;
6796
6797 arg = valuePop(ctxt);
6798 if (arg == NULL)
6799 XP_ERROR(XPATH_INVALID_OPERAND);
6800 val = xmlXPathCastToNumber(arg);
6801 xmlXPathReleaseObject(ctxt->context, arg);
6802 CAST_TO_NUMBER;
6803 CHECK_TYPE(XPATH_NUMBER);
6804 ctxt->value->floatval -= val;
6805}
6806
6807/**
6808 * xmlXPathMultValues:
6809 * @ctxt: the XPath Parser context
6810 *
6811 * Implement the multiply operation on XPath objects:
6812 * The numeric operators convert their operands to numbers as if
6813 * by calling the number function.
6814 */
6815void
6816xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6817 xmlXPathObjectPtr arg;
6818 double val;
6819
6820 arg = valuePop(ctxt);
6821 if (arg == NULL)
6822 XP_ERROR(XPATH_INVALID_OPERAND);
6823 val = xmlXPathCastToNumber(arg);
6824 xmlXPathReleaseObject(ctxt->context, arg);
6825 CAST_TO_NUMBER;
6826 CHECK_TYPE(XPATH_NUMBER);
6827 ctxt->value->floatval *= val;
6828}
6829
6830/**
6831 * xmlXPathDivValues:
6832 * @ctxt: the XPath Parser context
6833 *
6834 * Implement the div operation on XPath objects @arg1 / @arg2:
6835 * The numeric operators convert their operands to numbers as if
6836 * by calling the number function.
6837 */
6838ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6839void
6840xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6841 xmlXPathObjectPtr arg;
6842 double val;
6843
6844 arg = valuePop(ctxt);
6845 if (arg == NULL)
6846 XP_ERROR(XPATH_INVALID_OPERAND);
6847 val = xmlXPathCastToNumber(arg);
6848 xmlXPathReleaseObject(ctxt->context, arg);
6849 CAST_TO_NUMBER;
6850 CHECK_TYPE(XPATH_NUMBER);
6851 ctxt->value->floatval /= val;
6852}
6853
6854/**
6855 * xmlXPathModValues:
6856 * @ctxt: the XPath Parser context
6857 *
6858 * Implement the mod operation on XPath objects: @arg1 / @arg2
6859 * The numeric operators convert their operands to numbers as if
6860 * by calling the number function.
6861 */
6862void
6863xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6864 xmlXPathObjectPtr arg;
6865 double arg1, arg2;
6866
6867 arg = valuePop(ctxt);
6868 if (arg == NULL)
6869 XP_ERROR(XPATH_INVALID_OPERAND);
6870 arg2 = xmlXPathCastToNumber(arg);
6871 xmlXPathReleaseObject(ctxt->context, arg);
6872 CAST_TO_NUMBER;
6873 CHECK_TYPE(XPATH_NUMBER);
6874 arg1 = ctxt->value->floatval;
6875 if (arg2 == 0)
6876 ctxt->value->floatval = xmlXPathNAN;
6877 else {
6878 ctxt->value->floatval = fmod(arg1, arg2);
6879 }
6880}
6881
6882/************************************************************************
6883 * *
6884 * The traversal functions *
6885 * *
6886 ************************************************************************/
6887
6888/*
6889 * A traversal function enumerates nodes along an axis.
6890 * Initially it must be called with NULL, and it indicates
6891 * termination on the axis by returning NULL.
6892 */
6893typedef xmlNodePtr (*xmlXPathTraversalFunction)
6894 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6895
6896/*
6897 * xmlXPathTraversalFunctionExt:
6898 * A traversal function enumerates nodes along an axis.
6899 * Initially it must be called with NULL, and it indicates
6900 * termination on the axis by returning NULL.
6901 * The context node of the traversal is specified via @contextNode.
6902 */
6903typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6904 (xmlNodePtr cur, xmlNodePtr contextNode);
6905
6906/*
6907 * xmlXPathNodeSetMergeFunction:
6908 * Used for merging node sets in xmlXPathCollectAndTest().
6909 */
6910typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6911 (xmlNodeSetPtr, xmlNodeSetPtr);
6912
6913
6914/**
6915 * xmlXPathNextSelf:
6916 * @ctxt: the XPath Parser context
6917 * @cur: the current node in the traversal
6918 *
6919 * Traversal function for the "self" direction
6920 * The self axis contains just the context node itself
6921 *
6922 * Returns the next element following that axis
6923 */
6924xmlNodePtr
6925xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6926 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6927 if (cur == NULL)
6928 return(ctxt->context->node);
6929 return(NULL);
6930}
6931
6932/**
6933 * xmlXPathNextChild:
6934 * @ctxt: the XPath Parser context
6935 * @cur: the current node in the traversal
6936 *
6937 * Traversal function for the "child" direction
6938 * The child axis contains the children of the context node in document order.
6939 *
6940 * Returns the next element following that axis
6941 */
6942xmlNodePtr
6943xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6944 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6945 if (cur == NULL) {
6946 if (ctxt->context->node == NULL) return(NULL);
6947 switch (ctxt->context->node->type) {
6948 case XML_ELEMENT_NODE:
6949 case XML_TEXT_NODE:
6950 case XML_CDATA_SECTION_NODE:
6951 case XML_ENTITY_REF_NODE:
6952 case XML_ENTITY_NODE:
6953 case XML_PI_NODE:
6954 case XML_COMMENT_NODE:
6955 case XML_NOTATION_NODE:
6956 case XML_DTD_NODE:
6957 return(ctxt->context->node->children);
6958 case XML_DOCUMENT_NODE:
6959 case XML_DOCUMENT_TYPE_NODE:
6960 case XML_DOCUMENT_FRAG_NODE:
6961 case XML_HTML_DOCUMENT_NODE:
6962 return(((xmlDocPtr) ctxt->context->node)->children);
6963 case XML_ELEMENT_DECL:
6964 case XML_ATTRIBUTE_DECL:
6965 case XML_ENTITY_DECL:
6966 case XML_ATTRIBUTE_NODE:
6967 case XML_NAMESPACE_DECL:
6968 case XML_XINCLUDE_START:
6969 case XML_XINCLUDE_END:
6970 return(NULL);
6971 }
6972 return(NULL);
6973 }
6974 if ((cur->type == XML_DOCUMENT_NODE) ||
6975 (cur->type == XML_HTML_DOCUMENT_NODE))
6976 return(NULL);
6977 return(cur->next);
6978}
6979
6980/**
6981 * xmlXPathNextChildElement:
6982 * @ctxt: the XPath Parser context
6983 * @cur: the current node in the traversal
6984 *
6985 * Traversal function for the "child" direction and nodes of type element.
6986 * The child axis contains the children of the context node in document order.
6987 *
6988 * Returns the next element following that axis
6989 */
6990static xmlNodePtr
6991xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6992 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6993 if (cur == NULL) {
6994 cur = ctxt->context->node;
6995 if (cur == NULL) return(NULL);
6996 /*
6997 * Get the first element child.
6998 */
6999 switch (cur->type) {
7000 case XML_ELEMENT_NODE:
7001 case XML_DOCUMENT_FRAG_NODE:
7002 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7003 case XML_ENTITY_NODE:
7004 cur = cur->children;
7005 if (cur != NULL) {
7006 if (cur->type == XML_ELEMENT_NODE)
7007 return(cur);
7008 do {
7009 cur = cur->next;
7010 } while ((cur != NULL) &&
7011 (cur->type != XML_ELEMENT_NODE));
7012 return(cur);
7013 }
7014 return(NULL);
7015 case XML_DOCUMENT_NODE:
7016 case XML_HTML_DOCUMENT_NODE:
7017 return(xmlDocGetRootElement((xmlDocPtr) cur));
7018 default:
7019 return(NULL);
7020 }
7021 return(NULL);
7022 }
7023 /*
7024 * Get the next sibling element node.
7025 */
7026 switch (cur->type) {
7027 case XML_ELEMENT_NODE:
7028 case XML_TEXT_NODE:
7029 case XML_ENTITY_REF_NODE:
7030 case XML_ENTITY_NODE:
7031 case XML_CDATA_SECTION_NODE:
7032 case XML_PI_NODE:
7033 case XML_COMMENT_NODE:
7034 case XML_XINCLUDE_END:
7035 break;
7036 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7037 default:
7038 return(NULL);
7039 }
7040 if (cur->next != NULL) {
7041 if (cur->next->type == XML_ELEMENT_NODE)
7042 return(cur->next);
7043 cur = cur->next;
7044 do {
7045 cur = cur->next;
7046 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7047 return(cur);
7048 }
7049 return(NULL);
7050}
7051
7052#if 0
7053/**
7054 * xmlXPathNextDescendantOrSelfElemParent:
7055 * @ctxt: the XPath Parser context
7056 * @cur: the current node in the traversal
7057 *
7058 * Traversal function for the "descendant-or-self" axis.
7059 * Additionally it returns only nodes which can be parents of
7060 * element nodes.
7061 *
7062 *
7063 * Returns the next element following that axis
7064 */
7065static xmlNodePtr
7066xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7067 xmlNodePtr contextNode)
7068{
7069 if (cur == NULL) {
7070 if (contextNode == NULL)
7071 return(NULL);
7072 switch (contextNode->type) {
7073 case XML_ELEMENT_NODE:
7074 case XML_XINCLUDE_START:
7075 case XML_DOCUMENT_FRAG_NODE:
7076 case XML_DOCUMENT_NODE:
7077 case XML_HTML_DOCUMENT_NODE:
7078 return(contextNode);
7079 default:
7080 return(NULL);
7081 }
7082 return(NULL);
7083 } else {
7084 xmlNodePtr start = cur;
7085
7086 while (cur != NULL) {
7087 switch (cur->type) {
7088 case XML_ELEMENT_NODE:
7089 /* TODO: OK to have XInclude here? */
7090 case XML_XINCLUDE_START:
7091 case XML_DOCUMENT_FRAG_NODE:
7092 if (cur != start)
7093 return(cur);
7094 if (cur->children != NULL) {
7095 cur = cur->children;
7096 continue;
7097 }
7098 break;
7099 /* Not sure if we need those here. */
7100 case XML_DOCUMENT_NODE:
7101 case XML_HTML_DOCUMENT_NODE:
7102 if (cur != start)
7103 return(cur);
7104 return(xmlDocGetRootElement((xmlDocPtr) cur));
7105 default:
7106 break;
7107 }
7108
7109next_sibling:
7110 if ((cur == NULL) || (cur == contextNode))
7111 return(NULL);
7112 if (cur->next != NULL) {
7113 cur = cur->next;
7114 } else {
7115 cur = cur->parent;
7116 goto next_sibling;
7117 }
7118 }
7119 }
7120 return(NULL);
7121}
7122#endif
7123
7124/**
7125 * xmlXPathNextDescendant:
7126 * @ctxt: the XPath Parser context
7127 * @cur: the current node in the traversal
7128 *
7129 * Traversal function for the "descendant" direction
7130 * the descendant axis contains the descendants of the context node in document
7131 * order; a descendant is a child or a child of a child and so on.
7132 *
7133 * Returns the next element following that axis
7134 */
7135xmlNodePtr
7136xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7137 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7138 if (cur == NULL) {
7139 if (ctxt->context->node == NULL)
7140 return(NULL);
7141 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7142 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7143 return(NULL);
7144
7145 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7146 return(ctxt->context->doc->children);
7147 return(ctxt->context->node->children);
7148 }
7149
7150 if (cur->type == XML_NAMESPACE_DECL)
7151 return(NULL);
7152 if (cur->children != NULL) {
7153 /*
7154 * Do not descend on entities declarations
7155 */
7156 if (cur->children->type != XML_ENTITY_DECL) {
7157 cur = cur->children;
7158 /*
7159 * Skip DTDs
7160 */
7161 if (cur->type != XML_DTD_NODE)
7162 return(cur);
7163 }
7164 }
7165
7166 if (cur == ctxt->context->node) return(NULL);
7167
7168 while (cur->next != NULL) {
7169 cur = cur->next;
7170 if ((cur->type != XML_ENTITY_DECL) &&
7171 (cur->type != XML_DTD_NODE))
7172 return(cur);
7173 }
7174
7175 do {
7176 cur = cur->parent;
7177 if (cur == NULL) break;
7178 if (cur == ctxt->context->node) return(NULL);
7179 if (cur->next != NULL) {
7180 cur = cur->next;
7181 return(cur);
7182 }
7183 } while (cur != NULL);
7184 return(cur);
7185}
7186
7187/**
7188 * xmlXPathNextDescendantOrSelf:
7189 * @ctxt: the XPath Parser context
7190 * @cur: the current node in the traversal
7191 *
7192 * Traversal function for the "descendant-or-self" direction
7193 * the descendant-or-self axis contains the context node and the descendants
7194 * of the context node in document order; thus the context node is the first
7195 * node on the axis, and the first child of the context node is the second node
7196 * on the axis
7197 *
7198 * Returns the next element following that axis
7199 */
7200xmlNodePtr
7201xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7202 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7203 if (cur == NULL)
7204 return(ctxt->context->node);
7205
7206 if (ctxt->context->node == NULL)
7207 return(NULL);
7208 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7209 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7210 return(NULL);
7211
7212 return(xmlXPathNextDescendant(ctxt, cur));
7213}
7214
7215/**
7216 * xmlXPathNextParent:
7217 * @ctxt: the XPath Parser context
7218 * @cur: the current node in the traversal
7219 *
7220 * Traversal function for the "parent" direction
7221 * The parent axis contains the parent of the context node, if there is one.
7222 *
7223 * Returns the next element following that axis
7224 */
7225xmlNodePtr
7226xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7227 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7228 /*
7229 * the parent of an attribute or namespace node is the element
7230 * to which the attribute or namespace node is attached
7231 * Namespace handling !!!
7232 */
7233 if (cur == NULL) {
7234 if (ctxt->context->node == NULL) return(NULL);
7235 switch (ctxt->context->node->type) {
7236 case XML_ELEMENT_NODE:
7237 case XML_TEXT_NODE:
7238 case XML_CDATA_SECTION_NODE:
7239 case XML_ENTITY_REF_NODE:
7240 case XML_ENTITY_NODE:
7241 case XML_PI_NODE:
7242 case XML_COMMENT_NODE:
7243 case XML_NOTATION_NODE:
7244 case XML_DTD_NODE:
7245 case XML_ELEMENT_DECL:
7246 case XML_ATTRIBUTE_DECL:
7247 case XML_XINCLUDE_START:
7248 case XML_XINCLUDE_END:
7249 case XML_ENTITY_DECL:
7250 if (ctxt->context->node->parent == NULL)
7251 return((xmlNodePtr) ctxt->context->doc);
7252 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7253 ((ctxt->context->node->parent->name[0] == ' ') ||
7254 (xmlStrEqual(ctxt->context->node->parent->name,
7255 BAD_CAST "fake node libxslt"))))
7256 return(NULL);
7257 return(ctxt->context->node->parent);
7258 case XML_ATTRIBUTE_NODE: {
7259 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7260
7261 return(att->parent);
7262 }
7263 case XML_DOCUMENT_NODE:
7264 case XML_DOCUMENT_TYPE_NODE:
7265 case XML_DOCUMENT_FRAG_NODE:
7266 case XML_HTML_DOCUMENT_NODE:
7267 return(NULL);
7268 case XML_NAMESPACE_DECL: {
7269 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7270
7271 if ((ns->next != NULL) &&
7272 (ns->next->type != XML_NAMESPACE_DECL))
7273 return((xmlNodePtr) ns->next);
7274 return(NULL);
7275 }
7276 }
7277 }
7278 return(NULL);
7279}
7280
7281/**
7282 * xmlXPathNextAncestor:
7283 * @ctxt: the XPath Parser context
7284 * @cur: the current node in the traversal
7285 *
7286 * Traversal function for the "ancestor" direction
7287 * the ancestor axis contains the ancestors of the context node; the ancestors
7288 * of the context node consist of the parent of context node and the parent's
7289 * parent and so on; the nodes are ordered in reverse document order; thus the
7290 * parent is the first node on the axis, and the parent's parent is the second
7291 * node on the axis
7292 *
7293 * Returns the next element following that axis
7294 */
7295xmlNodePtr
7296xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7297 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7298 /*
7299 * the parent of an attribute or namespace node is the element
7300 * to which the attribute or namespace node is attached
7301 * !!!!!!!!!!!!!
7302 */
7303 if (cur == NULL) {
7304 if (ctxt->context->node == NULL) return(NULL);
7305 switch (ctxt->context->node->type) {
7306 case XML_ELEMENT_NODE:
7307 case XML_TEXT_NODE:
7308 case XML_CDATA_SECTION_NODE:
7309 case XML_ENTITY_REF_NODE:
7310 case XML_ENTITY_NODE:
7311 case XML_PI_NODE:
7312 case XML_COMMENT_NODE:
7313 case XML_DTD_NODE:
7314 case XML_ELEMENT_DECL:
7315 case XML_ATTRIBUTE_DECL:
7316 case XML_ENTITY_DECL:
7317 case XML_NOTATION_NODE:
7318 case XML_XINCLUDE_START:
7319 case XML_XINCLUDE_END:
7320 if (ctxt->context->node->parent == NULL)
7321 return((xmlNodePtr) ctxt->context->doc);
7322 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7323 ((ctxt->context->node->parent->name[0] == ' ') ||
7324 (xmlStrEqual(ctxt->context->node->parent->name,
7325 BAD_CAST "fake node libxslt"))))
7326 return(NULL);
7327 return(ctxt->context->node->parent);
7328 case XML_ATTRIBUTE_NODE: {
7329 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7330
7331 return(tmp->parent);
7332 }
7333 case XML_DOCUMENT_NODE:
7334 case XML_DOCUMENT_TYPE_NODE:
7335 case XML_DOCUMENT_FRAG_NODE:
7336 case XML_HTML_DOCUMENT_NODE:
7337 return(NULL);
7338 case XML_NAMESPACE_DECL: {
7339 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7340
7341 if ((ns->next != NULL) &&
7342 (ns->next->type != XML_NAMESPACE_DECL))
7343 return((xmlNodePtr) ns->next);
7344 /* Bad, how did that namespace end up here ? */
7345 return(NULL);
7346 }
7347 }
7348 return(NULL);
7349 }
7350 if (cur == ctxt->context->doc->children)
7351 return((xmlNodePtr) ctxt->context->doc);
7352 if (cur == (xmlNodePtr) ctxt->context->doc)
7353 return(NULL);
7354 switch (cur->type) {
7355 case XML_ELEMENT_NODE:
7356 case XML_TEXT_NODE:
7357 case XML_CDATA_SECTION_NODE:
7358 case XML_ENTITY_REF_NODE:
7359 case XML_ENTITY_NODE:
7360 case XML_PI_NODE:
7361 case XML_COMMENT_NODE:
7362 case XML_NOTATION_NODE:
7363 case XML_DTD_NODE:
7364 case XML_ELEMENT_DECL:
7365 case XML_ATTRIBUTE_DECL:
7366 case XML_ENTITY_DECL:
7367 case XML_XINCLUDE_START:
7368 case XML_XINCLUDE_END:
7369 if (cur->parent == NULL)
7370 return(NULL);
7371 if ((cur->parent->type == XML_ELEMENT_NODE) &&
7372 ((cur->parent->name[0] == ' ') ||
7373 (xmlStrEqual(cur->parent->name,
7374 BAD_CAST "fake node libxslt"))))
7375 return(NULL);
7376 return(cur->parent);
7377 case XML_ATTRIBUTE_NODE: {
7378 xmlAttrPtr att = (xmlAttrPtr) cur;
7379
7380 return(att->parent);
7381 }
7382 case XML_NAMESPACE_DECL: {
7383 xmlNsPtr ns = (xmlNsPtr) cur;
7384
7385 if ((ns->next != NULL) &&
7386 (ns->next->type != XML_NAMESPACE_DECL))
7387 return((xmlNodePtr) ns->next);
7388 /* Bad, how did that namespace end up here ? */
7389 return(NULL);
7390 }
7391 case XML_DOCUMENT_NODE:
7392 case XML_DOCUMENT_TYPE_NODE:
7393 case XML_DOCUMENT_FRAG_NODE:
7394 case XML_HTML_DOCUMENT_NODE:
7395 return(NULL);
7396 }
7397 return(NULL);
7398}
7399
7400/**
7401 * xmlXPathNextAncestorOrSelf:
7402 * @ctxt: the XPath Parser context
7403 * @cur: the current node in the traversal
7404 *
7405 * Traversal function for the "ancestor-or-self" direction
7406 * he ancestor-or-self axis contains the context node and ancestors of
7407 * the context node in reverse document order; thus the context node is
7408 * the first node on the axis, and the context node's parent the second;
7409 * parent here is defined the same as with the parent axis.
7410 *
7411 * Returns the next element following that axis
7412 */
7413xmlNodePtr
7414xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7415 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7416 if (cur == NULL)
7417 return(ctxt->context->node);
7418 return(xmlXPathNextAncestor(ctxt, cur));
7419}
7420
7421/**
7422 * xmlXPathNextFollowingSibling:
7423 * @ctxt: the XPath Parser context
7424 * @cur: the current node in the traversal
7425 *
7426 * Traversal function for the "following-sibling" direction
7427 * The following-sibling axis contains the following siblings of the context
7428 * node in document order.
7429 *
7430 * Returns the next element following that axis
7431 */
7432xmlNodePtr
7433xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7434 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7435 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7436 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7437 return(NULL);
7438 if (cur == (xmlNodePtr) ctxt->context->doc)
7439 return(NULL);
7440 if (cur == NULL)
7441 return(ctxt->context->node->next);
7442 return(cur->next);
7443}
7444
7445/**
7446 * xmlXPathNextPrecedingSibling:
7447 * @ctxt: the XPath Parser context
7448 * @cur: the current node in the traversal
7449 *
7450 * Traversal function for the "preceding-sibling" direction
7451 * The preceding-sibling axis contains the preceding siblings of the context
7452 * node in reverse document order; the first preceding sibling is first on the
7453 * axis; the sibling preceding that node is the second on the axis and so on.
7454 *
7455 * Returns the next element following that axis
7456 */
7457xmlNodePtr
7458xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7459 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7460 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7461 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7462 return(NULL);
7463 if (cur == (xmlNodePtr) ctxt->context->doc)
7464 return(NULL);
7465 if (cur == NULL)
7466 return(ctxt->context->node->prev);
7467 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7468 cur = cur->prev;
7469 if (cur == NULL)
7470 return(ctxt->context->node->prev);
7471 }
7472 return(cur->prev);
7473}
7474
7475/**
7476 * xmlXPathNextFollowing:
7477 * @ctxt: the XPath Parser context
7478 * @cur: the current node in the traversal
7479 *
7480 * Traversal function for the "following" direction
7481 * The following axis contains all nodes in the same document as the context
7482 * node that are after the context node in document order, excluding any
7483 * descendants and excluding attribute nodes and namespace nodes; the nodes
7484 * are ordered in document order
7485 *
7486 * Returns the next element following that axis
7487 */
7488xmlNodePtr
7489xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7490 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7491 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
7492 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
7493 return(cur->children);
7494
7495 if (cur == NULL) {
7496 cur = ctxt->context->node;
7497 if (cur->type == XML_ATTRIBUTE_NODE) {
7498 cur = cur->parent;
7499 } else if (cur->type == XML_NAMESPACE_DECL) {
7500 xmlNsPtr ns = (xmlNsPtr) cur;
7501
7502 if ((ns->next == NULL) ||
7503 (ns->next->type == XML_NAMESPACE_DECL))
7504 return (NULL);
7505 cur = (xmlNodePtr) ns->next;
7506 }
7507 }
7508 if (cur == NULL) return(NULL) ; /* ERROR */
7509 if (cur->next != NULL) return(cur->next) ;
7510 do {
7511 cur = cur->parent;
7512 if (cur == NULL) break;
7513 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7514 if (cur->next != NULL) return(cur->next);
7515 } while (cur != NULL);
7516 return(cur);
7517}
7518
7519/*
7520 * xmlXPathIsAncestor:
7521 * @ancestor: the ancestor node
7522 * @node: the current node
7523 *
7524 * Check that @ancestor is a @node's ancestor
7525 *
7526 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7527 */
7528static int
7529xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7530 if ((ancestor == NULL) || (node == NULL)) return(0);
7531 if (node->type == XML_NAMESPACE_DECL)
7532 return(0);
7533 if (ancestor->type == XML_NAMESPACE_DECL)
7534 return(0);
7535 /* nodes need to be in the same document */
7536 if (ancestor->doc != node->doc) return(0);
7537 /* avoid searching if ancestor or node is the root node */
7538 if (ancestor == (xmlNodePtr) node->doc) return(1);
7539 if (node == (xmlNodePtr) ancestor->doc) return(0);
7540 while (node->parent != NULL) {
7541 if (node->parent == ancestor)
7542 return(1);
7543 node = node->parent;
7544 }
7545 return(0);
7546}
7547
7548/**
7549 * xmlXPathNextPreceding:
7550 * @ctxt: the XPath Parser context
7551 * @cur: the current node in the traversal
7552 *
7553 * Traversal function for the "preceding" direction
7554 * the preceding axis contains all nodes in the same document as the context
7555 * node that are before the context node in document order, excluding any
7556 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7557 * ordered in reverse document order
7558 *
7559 * Returns the next element following that axis
7560 */
7561xmlNodePtr
7562xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7563{
7564 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7565 if (cur == NULL) {
7566 cur = ctxt->context->node;
7567 if (cur->type == XML_ATTRIBUTE_NODE) {
7568 cur = cur->parent;
7569 } else if (cur->type == XML_NAMESPACE_DECL) {
7570 xmlNsPtr ns = (xmlNsPtr) cur;
7571
7572 if ((ns->next == NULL) ||
7573 (ns->next->type == XML_NAMESPACE_DECL))
7574 return (NULL);
7575 cur = (xmlNodePtr) ns->next;
7576 }
7577 }
7578 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
7579 return (NULL);
7580 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7581 cur = cur->prev;
7582 do {
7583 if (cur->prev != NULL) {
7584 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7585 return (cur);
7586 }
7587
7588 cur = cur->parent;
7589 if (cur == NULL)
7590 return (NULL);
7591 if (cur == ctxt->context->doc->children)
7592 return (NULL);
7593 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
7594 return (cur);
7595}
7596
7597/**
7598 * xmlXPathNextPrecedingInternal:
7599 * @ctxt: the XPath Parser context
7600 * @cur: the current node in the traversal
7601 *
7602 * Traversal function for the "preceding" direction
7603 * the preceding axis contains all nodes in the same document as the context
7604 * node that are before the context node in document order, excluding any
7605 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7606 * ordered in reverse document order
7607 * This is a faster implementation but internal only since it requires a
7608 * state kept in the parser context: ctxt->ancestor.
7609 *
7610 * Returns the next element following that axis
7611 */
7612static xmlNodePtr
7613xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7614 xmlNodePtr cur)
7615{
7616 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7617 if (cur == NULL) {
7618 cur = ctxt->context->node;
7619 if (cur == NULL)
7620 return (NULL);
7621 if (cur->type == XML_ATTRIBUTE_NODE) {
7622 cur = cur->parent;
7623 } else if (cur->type == XML_NAMESPACE_DECL) {
7624 xmlNsPtr ns = (xmlNsPtr) cur;
7625
7626 if ((ns->next == NULL) ||
7627 (ns->next->type == XML_NAMESPACE_DECL))
7628 return (NULL);
7629 cur = (xmlNodePtr) ns->next;
7630 }
7631 ctxt->ancestor = cur->parent;
7632 }
7633 if (cur->type == XML_NAMESPACE_DECL)
7634 return(NULL);
7635 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7636 cur = cur->prev;
7637 while (cur->prev == NULL) {
7638 cur = cur->parent;
7639 if (cur == NULL)
7640 return (NULL);
7641 if (cur == ctxt->context->doc->children)
7642 return (NULL);
7643 if (cur != ctxt->ancestor)
7644 return (cur);
7645 ctxt->ancestor = cur->parent;
7646 }
7647 cur = cur->prev;
7648 while (cur->last != NULL)
7649 cur = cur->last;
7650 return (cur);
7651}
7652
7653/**
7654 * xmlXPathNextNamespace:
7655 * @ctxt: the XPath Parser context
7656 * @cur: the current attribute in the traversal
7657 *
7658 * Traversal function for the "namespace" direction
7659 * the namespace axis contains the namespace nodes of the context node;
7660 * the order of nodes on this axis is implementation-defined; the axis will
7661 * be empty unless the context node is an element
7662 *
7663 * We keep the XML namespace node at the end of the list.
7664 *
7665 * Returns the next element following that axis
7666 */
7667xmlNodePtr
7668xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7669 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7670 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7671 if (cur == NULL) {
7672 if (ctxt->context->tmpNsList != NULL)
7673 xmlFree(ctxt->context->tmpNsList);
7674 ctxt->context->tmpNsList =
7675 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
7676 ctxt->context->tmpNsNr = 0;
7677 if (ctxt->context->tmpNsList != NULL) {
7678 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7679 ctxt->context->tmpNsNr++;
7680 }
7681 }
7682 return((xmlNodePtr) xmlXPathXMLNamespace);
7683 }
7684 if (ctxt->context->tmpNsNr > 0) {
7685 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7686 } else {
7687 if (ctxt->context->tmpNsList != NULL)
7688 xmlFree(ctxt->context->tmpNsList);
7689 ctxt->context->tmpNsList = NULL;
7690 return(NULL);
7691 }
7692}
7693
7694/**
7695 * xmlXPathNextAttribute:
7696 * @ctxt: the XPath Parser context
7697 * @cur: the current attribute in the traversal
7698 *
7699 * Traversal function for the "attribute" direction
7700 * TODO: support DTD inherited default attributes
7701 *
7702 * Returns the next element following that axis
7703 */
7704xmlNodePtr
7705xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7706 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7707 if (ctxt->context->node == NULL)
7708 return(NULL);
7709 if (ctxt->context->node->type != XML_ELEMENT_NODE)
7710 return(NULL);
7711 if (cur == NULL) {
7712 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7713 return(NULL);
7714 return((xmlNodePtr)ctxt->context->node->properties);
7715 }
7716 return((xmlNodePtr)cur->next);
7717}
7718
7719/************************************************************************
7720 * *
7721 * NodeTest Functions *
7722 * *
7723 ************************************************************************/
7724
7725#define IS_FUNCTION 200
7726
7727
7728/************************************************************************
7729 * *
7730 * Implicit tree core function library *
7731 * *
7732 ************************************************************************/
7733
7734/**
7735 * xmlXPathRoot:
7736 * @ctxt: the XPath Parser context
7737 *
7738 * Initialize the context to the root of the document
7739 */
7740void
7741xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7742 if ((ctxt == NULL) || (ctxt->context == NULL))
7743 return;
7744 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
7745 (xmlNodePtr) ctxt->context->doc));
7746}
7747
7748/************************************************************************
7749 * *
7750 * The explicit core function library *
7751 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7752 * *
7753 ************************************************************************/
7754
7755
7756/**
7757 * xmlXPathLastFunction:
7758 * @ctxt: the XPath Parser context
7759 * @nargs: the number of arguments
7760 *
7761 * Implement the last() XPath function
7762 * number last()
7763 * The last function returns the number of nodes in the context node list.
7764 */
7765void
7766xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7767 CHECK_ARITY(0);
7768 if (ctxt->context->contextSize >= 0) {
7769 valuePush(ctxt,
7770 xmlXPathCacheNewFloat(ctxt->context,
7771 (double) ctxt->context->contextSize));
7772 } else {
7773 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7774 }
7775}
7776
7777/**
7778 * xmlXPathPositionFunction:
7779 * @ctxt: the XPath Parser context
7780 * @nargs: the number of arguments
7781 *
7782 * Implement the position() XPath function
7783 * number position()
7784 * The position function returns the position of the context node in the
7785 * context node list. The first position is 1, and so the last position
7786 * will be equal to last().
7787 */
7788void
7789xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7790 CHECK_ARITY(0);
7791 if (ctxt->context->proximityPosition >= 0) {
7792 valuePush(ctxt,
7793 xmlXPathCacheNewFloat(ctxt->context,
7794 (double) ctxt->context->proximityPosition));
7795 } else {
7796 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7797 }
7798}
7799
7800/**
7801 * xmlXPathCountFunction:
7802 * @ctxt: the XPath Parser context
7803 * @nargs: the number of arguments
7804 *
7805 * Implement the count() XPath function
7806 * number count(node-set)
7807 */
7808void
7809xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7810 xmlXPathObjectPtr cur;
7811
7812 CHECK_ARITY(1);
7813 if ((ctxt->value == NULL) ||
7814 ((ctxt->value->type != XPATH_NODESET) &&
7815 (ctxt->value->type != XPATH_XSLT_TREE)))
7816 XP_ERROR(XPATH_INVALID_TYPE);
7817 cur = valuePop(ctxt);
7818
7819 if ((cur == NULL) || (cur->nodesetval == NULL))
7820 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
7821 else
7822 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
7823 (double) cur->nodesetval->nodeNr));
7824 xmlXPathReleaseObject(ctxt->context, cur);
7825}
7826
7827/**
7828 * xmlXPathGetElementsByIds:
7829 * @doc: the document
7830 * @ids: a whitespace separated list of IDs
7831 *
7832 * Selects elements by their unique ID.
7833 *
7834 * Returns a node-set of selected elements.
7835 */
7836static xmlNodeSetPtr
7837xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7838 xmlNodeSetPtr ret;
7839 const xmlChar *cur = ids;
7840 xmlChar *ID;
7841 xmlAttrPtr attr;
7842 xmlNodePtr elem = NULL;
7843
7844 if (ids == NULL) return(NULL);
7845
7846 ret = xmlXPathNodeSetCreate(NULL);
7847 if (ret == NULL)
7848 return(ret);
7849
7850 while (IS_BLANK_CH(*cur)) cur++;
7851 while (*cur != 0) {
7852 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7853 cur++;
7854
7855 ID = xmlStrndup(ids, cur - ids);
7856 if (ID != NULL) {
7857 /*
7858 * We used to check the fact that the value passed
7859 * was an NCName, but this generated much troubles for
7860 * me and Aleksey Sanin, people blatantly violated that
7861 * constraint, like Visa3D spec.
7862 * if (xmlValidateNCName(ID, 1) == 0)
7863 */
7864 attr = xmlGetID(doc, ID);
7865 if (attr != NULL) {
7866 if (attr->type == XML_ATTRIBUTE_NODE)
7867 elem = attr->parent;
7868 else if (attr->type == XML_ELEMENT_NODE)
7869 elem = (xmlNodePtr) attr;
7870 else
7871 elem = NULL;
7872 /* TODO: Check memory error. */
7873 if (elem != NULL)
7874 xmlXPathNodeSetAdd(ret, elem);
7875 }
7876 xmlFree(ID);
7877 }
7878
7879 while (IS_BLANK_CH(*cur)) cur++;
7880 ids = cur;
7881 }
7882 return(ret);
7883}
7884
7885/**
7886 * xmlXPathIdFunction:
7887 * @ctxt: the XPath Parser context
7888 * @nargs: the number of arguments
7889 *
7890 * Implement the id() XPath function
7891 * node-set id(object)
7892 * The id function selects elements by their unique ID
7893 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7894 * then the result is the union of the result of applying id to the
7895 * string value of each of the nodes in the argument node-set. When the
7896 * argument to id is of any other type, the argument is converted to a
7897 * string as if by a call to the string function; the string is split
7898 * into a whitespace-separated list of tokens (whitespace is any sequence
7899 * of characters matching the production S); the result is a node-set
7900 * containing the elements in the same document as the context node that
7901 * have a unique ID equal to any of the tokens in the list.
7902 */
7903void
7904xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7905 xmlChar *tokens;
7906 xmlNodeSetPtr ret;
7907 xmlXPathObjectPtr obj;
7908
7909 CHECK_ARITY(1);
7910 obj = valuePop(ctxt);
7911 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7912 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7913 xmlNodeSetPtr ns;
7914 int i;
7915
7916 /* TODO: Check memory error. */
7917 ret = xmlXPathNodeSetCreate(NULL);
7918
7919 if (obj->nodesetval != NULL) {
7920 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7921 tokens =
7922 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7923 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7924 /* TODO: Check memory error. */
7925 ret = xmlXPathNodeSetMerge(ret, ns);
7926 xmlXPathFreeNodeSet(ns);
7927 if (tokens != NULL)
7928 xmlFree(tokens);
7929 }
7930 }
7931 xmlXPathReleaseObject(ctxt->context, obj);
7932 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
7933 return;
7934 }
7935 obj = xmlXPathCacheConvertString(ctxt->context, obj);
7936 if (obj == NULL) return;
7937 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
7938 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
7939 xmlXPathReleaseObject(ctxt->context, obj);
7940 return;
7941}
7942
7943/**
7944 * xmlXPathLocalNameFunction:
7945 * @ctxt: the XPath Parser context
7946 * @nargs: the number of arguments
7947 *
7948 * Implement the local-name() XPath function
7949 * string local-name(node-set?)
7950 * The local-name function returns a string containing the local part
7951 * of the name of the node in the argument node-set that is first in
7952 * document order. If the node-set is empty or the first node has no
7953 * name, an empty string is returned. If the argument is omitted it
7954 * defaults to the context node.
7955 */
7956void
7957xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7958 xmlXPathObjectPtr cur;
7959
7960 if (ctxt == NULL) return;
7961
7962 if (nargs == 0) {
7963 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
7964 ctxt->context->node));
7965 nargs = 1;
7966 }
7967
7968 CHECK_ARITY(1);
7969 if ((ctxt->value == NULL) ||
7970 ((ctxt->value->type != XPATH_NODESET) &&
7971 (ctxt->value->type != XPATH_XSLT_TREE)))
7972 XP_ERROR(XPATH_INVALID_TYPE);
7973 cur = valuePop(ctxt);
7974
7975 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7976 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7977 } else {
7978 int i = 0; /* Should be first in document order !!!!! */
7979 switch (cur->nodesetval->nodeTab[i]->type) {
7980 case XML_ELEMENT_NODE:
7981 case XML_ATTRIBUTE_NODE:
7982 case XML_PI_NODE:
7983 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7984 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7985 else
7986 valuePush(ctxt,
7987 xmlXPathCacheNewString(ctxt->context,
7988 cur->nodesetval->nodeTab[i]->name));
7989 break;
7990 case XML_NAMESPACE_DECL:
7991 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
7992 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7993 break;
7994 default:
7995 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7996 }
7997 }
7998 xmlXPathReleaseObject(ctxt->context, cur);
7999}
8000
8001/**
8002 * xmlXPathNamespaceURIFunction:
8003 * @ctxt: the XPath Parser context
8004 * @nargs: the number of arguments
8005 *
8006 * Implement the namespace-uri() XPath function
8007 * string namespace-uri(node-set?)
8008 * The namespace-uri function returns a string containing the
8009 * namespace URI of the expanded name of the node in the argument
8010 * node-set that is first in document order. If the node-set is empty,
8011 * the first node has no name, or the expanded name has no namespace
8012 * URI, an empty string is returned. If the argument is omitted it
8013 * defaults to the context node.
8014 */
8015void
8016xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8017 xmlXPathObjectPtr cur;
8018
8019 if (ctxt == NULL) return;
8020
8021 if (nargs == 0) {
8022 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8023 ctxt->context->node));
8024 nargs = 1;
8025 }
8026 CHECK_ARITY(1);
8027 if ((ctxt->value == NULL) ||
8028 ((ctxt->value->type != XPATH_NODESET) &&
8029 (ctxt->value->type != XPATH_XSLT_TREE)))
8030 XP_ERROR(XPATH_INVALID_TYPE);
8031 cur = valuePop(ctxt);
8032
8033 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8034 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8035 } else {
8036 int i = 0; /* Should be first in document order !!!!! */
8037 switch (cur->nodesetval->nodeTab[i]->type) {
8038 case XML_ELEMENT_NODE:
8039 case XML_ATTRIBUTE_NODE:
8040 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8041 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8042 else
8043 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8044 cur->nodesetval->nodeTab[i]->ns->href));
8045 break;
8046 default:
8047 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8048 }
8049 }
8050 xmlXPathReleaseObject(ctxt->context, cur);
8051}
8052
8053/**
8054 * xmlXPathNameFunction:
8055 * @ctxt: the XPath Parser context
8056 * @nargs: the number of arguments
8057 *
8058 * Implement the name() XPath function
8059 * string name(node-set?)
8060 * The name function returns a string containing a QName representing
8061 * the name of the node in the argument node-set that is first in document
8062 * order. The QName must represent the name with respect to the namespace
8063 * declarations in effect on the node whose name is being represented.
8064 * Typically, this will be the form in which the name occurred in the XML
8065 * source. This need not be the case if there are namespace declarations
8066 * in effect on the node that associate multiple prefixes with the same
8067 * namespace. However, an implementation may include information about
8068 * the original prefix in its representation of nodes; in this case, an
8069 * implementation can ensure that the returned string is always the same
8070 * as the QName used in the XML source. If the argument it omitted it
8071 * defaults to the context node.
8072 * Libxml keep the original prefix so the "real qualified name" used is
8073 * returned.
8074 */
8075static void
8076xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8077{
8078 xmlXPathObjectPtr cur;
8079
8080 if (nargs == 0) {
8081 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8082 ctxt->context->node));
8083 nargs = 1;
8084 }
8085
8086 CHECK_ARITY(1);
8087 if ((ctxt->value == NULL) ||
8088 ((ctxt->value->type != XPATH_NODESET) &&
8089 (ctxt->value->type != XPATH_XSLT_TREE)))
8090 XP_ERROR(XPATH_INVALID_TYPE);
8091 cur = valuePop(ctxt);
8092
8093 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8094 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8095 } else {
8096 int i = 0; /* Should be first in document order !!!!! */
8097
8098 switch (cur->nodesetval->nodeTab[i]->type) {
8099 case XML_ELEMENT_NODE:
8100 case XML_ATTRIBUTE_NODE:
8101 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8102 valuePush(ctxt,
8103 xmlXPathCacheNewCString(ctxt->context, ""));
8104 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8105 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8106 valuePush(ctxt,
8107 xmlXPathCacheNewString(ctxt->context,
8108 cur->nodesetval->nodeTab[i]->name));
8109 } else {
8110 xmlChar *fullname;
8111
8112 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8113 cur->nodesetval->nodeTab[i]->ns->prefix,
8114 NULL, 0);
8115 if (fullname == cur->nodesetval->nodeTab[i]->name)
8116 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8117 if (fullname == NULL)
8118 xmlXPathPErrMemory(ctxt, NULL);
8119 valuePush(ctxt, xmlXPathCacheWrapString(
8120 ctxt->context, fullname));
8121 }
8122 break;
8123 default:
8124 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8125 cur->nodesetval->nodeTab[i]));
8126 xmlXPathLocalNameFunction(ctxt, 1);
8127 }
8128 }
8129 xmlXPathReleaseObject(ctxt->context, cur);
8130}
8131
8132
8133/**
8134 * xmlXPathStringFunction:
8135 * @ctxt: the XPath Parser context
8136 * @nargs: the number of arguments
8137 *
8138 * Implement the string() XPath function
8139 * string string(object?)
8140 * The string function converts an object to a string as follows:
8141 * - A node-set is converted to a string by returning the value of
8142 * the node in the node-set that is first in document order.
8143 * If the node-set is empty, an empty string is returned.
8144 * - A number is converted to a string as follows
8145 * + NaN is converted to the string NaN
8146 * + positive zero is converted to the string 0
8147 * + negative zero is converted to the string 0
8148 * + positive infinity is converted to the string Infinity
8149 * + negative infinity is converted to the string -Infinity
8150 * + if the number is an integer, the number is represented in
8151 * decimal form as a Number with no decimal point and no leading
8152 * zeros, preceded by a minus sign (-) if the number is negative
8153 * + otherwise, the number is represented in decimal form as a
8154 * Number including a decimal point with at least one digit
8155 * before the decimal point and at least one digit after the
8156 * decimal point, preceded by a minus sign (-) if the number
8157 * is negative; there must be no leading zeros before the decimal
8158 * point apart possibly from the one required digit immediately
8159 * before the decimal point; beyond the one required digit
8160 * after the decimal point there must be as many, but only as
8161 * many, more digits as are needed to uniquely distinguish the
8162 * number from all other IEEE 754 numeric values.
8163 * - The boolean false value is converted to the string false.
8164 * The boolean true value is converted to the string true.
8165 *
8166 * If the argument is omitted, it defaults to a node-set with the
8167 * context node as its only member.
8168 */
8169void
8170xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8171 xmlXPathObjectPtr cur;
8172
8173 if (ctxt == NULL) return;
8174 if (nargs == 0) {
8175 valuePush(ctxt,
8176 xmlXPathCacheWrapString(ctxt->context,
8177 xmlXPathCastNodeToString(ctxt->context->node)));
8178 return;
8179 }
8180
8181 CHECK_ARITY(1);
8182 cur = valuePop(ctxt);
8183 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8184 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8185}
8186
8187/**
8188 * xmlXPathStringLengthFunction:
8189 * @ctxt: the XPath Parser context
8190 * @nargs: the number of arguments
8191 *
8192 * Implement the string-length() XPath function
8193 * number string-length(string?)
8194 * The string-length returns the number of characters in the string
8195 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8196 * the context node converted to a string, in other words the value
8197 * of the context node.
8198 */
8199void
8200xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8201 xmlXPathObjectPtr cur;
8202
8203 if (nargs == 0) {
8204 if ((ctxt == NULL) || (ctxt->context == NULL))
8205 return;
8206 if (ctxt->context->node == NULL) {
8207 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8208 } else {
8209 xmlChar *content;
8210
8211 content = xmlXPathCastNodeToString(ctxt->context->node);
8212 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8213 xmlUTF8Strlen(content)));
8214 xmlFree(content);
8215 }
8216 return;
8217 }
8218 CHECK_ARITY(1);
8219 CAST_TO_STRING;
8220 CHECK_TYPE(XPATH_STRING);
8221 cur = valuePop(ctxt);
8222 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8223 xmlUTF8Strlen(cur->stringval)));
8224 xmlXPathReleaseObject(ctxt->context, cur);
8225}
8226
8227/**
8228 * xmlXPathConcatFunction:
8229 * @ctxt: the XPath Parser context
8230 * @nargs: the number of arguments
8231 *
8232 * Implement the concat() XPath function
8233 * string concat(string, string, string*)
8234 * The concat function returns the concatenation of its arguments.
8235 */
8236void
8237xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8238 xmlXPathObjectPtr cur, newobj;
8239 xmlChar *tmp;
8240
8241 if (ctxt == NULL) return;
8242 if (nargs < 2) {
8243 CHECK_ARITY(2);
8244 }
8245
8246 CAST_TO_STRING;
8247 cur = valuePop(ctxt);
8248 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8249 xmlXPathReleaseObject(ctxt->context, cur);
8250 return;
8251 }
8252 nargs--;
8253
8254 while (nargs > 0) {
8255 CAST_TO_STRING;
8256 newobj = valuePop(ctxt);
8257 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8258 xmlXPathReleaseObject(ctxt->context, newobj);
8259 xmlXPathReleaseObject(ctxt->context, cur);
8260 XP_ERROR(XPATH_INVALID_TYPE);
8261 }
8262 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8263 newobj->stringval = cur->stringval;
8264 cur->stringval = tmp;
8265 xmlXPathReleaseObject(ctxt->context, newobj);
8266 nargs--;
8267 }
8268 valuePush(ctxt, cur);
8269}
8270
8271/**
8272 * xmlXPathContainsFunction:
8273 * @ctxt: the XPath Parser context
8274 * @nargs: the number of arguments
8275 *
8276 * Implement the contains() XPath function
8277 * boolean contains(string, string)
8278 * The contains function returns true if the first argument string
8279 * contains the second argument string, and otherwise returns false.
8280 */
8281void
8282xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8283 xmlXPathObjectPtr hay, needle;
8284
8285 CHECK_ARITY(2);
8286 CAST_TO_STRING;
8287 CHECK_TYPE(XPATH_STRING);
8288 needle = valuePop(ctxt);
8289 CAST_TO_STRING;
8290 hay = valuePop(ctxt);
8291
8292 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8293 xmlXPathReleaseObject(ctxt->context, hay);
8294 xmlXPathReleaseObject(ctxt->context, needle);
8295 XP_ERROR(XPATH_INVALID_TYPE);
8296 }
8297 if (xmlStrstr(hay->stringval, needle->stringval))
8298 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8299 else
8300 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8301 xmlXPathReleaseObject(ctxt->context, hay);
8302 xmlXPathReleaseObject(ctxt->context, needle);
8303}
8304
8305/**
8306 * xmlXPathStartsWithFunction:
8307 * @ctxt: the XPath Parser context
8308 * @nargs: the number of arguments
8309 *
8310 * Implement the starts-with() XPath function
8311 * boolean starts-with(string, string)
8312 * The starts-with function returns true if the first argument string
8313 * starts with the second argument string, and otherwise returns false.
8314 */
8315void
8316xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8317 xmlXPathObjectPtr hay, needle;
8318 int n;
8319
8320 CHECK_ARITY(2);
8321 CAST_TO_STRING;
8322 CHECK_TYPE(XPATH_STRING);
8323 needle = valuePop(ctxt);
8324 CAST_TO_STRING;
8325 hay = valuePop(ctxt);
8326
8327 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8328 xmlXPathReleaseObject(ctxt->context, hay);
8329 xmlXPathReleaseObject(ctxt->context, needle);
8330 XP_ERROR(XPATH_INVALID_TYPE);
8331 }
8332 n = xmlStrlen(needle->stringval);
8333 if (xmlStrncmp(hay->stringval, needle->stringval, n))
8334 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8335 else
8336 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8337 xmlXPathReleaseObject(ctxt->context, hay);
8338 xmlXPathReleaseObject(ctxt->context, needle);
8339}
8340
8341/**
8342 * xmlXPathSubstringFunction:
8343 * @ctxt: the XPath Parser context
8344 * @nargs: the number of arguments
8345 *
8346 * Implement the substring() XPath function
8347 * string substring(string, number, number?)
8348 * The substring function returns the substring of the first argument
8349 * starting at the position specified in the second argument with
8350 * length specified in the third argument. For example,
8351 * substring("12345",2,3) returns "234". If the third argument is not
8352 * specified, it returns the substring starting at the position specified
8353 * in the second argument and continuing to the end of the string. For
8354 * example, substring("12345",2) returns "2345". More precisely, each
8355 * character in the string (see [3.6 Strings]) is considered to have a
8356 * numeric position: the position of the first character is 1, the position
8357 * of the second character is 2 and so on. The returned substring contains
8358 * those characters for which the position of the character is greater than
8359 * or equal to the second argument and, if the third argument is specified,
8360 * less than the sum of the second and third arguments; the comparisons
8361 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8362 * - substring("12345", 1.5, 2.6) returns "234"
8363 * - substring("12345", 0, 3) returns "12"
8364 * - substring("12345", 0 div 0, 3) returns ""
8365 * - substring("12345", 1, 0 div 0) returns ""
8366 * - substring("12345", -42, 1 div 0) returns "12345"
8367 * - substring("12345", -1 div 0, 1 div 0) returns ""
8368 */
8369void
8370xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8371 xmlXPathObjectPtr str, start, len;
8372 double le=0, in;
8373 int i = 1, j = INT_MAX;
8374
8375 if (nargs < 2) {
8376 CHECK_ARITY(2);
8377 }
8378 if (nargs > 3) {
8379 CHECK_ARITY(3);
8380 }
8381 /*
8382 * take care of possible last (position) argument
8383 */
8384 if (nargs == 3) {
8385 CAST_TO_NUMBER;
8386 CHECK_TYPE(XPATH_NUMBER);
8387 len = valuePop(ctxt);
8388 le = len->floatval;
8389 xmlXPathReleaseObject(ctxt->context, len);
8390 }
8391
8392 CAST_TO_NUMBER;
8393 CHECK_TYPE(XPATH_NUMBER);
8394 start = valuePop(ctxt);
8395 in = start->floatval;
8396 xmlXPathReleaseObject(ctxt->context, start);
8397 CAST_TO_STRING;
8398 CHECK_TYPE(XPATH_STRING);
8399 str = valuePop(ctxt);
8400
8401 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
8402 i = INT_MAX;
8403 } else if (in >= 1.0) {
8404 i = (int)in;
8405 if (in - floor(in) >= 0.5)
8406 i += 1;
8407 }
8408
8409 if (nargs == 3) {
8410 double rin, rle, end;
8411
8412 rin = floor(in);
8413 if (in - rin >= 0.5)
8414 rin += 1.0;
8415
8416 rle = floor(le);
8417 if (le - rle >= 0.5)
8418 rle += 1.0;
8419
8420 end = rin + rle;
8421 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
8422 j = 1;
8423 } else if (end < INT_MAX) {
8424 j = (int)end;
8425 }
8426 }
8427
8428 if (i < j) {
8429 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
8430 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
8431 xmlFree(ret);
8432 } else {
8433 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8434 }
8435
8436 xmlXPathReleaseObject(ctxt->context, str);
8437}
8438
8439/**
8440 * xmlXPathSubstringBeforeFunction:
8441 * @ctxt: the XPath Parser context
8442 * @nargs: the number of arguments
8443 *
8444 * Implement the substring-before() XPath function
8445 * string substring-before(string, string)
8446 * The substring-before function returns the substring of the first
8447 * argument string that precedes the first occurrence of the second
8448 * argument string in the first argument string, or the empty string
8449 * if the first argument string does not contain the second argument
8450 * string. For example, substring-before("1999/04/01","/") returns 1999.
8451 */
8452void
8453xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8454 xmlXPathObjectPtr str;
8455 xmlXPathObjectPtr find;
8456 xmlBufPtr target;
8457 const xmlChar *point;
8458 int offset;
8459
8460 CHECK_ARITY(2);
8461 CAST_TO_STRING;
8462 find = valuePop(ctxt);
8463 CAST_TO_STRING;
8464 str = valuePop(ctxt);
8465
8466 target = xmlBufCreate();
8467 if (target) {
8468 point = xmlStrstr(str->stringval, find->stringval);
8469 if (point) {
8470 offset = point - str->stringval;
8471 xmlBufAdd(target, str->stringval, offset);
8472 }
8473 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8474 xmlBufContent(target)));
8475 xmlBufFree(target);
8476 }
8477 xmlXPathReleaseObject(ctxt->context, str);
8478 xmlXPathReleaseObject(ctxt->context, find);
8479}
8480
8481/**
8482 * xmlXPathSubstringAfterFunction:
8483 * @ctxt: the XPath Parser context
8484 * @nargs: the number of arguments
8485 *
8486 * Implement the substring-after() XPath function
8487 * string substring-after(string, string)
8488 * The substring-after function returns the substring of the first
8489 * argument string that follows the first occurrence of the second
8490 * argument string in the first argument string, or the empty stringi
8491 * if the first argument string does not contain the second argument
8492 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8493 * and substring-after("1999/04/01","19") returns 99/04/01.
8494 */
8495void
8496xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8497 xmlXPathObjectPtr str;
8498 xmlXPathObjectPtr find;
8499 xmlBufPtr target;
8500 const xmlChar *point;
8501 int offset;
8502
8503 CHECK_ARITY(2);
8504 CAST_TO_STRING;
8505 find = valuePop(ctxt);
8506 CAST_TO_STRING;
8507 str = valuePop(ctxt);
8508
8509 target = xmlBufCreate();
8510 if (target) {
8511 point = xmlStrstr(str->stringval, find->stringval);
8512 if (point) {
8513 offset = point - str->stringval + xmlStrlen(find->stringval);
8514 xmlBufAdd(target, &str->stringval[offset],
8515 xmlStrlen(str->stringval) - offset);
8516 }
8517 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8518 xmlBufContent(target)));
8519 xmlBufFree(target);
8520 }
8521 xmlXPathReleaseObject(ctxt->context, str);
8522 xmlXPathReleaseObject(ctxt->context, find);
8523}
8524
8525/**
8526 * xmlXPathNormalizeFunction:
8527 * @ctxt: the XPath Parser context
8528 * @nargs: the number of arguments
8529 *
8530 * Implement the normalize-space() XPath function
8531 * string normalize-space(string?)
8532 * The normalize-space function returns the argument string with white
8533 * space normalized by stripping leading and trailing whitespace
8534 * and replacing sequences of whitespace characters by a single
8535 * space. Whitespace characters are the same allowed by the S production
8536 * in XML. If the argument is omitted, it defaults to the context
8537 * node converted to a string, in other words the value of the context node.
8538 */
8539void
8540xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8541 xmlChar *source, *target;
8542 int blank;
8543
8544 if (ctxt == NULL) return;
8545 if (nargs == 0) {
8546 /* Use current context node */
8547 valuePush(ctxt,
8548 xmlXPathCacheWrapString(ctxt->context,
8549 xmlXPathCastNodeToString(ctxt->context->node)));
8550 nargs = 1;
8551 }
8552
8553 CHECK_ARITY(1);
8554 CAST_TO_STRING;
8555 CHECK_TYPE(XPATH_STRING);
8556 source = ctxt->value->stringval;
8557 if (source == NULL)
8558 return;
8559 target = source;
8560
8561 /* Skip leading whitespaces */
8562 while (IS_BLANK_CH(*source))
8563 source++;
8564
8565 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8566 blank = 0;
8567 while (*source) {
8568 if (IS_BLANK_CH(*source)) {
8569 blank = 1;
8570 } else {
8571 if (blank) {
8572 *target++ = 0x20;
8573 blank = 0;
8574 }
8575 *target++ = *source;
8576 }
8577 source++;
8578 }
8579 *target = 0;
8580}
8581
8582/**
8583 * xmlXPathTranslateFunction:
8584 * @ctxt: the XPath Parser context
8585 * @nargs: the number of arguments
8586 *
8587 * Implement the translate() XPath function
8588 * string translate(string, string, string)
8589 * The translate function returns the first argument string with
8590 * occurrences of characters in the second argument string replaced
8591 * by the character at the corresponding position in the third argument
8592 * string. For example, translate("bar","abc","ABC") returns the string
8593 * BAr. If there is a character in the second argument string with no
8594 * character at a corresponding position in the third argument string
8595 * (because the second argument string is longer than the third argument
8596 * string), then occurrences of that character in the first argument
8597 * string are removed. For example, translate("--aaa--","abc-","ABC")
8598 * returns "AAA". If a character occurs more than once in second
8599 * argument string, then the first occurrence determines the replacement
8600 * character. If the third argument string is longer than the second
8601 * argument string, then excess characters are ignored.
8602 */
8603void
8604xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8605 xmlXPathObjectPtr str;
8606 xmlXPathObjectPtr from;
8607 xmlXPathObjectPtr to;
8608 xmlBufPtr target;
8609 int offset, max;
8610 int ch;
8611 const xmlChar *point;
8612 xmlChar *cptr;
8613
8614 CHECK_ARITY(3);
8615
8616 CAST_TO_STRING;
8617 to = valuePop(ctxt);
8618 CAST_TO_STRING;
8619 from = valuePop(ctxt);
8620 CAST_TO_STRING;
8621 str = valuePop(ctxt);
8622
8623 target = xmlBufCreate();
8624 if (target) {
8625 max = xmlUTF8Strlen(to->stringval);
8626 for (cptr = str->stringval; (ch=*cptr); ) {
8627 offset = xmlUTF8Strloc(from->stringval, cptr);
8628 if (offset >= 0) {
8629 if (offset < max) {
8630 point = xmlUTF8Strpos(to->stringval, offset);
8631 if (point)
8632 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8633 }
8634 } else
8635 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8636
8637 /* Step to next character in input */
8638 cptr++;
8639 if ( ch & 0x80 ) {
8640 /* if not simple ascii, verify proper format */
8641 if ( (ch & 0xc0) != 0xc0 ) {
8642 xmlGenericError(xmlGenericErrorContext,
8643 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8644 /* not asserting an XPath error is probably better */
8645 break;
8646 }
8647 /* then skip over remaining bytes for this char */
8648 while ( (ch <<= 1) & 0x80 )
8649 if ( (*cptr++ & 0xc0) != 0x80 ) {
8650 xmlGenericError(xmlGenericErrorContext,
8651 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8652 /* not asserting an XPath error is probably better */
8653 break;
8654 }
8655 if (ch & 0x80) /* must have had error encountered */
8656 break;
8657 }
8658 }
8659 }
8660 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8661 xmlBufContent(target)));
8662 xmlBufFree(target);
8663 xmlXPathReleaseObject(ctxt->context, str);
8664 xmlXPathReleaseObject(ctxt->context, from);
8665 xmlXPathReleaseObject(ctxt->context, to);
8666}
8667
8668/**
8669 * xmlXPathBooleanFunction:
8670 * @ctxt: the XPath Parser context
8671 * @nargs: the number of arguments
8672 *
8673 * Implement the boolean() XPath function
8674 * boolean boolean(object)
8675 * The boolean function converts its argument to a boolean as follows:
8676 * - a number is true if and only if it is neither positive or
8677 * negative zero nor NaN
8678 * - a node-set is true if and only if it is non-empty
8679 * - a string is true if and only if its length is non-zero
8680 */
8681void
8682xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8683 xmlXPathObjectPtr cur;
8684
8685 CHECK_ARITY(1);
8686 cur = valuePop(ctxt);
8687 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8688 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
8689 valuePush(ctxt, cur);
8690}
8691
8692/**
8693 * xmlXPathNotFunction:
8694 * @ctxt: the XPath Parser context
8695 * @nargs: the number of arguments
8696 *
8697 * Implement the not() XPath function
8698 * boolean not(boolean)
8699 * The not function returns true if its argument is false,
8700 * and false otherwise.
8701 */
8702void
8703xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8704 CHECK_ARITY(1);
8705 CAST_TO_BOOLEAN;
8706 CHECK_TYPE(XPATH_BOOLEAN);
8707 ctxt->value->boolval = ! ctxt->value->boolval;
8708}
8709
8710/**
8711 * xmlXPathTrueFunction:
8712 * @ctxt: the XPath Parser context
8713 * @nargs: the number of arguments
8714 *
8715 * Implement the true() XPath function
8716 * boolean true()
8717 */
8718void
8719xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8720 CHECK_ARITY(0);
8721 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8722}
8723
8724/**
8725 * xmlXPathFalseFunction:
8726 * @ctxt: the XPath Parser context
8727 * @nargs: the number of arguments
8728 *
8729 * Implement the false() XPath function
8730 * boolean false()
8731 */
8732void
8733xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8734 CHECK_ARITY(0);
8735 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8736}
8737
8738/**
8739 * xmlXPathLangFunction:
8740 * @ctxt: the XPath Parser context
8741 * @nargs: the number of arguments
8742 *
8743 * Implement the lang() XPath function
8744 * boolean lang(string)
8745 * The lang function returns true or false depending on whether the
8746 * language of the context node as specified by xml:lang attributes
8747 * is the same as or is a sublanguage of the language specified by
8748 * the argument string. The language of the context node is determined
8749 * by the value of the xml:lang attribute on the context node, or, if
8750 * the context node has no xml:lang attribute, by the value of the
8751 * xml:lang attribute on the nearest ancestor of the context node that
8752 * has an xml:lang attribute. If there is no such attribute, then lang
8753 * returns false. If there is such an attribute, then lang returns
8754 * true if the attribute value is equal to the argument ignoring case,
8755 * or if there is some suffix starting with - such that the attribute
8756 * value is equal to the argument ignoring that suffix of the attribute
8757 * value and ignoring case.
8758 */
8759void
8760xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8761 xmlXPathObjectPtr val = NULL;
8762 const xmlChar *theLang = NULL;
8763 const xmlChar *lang;
8764 int ret = 0;
8765 int i;
8766
8767 CHECK_ARITY(1);
8768 CAST_TO_STRING;
8769 CHECK_TYPE(XPATH_STRING);
8770 val = valuePop(ctxt);
8771 lang = val->stringval;
8772 theLang = xmlNodeGetLang(ctxt->context->node);
8773 if ((theLang != NULL) && (lang != NULL)) {
8774 for (i = 0;lang[i] != 0;i++)
8775 if (toupper(lang[i]) != toupper(theLang[i]))
8776 goto not_equal;
8777 if ((theLang[i] == 0) || (theLang[i] == '-'))
8778 ret = 1;
8779 }
8780not_equal:
8781 if (theLang != NULL)
8782 xmlFree((void *)theLang);
8783
8784 xmlXPathReleaseObject(ctxt->context, val);
8785 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
8786}
8787
8788/**
8789 * xmlXPathNumberFunction:
8790 * @ctxt: the XPath Parser context
8791 * @nargs: the number of arguments
8792 *
8793 * Implement the number() XPath function
8794 * number number(object?)
8795 */
8796void
8797xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8798 xmlXPathObjectPtr cur;
8799 double res;
8800
8801 if (ctxt == NULL) return;
8802 if (nargs == 0) {
8803 if (ctxt->context->node == NULL) {
8804 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
8805 } else {
8806 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8807
8808 res = xmlXPathStringEvalNumber(content);
8809 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
8810 xmlFree(content);
8811 }
8812 return;
8813 }
8814
8815 CHECK_ARITY(1);
8816 cur = valuePop(ctxt);
8817 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
8818}
8819
8820/**
8821 * xmlXPathSumFunction:
8822 * @ctxt: the XPath Parser context
8823 * @nargs: the number of arguments
8824 *
8825 * Implement the sum() XPath function
8826 * number sum(node-set)
8827 * The sum function returns the sum of the values of the nodes in
8828 * the argument node-set.
8829 */
8830void
8831xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8832 xmlXPathObjectPtr cur;
8833 int i;
8834 double res = 0.0;
8835
8836 CHECK_ARITY(1);
8837 if ((ctxt->value == NULL) ||
8838 ((ctxt->value->type != XPATH_NODESET) &&
8839 (ctxt->value->type != XPATH_XSLT_TREE)))
8840 XP_ERROR(XPATH_INVALID_TYPE);
8841 cur = valuePop(ctxt);
8842
8843 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8844 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8845 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
8846 }
8847 }
8848 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
8849 xmlXPathReleaseObject(ctxt->context, cur);
8850}
8851
8852/**
8853 * xmlXPathFloorFunction:
8854 * @ctxt: the XPath Parser context
8855 * @nargs: the number of arguments
8856 *
8857 * Implement the floor() XPath function
8858 * number floor(number)
8859 * The floor function returns the largest (closest to positive infinity)
8860 * number that is not greater than the argument and that is an integer.
8861 */
8862void
8863xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8864 CHECK_ARITY(1);
8865 CAST_TO_NUMBER;
8866 CHECK_TYPE(XPATH_NUMBER);
8867
8868 ctxt->value->floatval = floor(ctxt->value->floatval);
8869}
8870
8871/**
8872 * xmlXPathCeilingFunction:
8873 * @ctxt: the XPath Parser context
8874 * @nargs: the number of arguments
8875 *
8876 * Implement the ceiling() XPath function
8877 * number ceiling(number)
8878 * The ceiling function returns the smallest (closest to negative infinity)
8879 * number that is not less than the argument and that is an integer.
8880 */
8881void
8882xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8883 CHECK_ARITY(1);
8884 CAST_TO_NUMBER;
8885 CHECK_TYPE(XPATH_NUMBER);
8886
8887#ifdef _AIX
8888 /* Work around buggy ceil() function on AIX */
8889 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8890#else
8891 ctxt->value->floatval = ceil(ctxt->value->floatval);
8892#endif
8893}
8894
8895/**
8896 * xmlXPathRoundFunction:
8897 * @ctxt: the XPath Parser context
8898 * @nargs: the number of arguments
8899 *
8900 * Implement the round() XPath function
8901 * number round(number)
8902 * The round function returns the number that is closest to the
8903 * argument and that is an integer. If there are two such numbers,
8904 * then the one that is closest to positive infinity is returned.
8905 */
8906void
8907xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8908 double f;
8909
8910 CHECK_ARITY(1);
8911 CAST_TO_NUMBER;
8912 CHECK_TYPE(XPATH_NUMBER);
8913
8914 f = ctxt->value->floatval;
8915
8916 if ((f >= -0.5) && (f < 0.5)) {
8917 /* Handles negative zero. */
8918 ctxt->value->floatval *= 0.0;
8919 }
8920 else {
8921 double rounded = floor(f);
8922 if (f - rounded >= 0.5)
8923 rounded += 1.0;
8924 ctxt->value->floatval = rounded;
8925 }
8926}
8927
8928/************************************************************************
8929 * *
8930 * The Parser *
8931 * *
8932 ************************************************************************/
8933
8934/*
8935 * a few forward declarations since we use a recursive call based
8936 * implementation.
8937 */
8938static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8939static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8940static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8941static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8942static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8943 int qualified);
8944
8945/**
8946 * xmlXPathCurrentChar:
8947 * @ctxt: the XPath parser context
8948 * @cur: pointer to the beginning of the char
8949 * @len: pointer to the length of the char read
8950 *
8951 * The current char value, if using UTF-8 this may actually span multiple
8952 * bytes in the input buffer.
8953 *
8954 * Returns the current char value and its length
8955 */
8956
8957static int
8958xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8959 unsigned char c;
8960 unsigned int val;
8961 const xmlChar *cur;
8962
8963 if (ctxt == NULL)
8964 return(0);
8965 cur = ctxt->cur;
8966
8967 /*
8968 * We are supposed to handle UTF8, check it's valid
8969 * From rfc2044: encoding of the Unicode values on UTF-8:
8970 *
8971 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
8972 * 0000 0000-0000 007F 0xxxxxxx
8973 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
8974 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
8975 *
8976 * Check for the 0x110000 limit too
8977 */
8978 c = *cur;
8979 if (c & 0x80) {
8980 if ((cur[1] & 0xc0) != 0x80)
8981 goto encoding_error;
8982 if ((c & 0xe0) == 0xe0) {
8983
8984 if ((cur[2] & 0xc0) != 0x80)
8985 goto encoding_error;
8986 if ((c & 0xf0) == 0xf0) {
8987 if (((c & 0xf8) != 0xf0) ||
8988 ((cur[3] & 0xc0) != 0x80))
8989 goto encoding_error;
8990 /* 4-byte code */
8991 *len = 4;
8992 val = (cur[0] & 0x7) << 18;
8993 val |= (cur[1] & 0x3f) << 12;
8994 val |= (cur[2] & 0x3f) << 6;
8995 val |= cur[3] & 0x3f;
8996 } else {
8997 /* 3-byte code */
8998 *len = 3;
8999 val = (cur[0] & 0xf) << 12;
9000 val |= (cur[1] & 0x3f) << 6;
9001 val |= cur[2] & 0x3f;
9002 }
9003 } else {
9004 /* 2-byte code */
9005 *len = 2;
9006 val = (cur[0] & 0x1f) << 6;
9007 val |= cur[1] & 0x3f;
9008 }
9009 if (!IS_CHAR(val)) {
9010 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9011 }
9012 return(val);
9013 } else {
9014 /* 1-byte code */
9015 *len = 1;
9016 return(*cur);
9017 }
9018encoding_error:
9019 /*
9020 * If we detect an UTF8 error that probably means that the
9021 * input encoding didn't get properly advertised in the
9022 * declaration header. Report the error and switch the encoding
9023 * to ISO-Latin-1 (if you don't like this policy, just declare the
9024 * encoding !)
9025 */
9026 *len = 0;
9027 XP_ERROR0(XPATH_ENCODING_ERROR);
9028}
9029
9030/**
9031 * xmlXPathParseNCName:
9032 * @ctxt: the XPath Parser context
9033 *
9034 * parse an XML namespace non qualified name.
9035 *
9036 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9037 *
9038 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9039 * CombiningChar | Extender
9040 *
9041 * Returns the namespace name or NULL
9042 */
9043
9044xmlChar *
9045xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9046 const xmlChar *in;
9047 xmlChar *ret;
9048 int count = 0;
9049
9050 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9051 /*
9052 * Accelerator for simple ASCII names
9053 */
9054 in = ctxt->cur;
9055 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9056 ((*in >= 0x41) && (*in <= 0x5A)) ||
9057 (*in == '_')) {
9058 in++;
9059 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9060 ((*in >= 0x41) && (*in <= 0x5A)) ||
9061 ((*in >= 0x30) && (*in <= 0x39)) ||
9062 (*in == '_') || (*in == '.') ||
9063 (*in == '-'))
9064 in++;
9065 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9066 (*in == '[') || (*in == ']') || (*in == ':') ||
9067 (*in == '@') || (*in == '*')) {
9068 count = in - ctxt->cur;
9069 if (count == 0)
9070 return(NULL);
9071 ret = xmlStrndup(ctxt->cur, count);
9072 ctxt->cur = in;
9073 return(ret);
9074 }
9075 }
9076 return(xmlXPathParseNameComplex(ctxt, 0));
9077}
9078
9079
9080/**
9081 * xmlXPathParseQName:
9082 * @ctxt: the XPath Parser context
9083 * @prefix: a xmlChar **
9084 *
9085 * parse an XML qualified name
9086 *
9087 * [NS 5] QName ::= (Prefix ':')? LocalPart
9088 *
9089 * [NS 6] Prefix ::= NCName
9090 *
9091 * [NS 7] LocalPart ::= NCName
9092 *
9093 * Returns the function returns the local part, and prefix is updated
9094 * to get the Prefix if any.
9095 */
9096
9097static xmlChar *
9098xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9099 xmlChar *ret = NULL;
9100
9101 *prefix = NULL;
9102 ret = xmlXPathParseNCName(ctxt);
9103 if (ret && CUR == ':') {
9104 *prefix = ret;
9105 NEXT;
9106 ret = xmlXPathParseNCName(ctxt);
9107 }
9108 return(ret);
9109}
9110
9111/**
9112 * xmlXPathParseName:
9113 * @ctxt: the XPath Parser context
9114 *
9115 * parse an XML name
9116 *
9117 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9118 * CombiningChar | Extender
9119 *
9120 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9121 *
9122 * Returns the namespace name or NULL
9123 */
9124
9125xmlChar *
9126xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9127 const xmlChar *in;
9128 xmlChar *ret;
9129 size_t count = 0;
9130
9131 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9132 /*
9133 * Accelerator for simple ASCII names
9134 */
9135 in = ctxt->cur;
9136 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9137 ((*in >= 0x41) && (*in <= 0x5A)) ||
9138 (*in == '_') || (*in == ':')) {
9139 in++;
9140 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9141 ((*in >= 0x41) && (*in <= 0x5A)) ||
9142 ((*in >= 0x30) && (*in <= 0x39)) ||
9143 (*in == '_') || (*in == '-') ||
9144 (*in == ':') || (*in == '.'))
9145 in++;
9146 if ((*in > 0) && (*in < 0x80)) {
9147 count = in - ctxt->cur;
9148 if (count > XML_MAX_NAME_LENGTH) {
9149 ctxt->cur = in;
9150 XP_ERRORNULL(XPATH_EXPR_ERROR);
9151 }
9152 ret = xmlStrndup(ctxt->cur, count);
9153 ctxt->cur = in;
9154 return(ret);
9155 }
9156 }
9157 return(xmlXPathParseNameComplex(ctxt, 1));
9158}
9159
9160static xmlChar *
9161xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9162 xmlChar buf[XML_MAX_NAMELEN + 5];
9163 int len = 0, l;
9164 int c;
9165
9166 /*
9167 * Handler for more complex cases
9168 */
9169 c = CUR_CHAR(l);
9170 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9171 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9172 (c == '*') || /* accelerators */
9173 (!IS_LETTER(c) && (c != '_') &&
9174 ((!qualified) || (c != ':')))) {
9175 return(NULL);
9176 }
9177
9178 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9179 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9180 (c == '.') || (c == '-') ||
9181 (c == '_') || ((qualified) && (c == ':')) ||
9182 (IS_COMBINING(c)) ||
9183 (IS_EXTENDER(c)))) {
9184 COPY_BUF(l,buf,len,c);
9185 NEXTL(l);
9186 c = CUR_CHAR(l);
9187 if (len >= XML_MAX_NAMELEN) {
9188 /*
9189 * Okay someone managed to make a huge name, so he's ready to pay
9190 * for the processing speed.
9191 */
9192 xmlChar *buffer;
9193 int max = len * 2;
9194
9195 if (len > XML_MAX_NAME_LENGTH) {
9196 XP_ERRORNULL(XPATH_EXPR_ERROR);
9197 }
9198 buffer = (xmlChar *) xmlMallocAtomic(max);
9199 if (buffer == NULL) {
9200 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9201 }
9202 memcpy(buffer, buf, len);
9203 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9204 (c == '.') || (c == '-') ||
9205 (c == '_') || ((qualified) && (c == ':')) ||
9206 (IS_COMBINING(c)) ||
9207 (IS_EXTENDER(c))) {
9208 if (len + 10 > max) {
9209 xmlChar *tmp;
9210 if (max > XML_MAX_NAME_LENGTH) {
9211 xmlFree(buffer);
9212 XP_ERRORNULL(XPATH_EXPR_ERROR);
9213 }
9214 max *= 2;
9215 tmp = (xmlChar *) xmlRealloc(buffer, max);
9216 if (tmp == NULL) {
9217 xmlFree(buffer);
9218 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9219 }
9220 buffer = tmp;
9221 }
9222 COPY_BUF(l,buffer,len,c);
9223 NEXTL(l);
9224 c = CUR_CHAR(l);
9225 }
9226 buffer[len] = 0;
9227 return(buffer);
9228 }
9229 }
9230 if (len == 0)
9231 return(NULL);
9232 return(xmlStrndup(buf, len));
9233}
9234
9235#define MAX_FRAC 20
9236
9237/**
9238 * xmlXPathStringEvalNumber:
9239 * @str: A string to scan
9240 *
9241 * [30a] Float ::= Number ('e' Digits?)?
9242 *
9243 * [30] Number ::= Digits ('.' Digits?)?
9244 * | '.' Digits
9245 * [31] Digits ::= [0-9]+
9246 *
9247 * Compile a Number in the string
9248 * In complement of the Number expression, this function also handles
9249 * negative values : '-' Number.
9250 *
9251 * Returns the double value.
9252 */
9253double
9254xmlXPathStringEvalNumber(const xmlChar *str) {
9255 const xmlChar *cur = str;
9256 double ret;
9257 int ok = 0;
9258 int isneg = 0;
9259 int exponent = 0;
9260 int is_exponent_negative = 0;
9261#ifdef __GNUC__
9262 unsigned long tmp = 0;
9263 double temp;
9264#endif
9265 if (cur == NULL) return(0);
9266 while (IS_BLANK_CH(*cur)) cur++;
9267 if (*cur == '-') {
9268 isneg = 1;
9269 cur++;
9270 }
9271 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9272 return(xmlXPathNAN);
9273 }
9274
9275#ifdef __GNUC__
9276 /*
9277 * tmp/temp is a workaround against a gcc compiler bug
9278 * http://veillard.com/gcc.bug
9279 */
9280 ret = 0;
9281 while ((*cur >= '0') && (*cur <= '9')) {
9282 ret = ret * 10;
9283 tmp = (*cur - '0');
9284 ok = 1;
9285 cur++;
9286 temp = (double) tmp;
9287 ret = ret + temp;
9288 }
9289#else
9290 ret = 0;
9291 while ((*cur >= '0') && (*cur <= '9')) {
9292 ret = ret * 10 + (*cur - '0');
9293 ok = 1;
9294 cur++;
9295 }
9296#endif
9297
9298 if (*cur == '.') {
9299 int v, frac = 0, max;
9300 double fraction = 0;
9301
9302 cur++;
9303 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9304 return(xmlXPathNAN);
9305 }
9306 while (*cur == '0') {
9307 frac = frac + 1;
9308 cur++;
9309 }
9310 max = frac + MAX_FRAC;
9311 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
9312 v = (*cur - '0');
9313 fraction = fraction * 10 + v;
9314 frac = frac + 1;
9315 cur++;
9316 }
9317 fraction /= pow(10.0, frac);
9318 ret = ret + fraction;
9319 while ((*cur >= '0') && (*cur <= '9'))
9320 cur++;
9321 }
9322 if ((*cur == 'e') || (*cur == 'E')) {
9323 cur++;
9324 if (*cur == '-') {
9325 is_exponent_negative = 1;
9326 cur++;
9327 } else if (*cur == '+') {
9328 cur++;
9329 }
9330 while ((*cur >= '0') && (*cur <= '9')) {
9331 if (exponent < 1000000)
9332 exponent = exponent * 10 + (*cur - '0');
9333 cur++;
9334 }
9335 }
9336 while (IS_BLANK_CH(*cur)) cur++;
9337 if (*cur != 0) return(xmlXPathNAN);
9338 if (isneg) ret = -ret;
9339 if (is_exponent_negative) exponent = -exponent;
9340 ret *= pow(10.0, (double)exponent);
9341 return(ret);
9342}
9343
9344/**
9345 * xmlXPathCompNumber:
9346 * @ctxt: the XPath Parser context
9347 *
9348 * [30] Number ::= Digits ('.' Digits?)?
9349 * | '.' Digits
9350 * [31] Digits ::= [0-9]+
9351 *
9352 * Compile a Number, then push it on the stack
9353 *
9354 */
9355static void
9356xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9357{
9358 double ret = 0.0;
9359 int ok = 0;
9360 int exponent = 0;
9361 int is_exponent_negative = 0;
9362 xmlXPathObjectPtr num;
9363#ifdef __GNUC__
9364 unsigned long tmp = 0;
9365 double temp;
9366#endif
9367
9368 CHECK_ERROR;
9369 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9370 XP_ERROR(XPATH_NUMBER_ERROR);
9371 }
9372#ifdef __GNUC__
9373 /*
9374 * tmp/temp is a workaround against a gcc compiler bug
9375 * http://veillard.com/gcc.bug
9376 */
9377 ret = 0;
9378 while ((CUR >= '0') && (CUR <= '9')) {
9379 ret = ret * 10;
9380 tmp = (CUR - '0');
9381 ok = 1;
9382 NEXT;
9383 temp = (double) tmp;
9384 ret = ret + temp;
9385 }
9386#else
9387 ret = 0;
9388 while ((CUR >= '0') && (CUR <= '9')) {
9389 ret = ret * 10 + (CUR - '0');
9390 ok = 1;
9391 NEXT;
9392 }
9393#endif
9394 if (CUR == '.') {
9395 int v, frac = 0, max;
9396 double fraction = 0;
9397
9398 NEXT;
9399 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9400 XP_ERROR(XPATH_NUMBER_ERROR);
9401 }
9402 while (CUR == '0') {
9403 frac = frac + 1;
9404 NEXT;
9405 }
9406 max = frac + MAX_FRAC;
9407 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
9408 v = (CUR - '0');
9409 fraction = fraction * 10 + v;
9410 frac = frac + 1;
9411 NEXT;
9412 }
9413 fraction /= pow(10.0, frac);
9414 ret = ret + fraction;
9415 while ((CUR >= '0') && (CUR <= '9'))
9416 NEXT;
9417 }
9418 if ((CUR == 'e') || (CUR == 'E')) {
9419 NEXT;
9420 if (CUR == '-') {
9421 is_exponent_negative = 1;
9422 NEXT;
9423 } else if (CUR == '+') {
9424 NEXT;
9425 }
9426 while ((CUR >= '0') && (CUR <= '9')) {
9427 if (exponent < 1000000)
9428 exponent = exponent * 10 + (CUR - '0');
9429 NEXT;
9430 }
9431 if (is_exponent_negative)
9432 exponent = -exponent;
9433 ret *= pow(10.0, (double) exponent);
9434 }
9435 num = xmlXPathCacheNewFloat(ctxt->context, ret);
9436 if (num == NULL) {
9437 ctxt->error = XPATH_MEMORY_ERROR;
9438 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
9439 NULL) == -1) {
9440 xmlXPathReleaseObject(ctxt->context, num);
9441 }
9442}
9443
9444/**
9445 * xmlXPathParseLiteral:
9446 * @ctxt: the XPath Parser context
9447 *
9448 * Parse a Literal
9449 *
9450 * [29] Literal ::= '"' [^"]* '"'
9451 * | "'" [^']* "'"
9452 *
9453 * Returns the value found or NULL in case of error
9454 */
9455static xmlChar *
9456xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9457 const xmlChar *q;
9458 xmlChar *ret = NULL;
9459
9460 if (CUR == '"') {
9461 NEXT;
9462 q = CUR_PTR;
9463 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
9464 NEXT;
9465 if (!IS_CHAR_CH(CUR)) {
9466 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9467 } else {
9468 ret = xmlStrndup(q, CUR_PTR - q);
9469 NEXT;
9470 }
9471 } else if (CUR == '\'') {
9472 NEXT;
9473 q = CUR_PTR;
9474 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
9475 NEXT;
9476 if (!IS_CHAR_CH(CUR)) {
9477 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9478 } else {
9479 ret = xmlStrndup(q, CUR_PTR - q);
9480 NEXT;
9481 }
9482 } else {
9483 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9484 }
9485 return(ret);
9486}
9487
9488/**
9489 * xmlXPathCompLiteral:
9490 * @ctxt: the XPath Parser context
9491 *
9492 * Parse a Literal and push it on the stack.
9493 *
9494 * [29] Literal ::= '"' [^"]* '"'
9495 * | "'" [^']* "'"
9496 *
9497 * TODO: xmlXPathCompLiteral memory allocation could be improved.
9498 */
9499static void
9500xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9501 const xmlChar *q;
9502 xmlChar *ret = NULL;
9503 xmlXPathObjectPtr lit;
9504
9505 if (CUR == '"') {
9506 NEXT;
9507 q = CUR_PTR;
9508 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
9509 NEXT;
9510 if (!IS_CHAR_CH(CUR)) {
9511 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9512 } else {
9513 ret = xmlStrndup(q, CUR_PTR - q);
9514 NEXT;
9515 }
9516 } else if (CUR == '\'') {
9517 NEXT;
9518 q = CUR_PTR;
9519 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
9520 NEXT;
9521 if (!IS_CHAR_CH(CUR)) {
9522 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9523 } else {
9524 ret = xmlStrndup(q, CUR_PTR - q);
9525 NEXT;
9526 }
9527 } else {
9528 XP_ERROR(XPATH_START_LITERAL_ERROR);
9529 }
9530 if (ret == NULL) {
9531 xmlXPathPErrMemory(ctxt, NULL);
9532 return;
9533 }
9534 lit = xmlXPathCacheNewString(ctxt->context, ret);
9535 if (lit == NULL) {
9536 ctxt->error = XPATH_MEMORY_ERROR;
9537 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
9538 NULL) == -1) {
9539 xmlXPathReleaseObject(ctxt->context, lit);
9540 }
9541 xmlFree(ret);
9542}
9543
9544/**
9545 * xmlXPathCompVariableReference:
9546 * @ctxt: the XPath Parser context
9547 *
9548 * Parse a VariableReference, evaluate it and push it on the stack.
9549 *
9550 * The variable bindings consist of a mapping from variable names
9551 * to variable values. The value of a variable is an object, which can be
9552 * of any of the types that are possible for the value of an expression,
9553 * and may also be of additional types not specified here.
9554 *
9555 * Early evaluation is possible since:
9556 * The variable bindings [...] used to evaluate a subexpression are
9557 * always the same as those used to evaluate the containing expression.
9558 *
9559 * [36] VariableReference ::= '$' QName
9560 */
9561static void
9562xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9563 xmlChar *name;
9564 xmlChar *prefix;
9565
9566 SKIP_BLANKS;
9567 if (CUR != '$') {
9568 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9569 }
9570 NEXT;
9571 name = xmlXPathParseQName(ctxt, &prefix);
9572 if (name == NULL) {
9573 xmlFree(prefix);
9574 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9575 }
9576 ctxt->comp->last = -1;
9577 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9578 xmlFree(prefix);
9579 xmlFree(name);
9580 }
9581 SKIP_BLANKS;
9582 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9583 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9584 }
9585}
9586
9587/**
9588 * xmlXPathIsNodeType:
9589 * @name: a name string
9590 *
9591 * Is the name given a NodeType one.
9592 *
9593 * [38] NodeType ::= 'comment'
9594 * | 'text'
9595 * | 'processing-instruction'
9596 * | 'node'
9597 *
9598 * Returns 1 if true 0 otherwise
9599 */
9600int
9601xmlXPathIsNodeType(const xmlChar *name) {
9602 if (name == NULL)
9603 return(0);
9604
9605 if (xmlStrEqual(name, BAD_CAST "node"))
9606 return(1);
9607 if (xmlStrEqual(name, BAD_CAST "text"))
9608 return(1);
9609 if (xmlStrEqual(name, BAD_CAST "comment"))
9610 return(1);
9611 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9612 return(1);
9613 return(0);
9614}
9615
9616/**
9617 * xmlXPathCompFunctionCall:
9618 * @ctxt: the XPath Parser context
9619 *
9620 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9621 * [17] Argument ::= Expr
9622 *
9623 * Compile a function call, the evaluation of all arguments are
9624 * pushed on the stack
9625 */
9626static void
9627xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9628 xmlChar *name;
9629 xmlChar *prefix;
9630 int nbargs = 0;
9631 int sort = 1;
9632
9633 name = xmlXPathParseQName(ctxt, &prefix);
9634 if (name == NULL) {
9635 xmlFree(prefix);
9636 XP_ERROR(XPATH_EXPR_ERROR);
9637 }
9638 SKIP_BLANKS;
9639
9640 if (CUR != '(') {
9641 xmlFree(name);
9642 xmlFree(prefix);
9643 XP_ERROR(XPATH_EXPR_ERROR);
9644 }
9645 NEXT;
9646 SKIP_BLANKS;
9647
9648 /*
9649 * Optimization for count(): we don't need the node-set to be sorted.
9650 */
9651 if ((prefix == NULL) && (name[0] == 'c') &&
9652 xmlStrEqual(name, BAD_CAST "count"))
9653 {
9654 sort = 0;
9655 }
9656 ctxt->comp->last = -1;
9657 if (CUR != ')') {
9658 while (CUR != 0) {
9659 int op1 = ctxt->comp->last;
9660 ctxt->comp->last = -1;
9661 xmlXPathCompileExpr(ctxt, sort);
9662 if (ctxt->error != XPATH_EXPRESSION_OK) {
9663 xmlFree(name);
9664 xmlFree(prefix);
9665 return;
9666 }
9667 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9668 nbargs++;
9669 if (CUR == ')') break;
9670 if (CUR != ',') {
9671 xmlFree(name);
9672 xmlFree(prefix);
9673 XP_ERROR(XPATH_EXPR_ERROR);
9674 }
9675 NEXT;
9676 SKIP_BLANKS;
9677 }
9678 }
9679 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9680 xmlFree(prefix);
9681 xmlFree(name);
9682 }
9683 NEXT;
9684 SKIP_BLANKS;
9685}
9686
9687/**
9688 * xmlXPathCompPrimaryExpr:
9689 * @ctxt: the XPath Parser context
9690 *
9691 * [15] PrimaryExpr ::= VariableReference
9692 * | '(' Expr ')'
9693 * | Literal
9694 * | Number
9695 * | FunctionCall
9696 *
9697 * Compile a primary expression.
9698 */
9699static void
9700xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9701 SKIP_BLANKS;
9702 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9703 else if (CUR == '(') {
9704 NEXT;
9705 SKIP_BLANKS;
9706 xmlXPathCompileExpr(ctxt, 1);
9707 CHECK_ERROR;
9708 if (CUR != ')') {
9709 XP_ERROR(XPATH_EXPR_ERROR);
9710 }
9711 NEXT;
9712 SKIP_BLANKS;
9713 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9714 xmlXPathCompNumber(ctxt);
9715 } else if ((CUR == '\'') || (CUR == '"')) {
9716 xmlXPathCompLiteral(ctxt);
9717 } else {
9718 xmlXPathCompFunctionCall(ctxt);
9719 }
9720 SKIP_BLANKS;
9721}
9722
9723/**
9724 * xmlXPathCompFilterExpr:
9725 * @ctxt: the XPath Parser context
9726 *
9727 * [20] FilterExpr ::= PrimaryExpr
9728 * | FilterExpr Predicate
9729 *
9730 * Compile a filter expression.
9731 * Square brackets are used to filter expressions in the same way that
9732 * they are used in location paths. It is an error if the expression to
9733 * be filtered does not evaluate to a node-set. The context node list
9734 * used for evaluating the expression in square brackets is the node-set
9735 * to be filtered listed in document order.
9736 */
9737
9738static void
9739xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9740 xmlXPathCompPrimaryExpr(ctxt);
9741 CHECK_ERROR;
9742 SKIP_BLANKS;
9743
9744 while (CUR == '[') {
9745 xmlXPathCompPredicate(ctxt, 1);
9746 SKIP_BLANKS;
9747 }
9748
9749
9750}
9751
9752/**
9753 * xmlXPathScanName:
9754 * @ctxt: the XPath Parser context
9755 *
9756 * Trickery: parse an XML name but without consuming the input flow
9757 * Needed to avoid insanity in the parser state.
9758 *
9759 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9760 * CombiningChar | Extender
9761 *
9762 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9763 *
9764 * [6] Names ::= Name (S Name)*
9765 *
9766 * Returns the Name parsed or NULL
9767 */
9768
9769static xmlChar *
9770xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9771 int l;
9772 int c;
9773 const xmlChar *cur;
9774 xmlChar *ret;
9775
9776 cur = ctxt->cur;
9777
9778 c = CUR_CHAR(l);
9779 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9780 (!IS_LETTER(c) && (c != '_') &&
9781 (c != ':'))) {
9782 return(NULL);
9783 }
9784
9785 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9786 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9787 (c == '.') || (c == '-') ||
9788 (c == '_') || (c == ':') ||
9789 (IS_COMBINING(c)) ||
9790 (IS_EXTENDER(c)))) {
9791 NEXTL(l);
9792 c = CUR_CHAR(l);
9793 }
9794 ret = xmlStrndup(cur, ctxt->cur - cur);
9795 ctxt->cur = cur;
9796 return(ret);
9797}
9798
9799/**
9800 * xmlXPathCompPathExpr:
9801 * @ctxt: the XPath Parser context
9802 *
9803 * [19] PathExpr ::= LocationPath
9804 * | FilterExpr
9805 * | FilterExpr '/' RelativeLocationPath
9806 * | FilterExpr '//' RelativeLocationPath
9807 *
9808 * Compile a path expression.
9809 * The / operator and // operators combine an arbitrary expression
9810 * and a relative location path. It is an error if the expression
9811 * does not evaluate to a node-set.
9812 * The / operator does composition in the same way as when / is
9813 * used in a location path. As in location paths, // is short for
9814 * /descendant-or-self::node()/.
9815 */
9816
9817static void
9818xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9819 int lc = 1; /* Should we branch to LocationPath ? */
9820 xmlChar *name = NULL; /* we may have to preparse a name to find out */
9821
9822 SKIP_BLANKS;
9823 if ((CUR == '$') || (CUR == '(') ||
9824 (IS_ASCII_DIGIT(CUR)) ||
9825 (CUR == '\'') || (CUR == '"') ||
9826 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9827 lc = 0;
9828 } else if (CUR == '*') {
9829 /* relative or absolute location path */
9830 lc = 1;
9831 } else if (CUR == '/') {
9832 /* relative or absolute location path */
9833 lc = 1;
9834 } else if (CUR == '@') {
9835 /* relative abbreviated attribute location path */
9836 lc = 1;
9837 } else if (CUR == '.') {
9838 /* relative abbreviated attribute location path */
9839 lc = 1;
9840 } else {
9841 /*
9842 * Problem is finding if we have a name here whether it's:
9843 * - a nodetype
9844 * - a function call in which case it's followed by '('
9845 * - an axis in which case it's followed by ':'
9846 * - a element name
9847 * We do an a priori analysis here rather than having to
9848 * maintain parsed token content through the recursive function
9849 * calls. This looks uglier but makes the code easier to
9850 * read/write/debug.
9851 */
9852 SKIP_BLANKS;
9853 name = xmlXPathScanName(ctxt);
9854 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9855 lc = 1;
9856 xmlFree(name);
9857 } else if (name != NULL) {
9858 int len =xmlStrlen(name);
9859
9860
9861 while (NXT(len) != 0) {
9862 if (NXT(len) == '/') {
9863 /* element name */
9864 lc = 1;
9865 break;
9866 } else if (IS_BLANK_CH(NXT(len))) {
9867 /* ignore blanks */
9868 ;
9869 } else if (NXT(len) == ':') {
9870 lc = 1;
9871 break;
9872 } else if ((NXT(len) == '(')) {
9873 /* Node Type or Function */
9874 if (xmlXPathIsNodeType(name)) {
9875 lc = 1;
9876#ifdef LIBXML_XPTR_LOCS_ENABLED
9877 } else if (ctxt->xptr &&
9878 xmlStrEqual(name, BAD_CAST "range-to")) {
9879 lc = 1;
9880#endif
9881 } else {
9882 lc = 0;
9883 }
9884 break;
9885 } else if ((NXT(len) == '[')) {
9886 /* element name */
9887 lc = 1;
9888 break;
9889 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9890 (NXT(len) == '=')) {
9891 lc = 1;
9892 break;
9893 } else {
9894 lc = 1;
9895 break;
9896 }
9897 len++;
9898 }
9899 if (NXT(len) == 0) {
9900 /* element name */
9901 lc = 1;
9902 }
9903 xmlFree(name);
9904 } else {
9905 /* make sure all cases are covered explicitly */
9906 XP_ERROR(XPATH_EXPR_ERROR);
9907 }
9908 }
9909
9910 if (lc) {
9911 if (CUR == '/') {
9912 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9913 } else {
9914 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9915 }
9916 xmlXPathCompLocationPath(ctxt);
9917 } else {
9918 xmlXPathCompFilterExpr(ctxt);
9919 CHECK_ERROR;
9920 if ((CUR == '/') && (NXT(1) == '/')) {
9921 SKIP(2);
9922 SKIP_BLANKS;
9923
9924 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9925 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9926
9927 xmlXPathCompRelativeLocationPath(ctxt);
9928 } else if (CUR == '/') {
9929 xmlXPathCompRelativeLocationPath(ctxt);
9930 }
9931 }
9932 SKIP_BLANKS;
9933}
9934
9935/**
9936 * xmlXPathCompUnionExpr:
9937 * @ctxt: the XPath Parser context
9938 *
9939 * [18] UnionExpr ::= PathExpr
9940 * | UnionExpr '|' PathExpr
9941 *
9942 * Compile an union expression.
9943 */
9944
9945static void
9946xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9947 xmlXPathCompPathExpr(ctxt);
9948 CHECK_ERROR;
9949 SKIP_BLANKS;
9950 while (CUR == '|') {
9951 int op1 = ctxt->comp->last;
9952 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9953
9954 NEXT;
9955 SKIP_BLANKS;
9956 xmlXPathCompPathExpr(ctxt);
9957
9958 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9959
9960 SKIP_BLANKS;
9961 }
9962}
9963
9964/**
9965 * xmlXPathCompUnaryExpr:
9966 * @ctxt: the XPath Parser context
9967 *
9968 * [27] UnaryExpr ::= UnionExpr
9969 * | '-' UnaryExpr
9970 *
9971 * Compile an unary expression.
9972 */
9973
9974static void
9975xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9976 int minus = 0;
9977 int found = 0;
9978
9979 SKIP_BLANKS;
9980 while (CUR == '-') {
9981 minus = 1 - minus;
9982 found = 1;
9983 NEXT;
9984 SKIP_BLANKS;
9985 }
9986
9987 xmlXPathCompUnionExpr(ctxt);
9988 CHECK_ERROR;
9989 if (found) {
9990 if (minus)
9991 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9992 else
9993 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9994 }
9995}
9996
9997/**
9998 * xmlXPathCompMultiplicativeExpr:
9999 * @ctxt: the XPath Parser context
10000 *
10001 * [26] MultiplicativeExpr ::= UnaryExpr
10002 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10003 * | MultiplicativeExpr 'div' UnaryExpr
10004 * | MultiplicativeExpr 'mod' UnaryExpr
10005 * [34] MultiplyOperator ::= '*'
10006 *
10007 * Compile an Additive expression.
10008 */
10009
10010static void
10011xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10012 xmlXPathCompUnaryExpr(ctxt);
10013 CHECK_ERROR;
10014 SKIP_BLANKS;
10015 while ((CUR == '*') ||
10016 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10017 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10018 int op = -1;
10019 int op1 = ctxt->comp->last;
10020
10021 if (CUR == '*') {
10022 op = 0;
10023 NEXT;
10024 } else if (CUR == 'd') {
10025 op = 1;
10026 SKIP(3);
10027 } else if (CUR == 'm') {
10028 op = 2;
10029 SKIP(3);
10030 }
10031 SKIP_BLANKS;
10032 xmlXPathCompUnaryExpr(ctxt);
10033 CHECK_ERROR;
10034 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10035 SKIP_BLANKS;
10036 }
10037}
10038
10039/**
10040 * xmlXPathCompAdditiveExpr:
10041 * @ctxt: the XPath Parser context
10042 *
10043 * [25] AdditiveExpr ::= MultiplicativeExpr
10044 * | AdditiveExpr '+' MultiplicativeExpr
10045 * | AdditiveExpr '-' MultiplicativeExpr
10046 *
10047 * Compile an Additive expression.
10048 */
10049
10050static void
10051xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10052
10053 xmlXPathCompMultiplicativeExpr(ctxt);
10054 CHECK_ERROR;
10055 SKIP_BLANKS;
10056 while ((CUR == '+') || (CUR == '-')) {
10057 int plus;
10058 int op1 = ctxt->comp->last;
10059
10060 if (CUR == '+') plus = 1;
10061 else plus = 0;
10062 NEXT;
10063 SKIP_BLANKS;
10064 xmlXPathCompMultiplicativeExpr(ctxt);
10065 CHECK_ERROR;
10066 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10067 SKIP_BLANKS;
10068 }
10069}
10070
10071/**
10072 * xmlXPathCompRelationalExpr:
10073 * @ctxt: the XPath Parser context
10074 *
10075 * [24] RelationalExpr ::= AdditiveExpr
10076 * | RelationalExpr '<' AdditiveExpr
10077 * | RelationalExpr '>' AdditiveExpr
10078 * | RelationalExpr '<=' AdditiveExpr
10079 * | RelationalExpr '>=' AdditiveExpr
10080 *
10081 * A <= B > C is allowed ? Answer from James, yes with
10082 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10083 * which is basically what got implemented.
10084 *
10085 * Compile a Relational expression, then push the result
10086 * on the stack
10087 */
10088
10089static void
10090xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10091 xmlXPathCompAdditiveExpr(ctxt);
10092 CHECK_ERROR;
10093 SKIP_BLANKS;
10094 while ((CUR == '<') || (CUR == '>')) {
10095 int inf, strict;
10096 int op1 = ctxt->comp->last;
10097
10098 if (CUR == '<') inf = 1;
10099 else inf = 0;
10100 if (NXT(1) == '=') strict = 0;
10101 else strict = 1;
10102 NEXT;
10103 if (!strict) NEXT;
10104 SKIP_BLANKS;
10105 xmlXPathCompAdditiveExpr(ctxt);
10106 CHECK_ERROR;
10107 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10108 SKIP_BLANKS;
10109 }
10110}
10111
10112/**
10113 * xmlXPathCompEqualityExpr:
10114 * @ctxt: the XPath Parser context
10115 *
10116 * [23] EqualityExpr ::= RelationalExpr
10117 * | EqualityExpr '=' RelationalExpr
10118 * | EqualityExpr '!=' RelationalExpr
10119 *
10120 * A != B != C is allowed ? Answer from James, yes with
10121 * (RelationalExpr = RelationalExpr) = RelationalExpr
10122 * (RelationalExpr != RelationalExpr) != RelationalExpr
10123 * which is basically what got implemented.
10124 *
10125 * Compile an Equality expression.
10126 *
10127 */
10128static void
10129xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10130 xmlXPathCompRelationalExpr(ctxt);
10131 CHECK_ERROR;
10132 SKIP_BLANKS;
10133 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10134 int eq;
10135 int op1 = ctxt->comp->last;
10136
10137 if (CUR == '=') eq = 1;
10138 else eq = 0;
10139 NEXT;
10140 if (!eq) NEXT;
10141 SKIP_BLANKS;
10142 xmlXPathCompRelationalExpr(ctxt);
10143 CHECK_ERROR;
10144 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10145 SKIP_BLANKS;
10146 }
10147}
10148
10149/**
10150 * xmlXPathCompAndExpr:
10151 * @ctxt: the XPath Parser context
10152 *
10153 * [22] AndExpr ::= EqualityExpr
10154 * | AndExpr 'and' EqualityExpr
10155 *
10156 * Compile an AND expression.
10157 *
10158 */
10159static void
10160xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10161 xmlXPathCompEqualityExpr(ctxt);
10162 CHECK_ERROR;
10163 SKIP_BLANKS;
10164 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10165 int op1 = ctxt->comp->last;
10166 SKIP(3);
10167 SKIP_BLANKS;
10168 xmlXPathCompEqualityExpr(ctxt);
10169 CHECK_ERROR;
10170 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10171 SKIP_BLANKS;
10172 }
10173}
10174
10175/**
10176 * xmlXPathCompileExpr:
10177 * @ctxt: the XPath Parser context
10178 *
10179 * [14] Expr ::= OrExpr
10180 * [21] OrExpr ::= AndExpr
10181 * | OrExpr 'or' AndExpr
10182 *
10183 * Parse and compile an expression
10184 */
10185static void
10186xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10187 xmlXPathContextPtr xpctxt = ctxt->context;
10188
10189 if (xpctxt != NULL) {
10190 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10191 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10192 /*
10193 * Parsing a single '(' pushes about 10 functions on the call stack
10194 * before recursing!
10195 */
10196 xpctxt->depth += 10;
10197 }
10198
10199 xmlXPathCompAndExpr(ctxt);
10200 CHECK_ERROR;
10201 SKIP_BLANKS;
10202 while ((CUR == 'o') && (NXT(1) == 'r')) {
10203 int op1 = ctxt->comp->last;
10204 SKIP(2);
10205 SKIP_BLANKS;
10206 xmlXPathCompAndExpr(ctxt);
10207 CHECK_ERROR;
10208 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10209 SKIP_BLANKS;
10210 }
10211 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10212 /* more ops could be optimized too */
10213 /*
10214 * This is the main place to eliminate sorting for
10215 * operations which don't require a sorted node-set.
10216 * E.g. count().
10217 */
10218 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10219 }
10220
10221 if (xpctxt != NULL)
10222 xpctxt->depth -= 10;
10223}
10224
10225/**
10226 * xmlXPathCompPredicate:
10227 * @ctxt: the XPath Parser context
10228 * @filter: act as a filter
10229 *
10230 * [8] Predicate ::= '[' PredicateExpr ']'
10231 * [9] PredicateExpr ::= Expr
10232 *
10233 * Compile a predicate expression
10234 */
10235static void
10236xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10237 int op1 = ctxt->comp->last;
10238
10239 SKIP_BLANKS;
10240 if (CUR != '[') {
10241 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10242 }
10243 NEXT;
10244 SKIP_BLANKS;
10245
10246 ctxt->comp->last = -1;
10247 /*
10248 * This call to xmlXPathCompileExpr() will deactivate sorting
10249 * of the predicate result.
10250 * TODO: Sorting is still activated for filters, since I'm not
10251 * sure if needed. Normally sorting should not be needed, since
10252 * a filter can only diminish the number of items in a sequence,
10253 * but won't change its order; so if the initial sequence is sorted,
10254 * subsequent sorting is not needed.
10255 */
10256 if (! filter)
10257 xmlXPathCompileExpr(ctxt, 0);
10258 else
10259 xmlXPathCompileExpr(ctxt, 1);
10260 CHECK_ERROR;
10261
10262 if (CUR != ']') {
10263 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10264 }
10265
10266 if (filter)
10267 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10268 else
10269 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10270
10271 NEXT;
10272 SKIP_BLANKS;
10273}
10274
10275/**
10276 * xmlXPathCompNodeTest:
10277 * @ctxt: the XPath Parser context
10278 * @test: pointer to a xmlXPathTestVal
10279 * @type: pointer to a xmlXPathTypeVal
10280 * @prefix: placeholder for a possible name prefix
10281 *
10282 * [7] NodeTest ::= NameTest
10283 * | NodeType '(' ')'
10284 * | 'processing-instruction' '(' Literal ')'
10285 *
10286 * [37] NameTest ::= '*'
10287 * | NCName ':' '*'
10288 * | QName
10289 * [38] NodeType ::= 'comment'
10290 * | 'text'
10291 * | 'processing-instruction'
10292 * | 'node'
10293 *
10294 * Returns the name found and updates @test, @type and @prefix appropriately
10295 */
10296static xmlChar *
10297xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10298 xmlXPathTypeVal *type, xmlChar **prefix,
10299 xmlChar *name) {
10300 int blanks;
10301
10302 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10303 STRANGE;
10304 return(NULL);
10305 }
10306 *type = (xmlXPathTypeVal) 0;
10307 *test = (xmlXPathTestVal) 0;
10308 *prefix = NULL;
10309 SKIP_BLANKS;
10310
10311 if ((name == NULL) && (CUR == '*')) {
10312 /*
10313 * All elements
10314 */
10315 NEXT;
10316 *test = NODE_TEST_ALL;
10317 return(NULL);
10318 }
10319
10320 if (name == NULL)
10321 name = xmlXPathParseNCName(ctxt);
10322 if (name == NULL) {
10323 XP_ERRORNULL(XPATH_EXPR_ERROR);
10324 }
10325
10326 blanks = IS_BLANK_CH(CUR);
10327 SKIP_BLANKS;
10328 if (CUR == '(') {
10329 NEXT;
10330 /*
10331 * NodeType or PI search
10332 */
10333 if (xmlStrEqual(name, BAD_CAST "comment"))
10334 *type = NODE_TYPE_COMMENT;
10335 else if (xmlStrEqual(name, BAD_CAST "node"))
10336 *type = NODE_TYPE_NODE;
10337 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10338 *type = NODE_TYPE_PI;
10339 else if (xmlStrEqual(name, BAD_CAST "text"))
10340 *type = NODE_TYPE_TEXT;
10341 else {
10342 if (name != NULL)
10343 xmlFree(name);
10344 XP_ERRORNULL(XPATH_EXPR_ERROR);
10345 }
10346
10347 *test = NODE_TEST_TYPE;
10348
10349 SKIP_BLANKS;
10350 if (*type == NODE_TYPE_PI) {
10351 /*
10352 * Specific case: search a PI by name.
10353 */
10354 if (name != NULL)
10355 xmlFree(name);
10356 name = NULL;
10357 if (CUR != ')') {
10358 name = xmlXPathParseLiteral(ctxt);
10359 if (name == NULL) {
10360 XP_ERRORNULL(XPATH_EXPR_ERROR);
10361 }
10362 *test = NODE_TEST_PI;
10363 SKIP_BLANKS;
10364 }
10365 }
10366 if (CUR != ')') {
10367 if (name != NULL)
10368 xmlFree(name);
10369 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10370 }
10371 NEXT;
10372 return(name);
10373 }
10374 *test = NODE_TEST_NAME;
10375 if ((!blanks) && (CUR == ':')) {
10376 NEXT;
10377
10378 /*
10379 * Since currently the parser context don't have a
10380 * namespace list associated:
10381 * The namespace name for this prefix can be computed
10382 * only at evaluation time. The compilation is done
10383 * outside of any context.
10384 */
10385#if 0
10386 *prefix = xmlXPathNsLookup(ctxt->context, name);
10387 if (name != NULL)
10388 xmlFree(name);
10389 if (*prefix == NULL) {
10390 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10391 }
10392#else
10393 *prefix = name;
10394#endif
10395
10396 if (CUR == '*') {
10397 /*
10398 * All elements
10399 */
10400 NEXT;
10401 *test = NODE_TEST_ALL;
10402 return(NULL);
10403 }
10404
10405 name = xmlXPathParseNCName(ctxt);
10406 if (name == NULL) {
10407 XP_ERRORNULL(XPATH_EXPR_ERROR);
10408 }
10409 }
10410 return(name);
10411}
10412
10413/**
10414 * xmlXPathIsAxisName:
10415 * @name: a preparsed name token
10416 *
10417 * [6] AxisName ::= 'ancestor'
10418 * | 'ancestor-or-self'
10419 * | 'attribute'
10420 * | 'child'
10421 * | 'descendant'
10422 * | 'descendant-or-self'
10423 * | 'following'
10424 * | 'following-sibling'
10425 * | 'namespace'
10426 * | 'parent'
10427 * | 'preceding'
10428 * | 'preceding-sibling'
10429 * | 'self'
10430 *
10431 * Returns the axis or 0
10432 */
10433static xmlXPathAxisVal
10434xmlXPathIsAxisName(const xmlChar *name) {
10435 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10436 switch (name[0]) {
10437 case 'a':
10438 if (xmlStrEqual(name, BAD_CAST "ancestor"))
10439 ret = AXIS_ANCESTOR;
10440 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10441 ret = AXIS_ANCESTOR_OR_SELF;
10442 if (xmlStrEqual(name, BAD_CAST "attribute"))
10443 ret = AXIS_ATTRIBUTE;
10444 break;
10445 case 'c':
10446 if (xmlStrEqual(name, BAD_CAST "child"))
10447 ret = AXIS_CHILD;
10448 break;
10449 case 'd':
10450 if (xmlStrEqual(name, BAD_CAST "descendant"))
10451 ret = AXIS_DESCENDANT;
10452 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10453 ret = AXIS_DESCENDANT_OR_SELF;
10454 break;
10455 case 'f':
10456 if (xmlStrEqual(name, BAD_CAST "following"))
10457 ret = AXIS_FOLLOWING;
10458 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10459 ret = AXIS_FOLLOWING_SIBLING;
10460 break;
10461 case 'n':
10462 if (xmlStrEqual(name, BAD_CAST "namespace"))
10463 ret = AXIS_NAMESPACE;
10464 break;
10465 case 'p':
10466 if (xmlStrEqual(name, BAD_CAST "parent"))
10467 ret = AXIS_PARENT;
10468 if (xmlStrEqual(name, BAD_CAST "preceding"))
10469 ret = AXIS_PRECEDING;
10470 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10471 ret = AXIS_PRECEDING_SIBLING;
10472 break;
10473 case 's':
10474 if (xmlStrEqual(name, BAD_CAST "self"))
10475 ret = AXIS_SELF;
10476 break;
10477 }
10478 return(ret);
10479}
10480
10481/**
10482 * xmlXPathCompStep:
10483 * @ctxt: the XPath Parser context
10484 *
10485 * [4] Step ::= AxisSpecifier NodeTest Predicate*
10486 * | AbbreviatedStep
10487 *
10488 * [12] AbbreviatedStep ::= '.' | '..'
10489 *
10490 * [5] AxisSpecifier ::= AxisName '::'
10491 * | AbbreviatedAxisSpecifier
10492 *
10493 * [13] AbbreviatedAxisSpecifier ::= '@'?
10494 *
10495 * Modified for XPtr range support as:
10496 *
10497 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10498 * | AbbreviatedStep
10499 * | 'range-to' '(' Expr ')' Predicate*
10500 *
10501 * Compile one step in a Location Path
10502 * A location step of . is short for self::node(). This is
10503 * particularly useful in conjunction with //. For example, the
10504 * location path .//para is short for
10505 * self::node()/descendant-or-self::node()/child::para
10506 * and so will select all para descendant elements of the context
10507 * node.
10508 * Similarly, a location step of .. is short for parent::node().
10509 * For example, ../title is short for parent::node()/child::title
10510 * and so will select the title children of the parent of the context
10511 * node.
10512 */
10513static void
10514xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10515#ifdef LIBXML_XPTR_LOCS_ENABLED
10516 int rangeto = 0;
10517 int op2 = -1;
10518#endif
10519
10520 SKIP_BLANKS;
10521 if ((CUR == '.') && (NXT(1) == '.')) {
10522 SKIP(2);
10523 SKIP_BLANKS;
10524 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10525 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10526 } else if (CUR == '.') {
10527 NEXT;
10528 SKIP_BLANKS;
10529 } else {
10530 xmlChar *name = NULL;
10531 xmlChar *prefix = NULL;
10532 xmlXPathTestVal test = (xmlXPathTestVal) 0;
10533 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10534 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10535 int op1;
10536
10537 /*
10538 * The modification needed for XPointer change to the production
10539 */
10540#ifdef LIBXML_XPTR_LOCS_ENABLED
10541 if (ctxt->xptr) {
10542 name = xmlXPathParseNCName(ctxt);
10543 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
10544 op2 = ctxt->comp->last;
10545 xmlFree(name);
10546 SKIP_BLANKS;
10547 if (CUR != '(') {
10548 XP_ERROR(XPATH_EXPR_ERROR);
10549 }
10550 NEXT;
10551 SKIP_BLANKS;
10552
10553 xmlXPathCompileExpr(ctxt, 1);
10554 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
10555 CHECK_ERROR;
10556
10557 SKIP_BLANKS;
10558 if (CUR != ')') {
10559 XP_ERROR(XPATH_EXPR_ERROR);
10560 }
10561 NEXT;
10562 rangeto = 1;
10563 goto eval_predicates;
10564 }
10565 }
10566#endif
10567 if (CUR == '*') {
10568 axis = AXIS_CHILD;
10569 } else {
10570 if (name == NULL)
10571 name = xmlXPathParseNCName(ctxt);
10572 if (name != NULL) {
10573 axis = xmlXPathIsAxisName(name);
10574 if (axis != 0) {
10575 SKIP_BLANKS;
10576 if ((CUR == ':') && (NXT(1) == ':')) {
10577 SKIP(2);
10578 xmlFree(name);
10579 name = NULL;
10580 } else {
10581 /* an element name can conflict with an axis one :-\ */
10582 axis = AXIS_CHILD;
10583 }
10584 } else {
10585 axis = AXIS_CHILD;
10586 }
10587 } else if (CUR == '@') {
10588 NEXT;
10589 axis = AXIS_ATTRIBUTE;
10590 } else {
10591 axis = AXIS_CHILD;
10592 }
10593 }
10594
10595 if (ctxt->error != XPATH_EXPRESSION_OK) {
10596 xmlFree(name);
10597 return;
10598 }
10599
10600 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10601 if (test == 0)
10602 return;
10603
10604 if ((prefix != NULL) && (ctxt->context != NULL) &&
10605 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10606 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10607 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10608 }
10609 }
10610
10611#ifdef LIBXML_XPTR_LOCS_ENABLED
10612eval_predicates:
10613#endif
10614 op1 = ctxt->comp->last;
10615 ctxt->comp->last = -1;
10616
10617 SKIP_BLANKS;
10618 while (CUR == '[') {
10619 xmlXPathCompPredicate(ctxt, 0);
10620 }
10621
10622#ifdef LIBXML_XPTR_LOCS_ENABLED
10623 if (rangeto) {
10624 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10625 } else
10626#endif
10627 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10628 test, type, (void *)prefix, (void *)name) == -1) {
10629 xmlFree(prefix);
10630 xmlFree(name);
10631 }
10632 }
10633}
10634
10635/**
10636 * xmlXPathCompRelativeLocationPath:
10637 * @ctxt: the XPath Parser context
10638 *
10639 * [3] RelativeLocationPath ::= Step
10640 * | RelativeLocationPath '/' Step
10641 * | AbbreviatedRelativeLocationPath
10642 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
10643 *
10644 * Compile a relative location path.
10645 */
10646static void
10647xmlXPathCompRelativeLocationPath
10648(xmlXPathParserContextPtr ctxt) {
10649 SKIP_BLANKS;
10650 if ((CUR == '/') && (NXT(1) == '/')) {
10651 SKIP(2);
10652 SKIP_BLANKS;
10653 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10654 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10655 } else if (CUR == '/') {
10656 NEXT;
10657 SKIP_BLANKS;
10658 }
10659 xmlXPathCompStep(ctxt);
10660 CHECK_ERROR;
10661 SKIP_BLANKS;
10662 while (CUR == '/') {
10663 if ((CUR == '/') && (NXT(1) == '/')) {
10664 SKIP(2);
10665 SKIP_BLANKS;
10666 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10667 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10668 xmlXPathCompStep(ctxt);
10669 } else if (CUR == '/') {
10670 NEXT;
10671 SKIP_BLANKS;
10672 xmlXPathCompStep(ctxt);
10673 }
10674 SKIP_BLANKS;
10675 }
10676}
10677
10678/**
10679 * xmlXPathCompLocationPath:
10680 * @ctxt: the XPath Parser context
10681 *
10682 * [1] LocationPath ::= RelativeLocationPath
10683 * | AbsoluteLocationPath
10684 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
10685 * | AbbreviatedAbsoluteLocationPath
10686 * [10] AbbreviatedAbsoluteLocationPath ::=
10687 * '//' RelativeLocationPath
10688 *
10689 * Compile a location path
10690 *
10691 * // is short for /descendant-or-self::node()/. For example,
10692 * //para is short for /descendant-or-self::node()/child::para and
10693 * so will select any para element in the document (even a para element
10694 * that is a document element will be selected by //para since the
10695 * document element node is a child of the root node); div//para is
10696 * short for div/descendant-or-self::node()/child::para and so will
10697 * select all para descendants of div children.
10698 */
10699static void
10700xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10701 SKIP_BLANKS;
10702 if (CUR != '/') {
10703 xmlXPathCompRelativeLocationPath(ctxt);
10704 } else {
10705 while (CUR == '/') {
10706 if ((CUR == '/') && (NXT(1) == '/')) {
10707 SKIP(2);
10708 SKIP_BLANKS;
10709 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10710 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10711 xmlXPathCompRelativeLocationPath(ctxt);
10712 } else if (CUR == '/') {
10713 NEXT;
10714 SKIP_BLANKS;
10715 if ((CUR != 0 ) &&
10716 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10717 (CUR == '@') || (CUR == '*')))
10718 xmlXPathCompRelativeLocationPath(ctxt);
10719 }
10720 CHECK_ERROR;
10721 }
10722 }
10723}
10724
10725/************************************************************************
10726 * *
10727 * XPath precompiled expression evaluation *
10728 * *
10729 ************************************************************************/
10730
10731static int
10732xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10733
10734/**
10735 * xmlXPathNodeSetFilter:
10736 * @ctxt: the XPath Parser context
10737 * @set: the node set to filter
10738 * @filterOpIndex: the index of the predicate/filter op
10739 * @minPos: minimum position in the filtered set (1-based)
10740 * @maxPos: maximum position in the filtered set (1-based)
10741 * @hasNsNodes: true if the node set may contain namespace nodes
10742 *
10743 * Filter a node set, keeping only nodes for which the predicate expression
10744 * matches. Afterwards, keep only nodes between minPos and maxPos in the
10745 * filtered result.
10746 */
10747static void
10748xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10749 xmlNodeSetPtr set,
10750 int filterOpIndex,
10751 int minPos, int maxPos,
10752 int hasNsNodes)
10753{
10754 xmlXPathContextPtr xpctxt;
10755 xmlNodePtr oldnode;
10756 xmlDocPtr olddoc;
10757 xmlXPathStepOpPtr filterOp;
10758 int oldcs, oldpp;
10759 int i, j, pos;
10760
10761 if ((set == NULL) || (set->nodeNr == 0))
10762 return;
10763
10764 /*
10765 * Check if the node set contains a sufficient number of nodes for
10766 * the requested range.
10767 */
10768 if (set->nodeNr < minPos) {
10769 xmlXPathNodeSetClear(set, hasNsNodes);
10770 return;
10771 }
10772
10773 xpctxt = ctxt->context;
10774 oldnode = xpctxt->node;
10775 olddoc = xpctxt->doc;
10776 oldcs = xpctxt->contextSize;
10777 oldpp = xpctxt->proximityPosition;
10778 filterOp = &ctxt->comp->steps[filterOpIndex];
10779
10780 xpctxt->contextSize = set->nodeNr;
10781
10782 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10783 xmlNodePtr node = set->nodeTab[i];
10784 int res;
10785
10786 xpctxt->node = node;
10787 xpctxt->proximityPosition = i + 1;
10788
10789 /*
10790 * Also set the xpath document in case things like
10791 * key() are evaluated in the predicate.
10792 *
10793 * TODO: Get real doc for namespace nodes.
10794 */
10795 if ((node->type != XML_NAMESPACE_DECL) &&
10796 (node->doc != NULL))
10797 xpctxt->doc = node->doc;
10798
10799 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10800
10801 if (ctxt->error != XPATH_EXPRESSION_OK)
10802 break;
10803 if (res < 0) {
10804 /* Shouldn't happen */
10805 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10806 break;
10807 }
10808
10809 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10810 if (i != j) {
10811 set->nodeTab[j] = node;
10812 set->nodeTab[i] = NULL;
10813 }
10814
10815 j += 1;
10816 } else {
10817 /* Remove the entry from the initial node set. */
10818 set->nodeTab[i] = NULL;
10819 if (node->type == XML_NAMESPACE_DECL)
10820 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10821 }
10822
10823 if (res != 0) {
10824 if (pos == maxPos) {
10825 i += 1;
10826 break;
10827 }
10828
10829 pos += 1;
10830 }
10831 }
10832
10833 /* Free remaining nodes. */
10834 if (hasNsNodes) {
10835 for (; i < set->nodeNr; i++) {
10836 xmlNodePtr node = set->nodeTab[i];
10837 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10838 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10839 }
10840 }
10841
10842 set->nodeNr = j;
10843
10844 /* If too many elements were removed, shrink table to preserve memory. */
10845 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10846 (set->nodeNr < set->nodeMax / 2)) {
10847 xmlNodePtr *tmp;
10848 int nodeMax = set->nodeNr;
10849
10850 if (nodeMax < XML_NODESET_DEFAULT)
10851 nodeMax = XML_NODESET_DEFAULT;
10852 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10853 nodeMax * sizeof(xmlNodePtr));
10854 if (tmp == NULL) {
10855 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
10856 } else {
10857 set->nodeTab = tmp;
10858 set->nodeMax = nodeMax;
10859 }
10860 }
10861
10862 xpctxt->node = oldnode;
10863 xpctxt->doc = olddoc;
10864 xpctxt->contextSize = oldcs;
10865 xpctxt->proximityPosition = oldpp;
10866}
10867
10868#ifdef LIBXML_XPTR_LOCS_ENABLED
10869/**
10870 * xmlXPathLocationSetFilter:
10871 * @ctxt: the XPath Parser context
10872 * @locset: the location set to filter
10873 * @filterOpIndex: the index of the predicate/filter op
10874 * @minPos: minimum position in the filtered set (1-based)
10875 * @maxPos: maximum position in the filtered set (1-based)
10876 *
10877 * Filter a location set, keeping only nodes for which the predicate
10878 * expression matches. Afterwards, keep only nodes between minPos and maxPos
10879 * in the filtered result.
10880 */
10881static void
10882xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
10883 xmlLocationSetPtr locset,
10884 int filterOpIndex,
10885 int minPos, int maxPos)
10886{
10887 xmlXPathContextPtr xpctxt;
10888 xmlNodePtr oldnode;
10889 xmlDocPtr olddoc;
10890 xmlXPathStepOpPtr filterOp;
10891 int oldcs, oldpp;
10892 int i, j, pos;
10893
10894 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
10895 return;
10896
10897 xpctxt = ctxt->context;
10898 oldnode = xpctxt->node;
10899 olddoc = xpctxt->doc;
10900 oldcs = xpctxt->contextSize;
10901 oldpp = xpctxt->proximityPosition;
10902 filterOp = &ctxt->comp->steps[filterOpIndex];
10903
10904 xpctxt->contextSize = locset->locNr;
10905
10906 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
10907 xmlNodePtr contextNode = locset->locTab[i]->user;
10908 int res;
10909
10910 xpctxt->node = contextNode;
10911 xpctxt->proximityPosition = i + 1;
10912
10913 /*
10914 * Also set the xpath document in case things like
10915 * key() are evaluated in the predicate.
10916 *
10917 * TODO: Get real doc for namespace nodes.
10918 */
10919 if ((contextNode->type != XML_NAMESPACE_DECL) &&
10920 (contextNode->doc != NULL))
10921 xpctxt->doc = contextNode->doc;
10922
10923 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10924
10925 if (ctxt->error != XPATH_EXPRESSION_OK)
10926 break;
10927 if (res < 0) {
10928 /* Shouldn't happen */
10929 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10930 break;
10931 }
10932
10933 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10934 if (i != j) {
10935 locset->locTab[j] = locset->locTab[i];
10936 locset->locTab[i] = NULL;
10937 }
10938
10939 j += 1;
10940 } else {
10941 /* Remove the entry from the initial location set. */
10942 xmlXPathFreeObject(locset->locTab[i]);
10943 locset->locTab[i] = NULL;
10944 }
10945
10946 if (res != 0) {
10947 if (pos == maxPos) {
10948 i += 1;
10949 break;
10950 }
10951
10952 pos += 1;
10953 }
10954 }
10955
10956 /* Free remaining nodes. */
10957 for (; i < locset->locNr; i++)
10958 xmlXPathFreeObject(locset->locTab[i]);
10959
10960 locset->locNr = j;
10961
10962 /* If too many elements were removed, shrink table to preserve memory. */
10963 if ((locset->locMax > XML_NODESET_DEFAULT) &&
10964 (locset->locNr < locset->locMax / 2)) {
10965 xmlXPathObjectPtr *tmp;
10966 int locMax = locset->locNr;
10967
10968 if (locMax < XML_NODESET_DEFAULT)
10969 locMax = XML_NODESET_DEFAULT;
10970 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
10971 locMax * sizeof(xmlXPathObjectPtr));
10972 if (tmp == NULL) {
10973 xmlXPathPErrMemory(ctxt, "shrinking locset\n");
10974 } else {
10975 locset->locTab = tmp;
10976 locset->locMax = locMax;
10977 }
10978 }
10979
10980 xpctxt->node = oldnode;
10981 xpctxt->doc = olddoc;
10982 xpctxt->contextSize = oldcs;
10983 xpctxt->proximityPosition = oldpp;
10984}
10985#endif /* LIBXML_XPTR_LOCS_ENABLED */
10986
10987/**
10988 * xmlXPathCompOpEvalPredicate:
10989 * @ctxt: the XPath Parser context
10990 * @op: the predicate op
10991 * @set: the node set to filter
10992 * @minPos: minimum position in the filtered set (1-based)
10993 * @maxPos: maximum position in the filtered set (1-based)
10994 * @hasNsNodes: true if the node set may contain namespace nodes
10995 *
10996 * Filter a node set, keeping only nodes for which the sequence of predicate
10997 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10998 * in the filtered result.
10999 */
11000static void
11001xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11002 xmlXPathStepOpPtr op,
11003 xmlNodeSetPtr set,
11004 int minPos, int maxPos,
11005 int hasNsNodes)
11006{
11007 if (op->ch1 != -1) {
11008 xmlXPathCompExprPtr comp = ctxt->comp;
11009 /*
11010 * Process inner predicates first.
11011 */
11012 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11013 xmlGenericError(xmlGenericErrorContext,
11014 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11015 XP_ERROR(XPATH_INVALID_OPERAND);
11016 }
11017 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11018 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11019 ctxt->context->depth += 1;
11020 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11021 1, set->nodeNr, hasNsNodes);
11022 ctxt->context->depth -= 1;
11023 CHECK_ERROR;
11024 }
11025
11026 if (op->ch2 != -1)
11027 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11028}
11029
11030static int
11031xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11032 xmlXPathStepOpPtr op,
11033 int *maxPos)
11034{
11035
11036 xmlXPathStepOpPtr exprOp;
11037
11038 /*
11039 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11040 */
11041
11042 /*
11043 * If not -1, then ch1 will point to:
11044 * 1) For predicates (XPATH_OP_PREDICATE):
11045 * - an inner predicate operator
11046 * 2) For filters (XPATH_OP_FILTER):
11047 * - an inner filter operator OR
11048 * - an expression selecting the node set.
11049 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11050 */
11051 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11052 return(0);
11053
11054 if (op->ch2 != -1) {
11055 exprOp = &ctxt->comp->steps[op->ch2];
11056 } else
11057 return(0);
11058
11059 if ((exprOp != NULL) &&
11060 (exprOp->op == XPATH_OP_VALUE) &&
11061 (exprOp->value4 != NULL) &&
11062 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11063 {
11064 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11065
11066 /*
11067 * We have a "[n]" predicate here.
11068 * TODO: Unfortunately this simplistic test here is not
11069 * able to detect a position() predicate in compound
11070 * expressions like "[@attr = 'a" and position() = 1],
11071 * and even not the usage of position() in
11072 * "[position() = 1]"; thus - obviously - a position-range,
11073 * like it "[position() < 5]", is also not detected.
11074 * Maybe we could rewrite the AST to ease the optimization.
11075 */
11076
11077 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11078 *maxPos = (int) floatval;
11079 if (floatval == (double) *maxPos)
11080 return(1);
11081 }
11082 }
11083 return(0);
11084}
11085
11086static int
11087xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11088 xmlXPathStepOpPtr op,
11089 xmlNodePtr * first, xmlNodePtr * last,
11090 int toBool)
11091{
11092
11093#define XP_TEST_HIT \
11094 if (hasAxisRange != 0) { \
11095 if (++pos == maxPos) { \
11096 if (addNode(seq, cur) < 0) \
11097 ctxt->error = XPATH_MEMORY_ERROR; \
11098 goto axis_range_end; } \
11099 } else { \
11100 if (addNode(seq, cur) < 0) \
11101 ctxt->error = XPATH_MEMORY_ERROR; \
11102 if (breakOnFirstHit) goto first_hit; }
11103
11104#define XP_TEST_HIT_NS \
11105 if (hasAxisRange != 0) { \
11106 if (++pos == maxPos) { \
11107 hasNsNodes = 1; \
11108 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11109 ctxt->error = XPATH_MEMORY_ERROR; \
11110 goto axis_range_end; } \
11111 } else { \
11112 hasNsNodes = 1; \
11113 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11114 ctxt->error = XPATH_MEMORY_ERROR; \
11115 if (breakOnFirstHit) goto first_hit; }
11116
11117 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11118 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11119 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11120 const xmlChar *prefix = op->value4;
11121 const xmlChar *name = op->value5;
11122 const xmlChar *URI = NULL;
11123
11124 int total = 0, hasNsNodes = 0;
11125 /* The popped object holding the context nodes */
11126 xmlXPathObjectPtr obj;
11127 /* The set of context nodes for the node tests */
11128 xmlNodeSetPtr contextSeq;
11129 int contextIdx;
11130 xmlNodePtr contextNode;
11131 /* The final resulting node set wrt to all context nodes */
11132 xmlNodeSetPtr outSeq;
11133 /*
11134 * The temporary resulting node set wrt 1 context node.
11135 * Used to feed predicate evaluation.
11136 */
11137 xmlNodeSetPtr seq;
11138 xmlNodePtr cur;
11139 /* First predicate operator */
11140 xmlXPathStepOpPtr predOp;
11141 int maxPos; /* The requested position() (when a "[n]" predicate) */
11142 int hasPredicateRange, hasAxisRange, pos;
11143 int breakOnFirstHit;
11144
11145 xmlXPathTraversalFunction next = NULL;
11146 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11147 xmlXPathNodeSetMergeFunction mergeAndClear;
11148 xmlNodePtr oldContextNode;
11149 xmlXPathContextPtr xpctxt = ctxt->context;
11150
11151
11152 CHECK_TYPE0(XPATH_NODESET);
11153 obj = valuePop(ctxt);
11154 /*
11155 * Setup namespaces.
11156 */
11157 if (prefix != NULL) {
11158 URI = xmlXPathNsLookup(xpctxt, prefix);
11159 if (URI == NULL) {
11160 xmlXPathReleaseObject(xpctxt, obj);
11161 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11162 }
11163 }
11164 /*
11165 * Setup axis.
11166 *
11167 * MAYBE FUTURE TODO: merging optimizations:
11168 * - If the nodes to be traversed wrt to the initial nodes and
11169 * the current axis cannot overlap, then we could avoid searching
11170 * for duplicates during the merge.
11171 * But the question is how/when to evaluate if they cannot overlap.
11172 * Example: if we know that for two initial nodes, the one is
11173 * not in the ancestor-or-self axis of the other, then we could safely
11174 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11175 * the descendant-or-self axis.
11176 */
11177 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11178 switch (axis) {
11179 case AXIS_ANCESTOR:
11180 first = NULL;
11181 next = xmlXPathNextAncestor;
11182 break;
11183 case AXIS_ANCESTOR_OR_SELF:
11184 first = NULL;
11185 next = xmlXPathNextAncestorOrSelf;
11186 break;
11187 case AXIS_ATTRIBUTE:
11188 first = NULL;
11189 last = NULL;
11190 next = xmlXPathNextAttribute;
11191 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11192 break;
11193 case AXIS_CHILD:
11194 last = NULL;
11195 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11196 (type == NODE_TYPE_NODE))
11197 {
11198 /*
11199 * Optimization if an element node type is 'element'.
11200 */
11201 next = xmlXPathNextChildElement;
11202 } else
11203 next = xmlXPathNextChild;
11204 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11205 break;
11206 case AXIS_DESCENDANT:
11207 last = NULL;
11208 next = xmlXPathNextDescendant;
11209 break;
11210 case AXIS_DESCENDANT_OR_SELF:
11211 last = NULL;
11212 next = xmlXPathNextDescendantOrSelf;
11213 break;
11214 case AXIS_FOLLOWING:
11215 last = NULL;
11216 next = xmlXPathNextFollowing;
11217 break;
11218 case AXIS_FOLLOWING_SIBLING:
11219 last = NULL;
11220 next = xmlXPathNextFollowingSibling;
11221 break;
11222 case AXIS_NAMESPACE:
11223 first = NULL;
11224 last = NULL;
11225 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11226 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11227 break;
11228 case AXIS_PARENT:
11229 first = NULL;
11230 next = xmlXPathNextParent;
11231 break;
11232 case AXIS_PRECEDING:
11233 first = NULL;
11234 next = xmlXPathNextPrecedingInternal;
11235 break;
11236 case AXIS_PRECEDING_SIBLING:
11237 first = NULL;
11238 next = xmlXPathNextPrecedingSibling;
11239 break;
11240 case AXIS_SELF:
11241 first = NULL;
11242 last = NULL;
11243 next = xmlXPathNextSelf;
11244 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11245 break;
11246 }
11247
11248 if (next == NULL) {
11249 xmlXPathReleaseObject(xpctxt, obj);
11250 return(0);
11251 }
11252 contextSeq = obj->nodesetval;
11253 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
11254 xmlXPathReleaseObject(xpctxt, obj);
11255 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
11256 return(0);
11257 }
11258 /*
11259 * Predicate optimization ---------------------------------------------
11260 * If this step has a last predicate, which contains a position(),
11261 * then we'll optimize (although not exactly "position()", but only
11262 * the short-hand form, i.e., "[n]".
11263 *
11264 * Example - expression "/foo[parent::bar][1]":
11265 *
11266 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
11267 * ROOT -- op->ch1
11268 * PREDICATE -- op->ch2 (predOp)
11269 * PREDICATE -- predOp->ch1 = [parent::bar]
11270 * SORT
11271 * COLLECT 'parent' 'name' 'node' bar
11272 * NODE
11273 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
11274 *
11275 */
11276 maxPos = 0;
11277 predOp = NULL;
11278 hasPredicateRange = 0;
11279 hasAxisRange = 0;
11280 if (op->ch2 != -1) {
11281 /*
11282 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
11283 */
11284 predOp = &ctxt->comp->steps[op->ch2];
11285 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
11286 if (predOp->ch1 != -1) {
11287 /*
11288 * Use the next inner predicate operator.
11289 */
11290 predOp = &ctxt->comp->steps[predOp->ch1];
11291 hasPredicateRange = 1;
11292 } else {
11293 /*
11294 * There's no other predicate than the [n] predicate.
11295 */
11296 predOp = NULL;
11297 hasAxisRange = 1;
11298 }
11299 }
11300 }
11301 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
11302 /*
11303 * Axis traversal -----------------------------------------------------
11304 */
11305 /*
11306 * 2.3 Node Tests
11307 * - For the attribute axis, the principal node type is attribute.
11308 * - For the namespace axis, the principal node type is namespace.
11309 * - For other axes, the principal node type is element.
11310 *
11311 * A node test * is true for any node of the
11312 * principal node type. For example, child::* will
11313 * select all element children of the context node
11314 */
11315 oldContextNode = xpctxt->node;
11316 addNode = xmlXPathNodeSetAddUnique;
11317 outSeq = NULL;
11318 seq = NULL;
11319 contextNode = NULL;
11320 contextIdx = 0;
11321
11322
11323 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
11324 (ctxt->error == XPATH_EXPRESSION_OK)) {
11325 xpctxt->node = contextSeq->nodeTab[contextIdx++];
11326
11327 if (seq == NULL) {
11328 seq = xmlXPathNodeSetCreate(NULL);
11329 if (seq == NULL) {
11330 /* TODO: Propagate memory error. */
11331 total = 0;
11332 goto error;
11333 }
11334 }
11335 /*
11336 * Traverse the axis and test the nodes.
11337 */
11338 pos = 0;
11339 cur = NULL;
11340 hasNsNodes = 0;
11341 do {
11342 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11343 goto error;
11344
11345 cur = next(ctxt, cur);
11346 if (cur == NULL)
11347 break;
11348
11349 /*
11350 * QUESTION TODO: What does the "first" and "last" stuff do?
11351 */
11352 if ((first != NULL) && (*first != NULL)) {
11353 if (*first == cur)
11354 break;
11355 if (((total % 256) == 0) &&
11356#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11357 (xmlXPathCmpNodesExt(*first, cur) >= 0))
11358#else
11359 (xmlXPathCmpNodes(*first, cur) >= 0))
11360#endif
11361 {
11362 break;
11363 }
11364 }
11365 if ((last != NULL) && (*last != NULL)) {
11366 if (*last == cur)
11367 break;
11368 if (((total % 256) == 0) &&
11369#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11370 (xmlXPathCmpNodesExt(cur, *last) >= 0))
11371#else
11372 (xmlXPathCmpNodes(cur, *last) >= 0))
11373#endif
11374 {
11375 break;
11376 }
11377 }
11378
11379 total++;
11380
11381 switch (test) {
11382 case NODE_TEST_NONE:
11383 total = 0;
11384 STRANGE
11385 goto error;
11386 case NODE_TEST_TYPE:
11387 if (type == NODE_TYPE_NODE) {
11388 switch (cur->type) {
11389 case XML_DOCUMENT_NODE:
11390 case XML_HTML_DOCUMENT_NODE:
11391 case XML_ELEMENT_NODE:
11392 case XML_ATTRIBUTE_NODE:
11393 case XML_PI_NODE:
11394 case XML_COMMENT_NODE:
11395 case XML_CDATA_SECTION_NODE:
11396 case XML_TEXT_NODE:
11397 XP_TEST_HIT
11398 break;
11399 case XML_NAMESPACE_DECL: {
11400 if (axis == AXIS_NAMESPACE) {
11401 XP_TEST_HIT_NS
11402 } else {
11403 hasNsNodes = 1;
11404 XP_TEST_HIT
11405 }
11406 break;
11407 }
11408 default:
11409 break;
11410 }
11411 } else if (cur->type == (xmlElementType) type) {
11412 if (cur->type == XML_NAMESPACE_DECL)
11413 XP_TEST_HIT_NS
11414 else
11415 XP_TEST_HIT
11416 } else if ((type == NODE_TYPE_TEXT) &&
11417 (cur->type == XML_CDATA_SECTION_NODE))
11418 {
11419 XP_TEST_HIT
11420 }
11421 break;
11422 case NODE_TEST_PI:
11423 if ((cur->type == XML_PI_NODE) &&
11424 ((name == NULL) || xmlStrEqual(name, cur->name)))
11425 {
11426 XP_TEST_HIT
11427 }
11428 break;
11429 case NODE_TEST_ALL:
11430 if (axis == AXIS_ATTRIBUTE) {
11431 if (cur->type == XML_ATTRIBUTE_NODE)
11432 {
11433 if (prefix == NULL)
11434 {
11435 XP_TEST_HIT
11436 } else if ((cur->ns != NULL) &&
11437 (xmlStrEqual(URI, cur->ns->href)))
11438 {
11439 XP_TEST_HIT
11440 }
11441 }
11442 } else if (axis == AXIS_NAMESPACE) {
11443 if (cur->type == XML_NAMESPACE_DECL)
11444 {
11445 XP_TEST_HIT_NS
11446 }
11447 } else {
11448 if (cur->type == XML_ELEMENT_NODE) {
11449 if (prefix == NULL)
11450 {
11451 XP_TEST_HIT
11452
11453 } else if ((cur->ns != NULL) &&
11454 (xmlStrEqual(URI, cur->ns->href)))
11455 {
11456 XP_TEST_HIT
11457 }
11458 }
11459 }
11460 break;
11461 case NODE_TEST_NS:{
11462 TODO;
11463 break;
11464 }
11465 case NODE_TEST_NAME:
11466 if (axis == AXIS_ATTRIBUTE) {
11467 if (cur->type != XML_ATTRIBUTE_NODE)
11468 break;
11469 } else if (axis == AXIS_NAMESPACE) {
11470 if (cur->type != XML_NAMESPACE_DECL)
11471 break;
11472 } else {
11473 if (cur->type != XML_ELEMENT_NODE)
11474 break;
11475 }
11476 switch (cur->type) {
11477 case XML_ELEMENT_NODE:
11478 if (xmlStrEqual(name, cur->name)) {
11479 if (prefix == NULL) {
11480 if (cur->ns == NULL)
11481 {
11482 XP_TEST_HIT
11483 }
11484 } else {
11485 if ((cur->ns != NULL) &&
11486 (xmlStrEqual(URI, cur->ns->href)))
11487 {
11488 XP_TEST_HIT
11489 }
11490 }
11491 }
11492 break;
11493 case XML_ATTRIBUTE_NODE:{
11494 xmlAttrPtr attr = (xmlAttrPtr) cur;
11495
11496 if (xmlStrEqual(name, attr->name)) {
11497 if (prefix == NULL) {
11498 if ((attr->ns == NULL) ||
11499 (attr->ns->prefix == NULL))
11500 {
11501 XP_TEST_HIT
11502 }
11503 } else {
11504 if ((attr->ns != NULL) &&
11505 (xmlStrEqual(URI,
11506 attr->ns->href)))
11507 {
11508 XP_TEST_HIT
11509 }
11510 }
11511 }
11512 break;
11513 }
11514 case XML_NAMESPACE_DECL:
11515 if (cur->type == XML_NAMESPACE_DECL) {
11516 xmlNsPtr ns = (xmlNsPtr) cur;
11517
11518 if ((ns->prefix != NULL) && (name != NULL)
11519 && (xmlStrEqual(ns->prefix, name)))
11520 {
11521 XP_TEST_HIT_NS
11522 }
11523 }
11524 break;
11525 default:
11526 break;
11527 }
11528 break;
11529 } /* switch(test) */
11530 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
11531
11532 goto apply_predicates;
11533
11534axis_range_end: /* ----------------------------------------------------- */
11535 /*
11536 * We have a "/foo[n]", and position() = n was reached.
11537 * Note that we can have as well "/foo/::parent::foo[1]", so
11538 * a duplicate-aware merge is still needed.
11539 * Merge with the result.
11540 */
11541 if (outSeq == NULL) {
11542 outSeq = seq;
11543 seq = NULL;
11544 } else
11545 /* TODO: Check memory error. */
11546 outSeq = mergeAndClear(outSeq, seq);
11547 /*
11548 * Break if only a true/false result was requested.
11549 */
11550 if (toBool)
11551 break;
11552 continue;
11553
11554first_hit: /* ---------------------------------------------------------- */
11555 /*
11556 * Break if only a true/false result was requested and
11557 * no predicates existed and a node test succeeded.
11558 */
11559 if (outSeq == NULL) {
11560 outSeq = seq;
11561 seq = NULL;
11562 } else
11563 /* TODO: Check memory error. */
11564 outSeq = mergeAndClear(outSeq, seq);
11565 break;
11566
11567apply_predicates: /* --------------------------------------------------- */
11568 if (ctxt->error != XPATH_EXPRESSION_OK)
11569 goto error;
11570
11571 /*
11572 * Apply predicates.
11573 */
11574 if ((predOp != NULL) && (seq->nodeNr > 0)) {
11575 /*
11576 * E.g. when we have a "/foo[some expression][n]".
11577 */
11578 /*
11579 * QUESTION TODO: The old predicate evaluation took into
11580 * account location-sets.
11581 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
11582 * Do we expect such a set here?
11583 * All what I learned now from the evaluation semantics
11584 * does not indicate that a location-set will be processed
11585 * here, so this looks OK.
11586 */
11587 /*
11588 * Iterate over all predicates, starting with the outermost
11589 * predicate.
11590 * TODO: Problem: we cannot execute the inner predicates first
11591 * since we cannot go back *up* the operator tree!
11592 * Options we have:
11593 * 1) Use of recursive functions (like is it currently done
11594 * via xmlXPathCompOpEval())
11595 * 2) Add a predicate evaluation information stack to the
11596 * context struct
11597 * 3) Change the way the operators are linked; we need a
11598 * "parent" field on xmlXPathStepOp
11599 *
11600 * For the moment, I'll try to solve this with a recursive
11601 * function: xmlXPathCompOpEvalPredicate().
11602 */
11603 if (hasPredicateRange != 0)
11604 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
11605 hasNsNodes);
11606 else
11607 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
11608 hasNsNodes);
11609
11610 if (ctxt->error != XPATH_EXPRESSION_OK) {
11611 total = 0;
11612 goto error;
11613 }
11614 }
11615
11616 if (seq->nodeNr > 0) {
11617 /*
11618 * Add to result set.
11619 */
11620 if (outSeq == NULL) {
11621 outSeq = seq;
11622 seq = NULL;
11623 } else {
11624 /* TODO: Check memory error. */
11625 outSeq = mergeAndClear(outSeq, seq);
11626 }
11627
11628 if (toBool)
11629 break;
11630 }
11631 }
11632
11633error:
11634 if ((obj->boolval) && (obj->user != NULL)) {
11635 /*
11636 * QUESTION TODO: What does this do and why?
11637 * TODO: Do we have to do this also for the "error"
11638 * cleanup further down?
11639 */
11640 ctxt->value->boolval = 1;
11641 ctxt->value->user = obj->user;
11642 obj->user = NULL;
11643 obj->boolval = 0;
11644 }
11645 xmlXPathReleaseObject(xpctxt, obj);
11646
11647 /*
11648 * Ensure we return at least an empty set.
11649 */
11650 if (outSeq == NULL) {
11651 if ((seq != NULL) && (seq->nodeNr == 0))
11652 outSeq = seq;
11653 else
11654 /* TODO: Check memory error. */
11655 outSeq = xmlXPathNodeSetCreate(NULL);
11656 }
11657 if ((seq != NULL) && (seq != outSeq)) {
11658 xmlXPathFreeNodeSet(seq);
11659 }
11660 /*
11661 * Hand over the result. Better to push the set also in
11662 * case of errors.
11663 */
11664 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
11665 /*
11666 * Reset the context node.
11667 */
11668 xpctxt->node = oldContextNode;
11669 /*
11670 * When traversing the namespace axis in "toBool" mode, it's
11671 * possible that tmpNsList wasn't freed.
11672 */
11673 if (xpctxt->tmpNsList != NULL) {
11674 xmlFree(xpctxt->tmpNsList);
11675 xpctxt->tmpNsList = NULL;
11676 }
11677
11678 return(total);
11679}
11680
11681static int
11682xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11683 xmlXPathStepOpPtr op, xmlNodePtr * first);
11684
11685/**
11686 * xmlXPathCompOpEvalFirst:
11687 * @ctxt: the XPath parser context with the compiled expression
11688 * @op: an XPath compiled operation
11689 * @first: the first elem found so far
11690 *
11691 * Evaluate the Precompiled XPath operation searching only the first
11692 * element in document order
11693 *
11694 * Returns the number of examined objects.
11695 */
11696static int
11697xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11698 xmlXPathStepOpPtr op, xmlNodePtr * first)
11699{
11700 int total = 0, cur;
11701 xmlXPathCompExprPtr comp;
11702 xmlXPathObjectPtr arg1, arg2;
11703
11704 CHECK_ERROR0;
11705 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11706 return(0);
11707 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11708 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11709 ctxt->context->depth += 1;
11710 comp = ctxt->comp;
11711 switch (op->op) {
11712 case XPATH_OP_END:
11713 break;
11714 case XPATH_OP_UNION:
11715 total =
11716 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11717 first);
11718 CHECK_ERROR0;
11719 if ((ctxt->value != NULL)
11720 && (ctxt->value->type == XPATH_NODESET)
11721 && (ctxt->value->nodesetval != NULL)
11722 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11723 /*
11724 * limit tree traversing to first node in the result
11725 */
11726 /*
11727 * OPTIMIZE TODO: This implicitly sorts
11728 * the result, even if not needed. E.g. if the argument
11729 * of the count() function, no sorting is needed.
11730 * OPTIMIZE TODO: How do we know if the node-list wasn't
11731 * already sorted?
11732 */
11733 if (ctxt->value->nodesetval->nodeNr > 1)
11734 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11735 *first = ctxt->value->nodesetval->nodeTab[0];
11736 }
11737 cur =
11738 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11739 first);
11740 CHECK_ERROR0;
11741
11742 arg2 = valuePop(ctxt);
11743 arg1 = valuePop(ctxt);
11744 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11745 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11746 xmlXPathReleaseObject(ctxt->context, arg1);
11747 xmlXPathReleaseObject(ctxt->context, arg2);
11748 XP_ERROR0(XPATH_INVALID_TYPE);
11749 }
11750 if ((ctxt->context->opLimit != 0) &&
11751 (((arg1->nodesetval != NULL) &&
11752 (xmlXPathCheckOpLimit(ctxt,
11753 arg1->nodesetval->nodeNr) < 0)) ||
11754 ((arg2->nodesetval != NULL) &&
11755 (xmlXPathCheckOpLimit(ctxt,
11756 arg2->nodesetval->nodeNr) < 0)))) {
11757 xmlXPathReleaseObject(ctxt->context, arg1);
11758 xmlXPathReleaseObject(ctxt->context, arg2);
11759 break;
11760 }
11761
11762 /* TODO: Check memory error. */
11763 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11764 arg2->nodesetval);
11765 valuePush(ctxt, arg1);
11766 xmlXPathReleaseObject(ctxt->context, arg2);
11767 /* optimizer */
11768 if (total > cur)
11769 xmlXPathCompSwap(op);
11770 total += cur;
11771 break;
11772 case XPATH_OP_ROOT:
11773 xmlXPathRoot(ctxt);
11774 break;
11775 case XPATH_OP_NODE:
11776 if (op->ch1 != -1)
11777 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11778 CHECK_ERROR0;
11779 if (op->ch2 != -1)
11780 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11781 CHECK_ERROR0;
11782 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
11783 ctxt->context->node));
11784 break;
11785 case XPATH_OP_COLLECT:{
11786 if (op->ch1 == -1)
11787 break;
11788
11789 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11790 CHECK_ERROR0;
11791
11792 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11793 break;
11794 }
11795 case XPATH_OP_VALUE:
11796 valuePush(ctxt,
11797 xmlXPathCacheObjectCopy(ctxt->context,
11798 (xmlXPathObjectPtr) op->value4));
11799 break;
11800 case XPATH_OP_SORT:
11801 if (op->ch1 != -1)
11802 total +=
11803 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11804 first);
11805 CHECK_ERROR0;
11806 if ((ctxt->value != NULL)
11807 && (ctxt->value->type == XPATH_NODESET)
11808 && (ctxt->value->nodesetval != NULL)
11809 && (ctxt->value->nodesetval->nodeNr > 1))
11810 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11811 break;
11812#ifdef XP_OPTIMIZED_FILTER_FIRST
11813 case XPATH_OP_FILTER:
11814 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11815 break;
11816#endif
11817 default:
11818 total += xmlXPathCompOpEval(ctxt, op);
11819 break;
11820 }
11821
11822 ctxt->context->depth -= 1;
11823 return(total);
11824}
11825
11826/**
11827 * xmlXPathCompOpEvalLast:
11828 * @ctxt: the XPath parser context with the compiled expression
11829 * @op: an XPath compiled operation
11830 * @last: the last elem found so far
11831 *
11832 * Evaluate the Precompiled XPath operation searching only the last
11833 * element in document order
11834 *
11835 * Returns the number of nodes traversed
11836 */
11837static int
11838xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11839 xmlNodePtr * last)
11840{
11841 int total = 0, cur;
11842 xmlXPathCompExprPtr comp;
11843 xmlXPathObjectPtr arg1, arg2;
11844
11845 CHECK_ERROR0;
11846 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11847 return(0);
11848 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11849 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11850 ctxt->context->depth += 1;
11851 comp = ctxt->comp;
11852 switch (op->op) {
11853 case XPATH_OP_END:
11854 break;
11855 case XPATH_OP_UNION:
11856 total =
11857 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11858 CHECK_ERROR0;
11859 if ((ctxt->value != NULL)
11860 && (ctxt->value->type == XPATH_NODESET)
11861 && (ctxt->value->nodesetval != NULL)
11862 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11863 /*
11864 * limit tree traversing to first node in the result
11865 */
11866 if (ctxt->value->nodesetval->nodeNr > 1)
11867 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11868 *last =
11869 ctxt->value->nodesetval->nodeTab[ctxt->value->
11870 nodesetval->nodeNr -
11871 1];
11872 }
11873 cur =
11874 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11875 CHECK_ERROR0;
11876 if ((ctxt->value != NULL)
11877 && (ctxt->value->type == XPATH_NODESET)
11878 && (ctxt->value->nodesetval != NULL)
11879 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11880 }
11881
11882 arg2 = valuePop(ctxt);
11883 arg1 = valuePop(ctxt);
11884 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11885 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11886 xmlXPathReleaseObject(ctxt->context, arg1);
11887 xmlXPathReleaseObject(ctxt->context, arg2);
11888 XP_ERROR0(XPATH_INVALID_TYPE);
11889 }
11890 if ((ctxt->context->opLimit != 0) &&
11891 (((arg1->nodesetval != NULL) &&
11892 (xmlXPathCheckOpLimit(ctxt,
11893 arg1->nodesetval->nodeNr) < 0)) ||
11894 ((arg2->nodesetval != NULL) &&
11895 (xmlXPathCheckOpLimit(ctxt,
11896 arg2->nodesetval->nodeNr) < 0)))) {
11897 xmlXPathReleaseObject(ctxt->context, arg1);
11898 xmlXPathReleaseObject(ctxt->context, arg2);
11899 break;
11900 }
11901
11902 /* TODO: Check memory error. */
11903 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11904 arg2->nodesetval);
11905 valuePush(ctxt, arg1);
11906 xmlXPathReleaseObject(ctxt->context, arg2);
11907 /* optimizer */
11908 if (total > cur)
11909 xmlXPathCompSwap(op);
11910 total += cur;
11911 break;
11912 case XPATH_OP_ROOT:
11913 xmlXPathRoot(ctxt);
11914 break;
11915 case XPATH_OP_NODE:
11916 if (op->ch1 != -1)
11917 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11918 CHECK_ERROR0;
11919 if (op->ch2 != -1)
11920 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11921 CHECK_ERROR0;
11922 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
11923 ctxt->context->node));
11924 break;
11925 case XPATH_OP_COLLECT:{
11926 if (op->ch1 == -1)
11927 break;
11928
11929 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11930 CHECK_ERROR0;
11931
11932 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11933 break;
11934 }
11935 case XPATH_OP_VALUE:
11936 valuePush(ctxt,
11937 xmlXPathCacheObjectCopy(ctxt->context,
11938 (xmlXPathObjectPtr) op->value4));
11939 break;
11940 case XPATH_OP_SORT:
11941 if (op->ch1 != -1)
11942 total +=
11943 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11944 last);
11945 CHECK_ERROR0;
11946 if ((ctxt->value != NULL)
11947 && (ctxt->value->type == XPATH_NODESET)
11948 && (ctxt->value->nodesetval != NULL)
11949 && (ctxt->value->nodesetval->nodeNr > 1))
11950 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11951 break;
11952 default:
11953 total += xmlXPathCompOpEval(ctxt, op);
11954 break;
11955 }
11956
11957 ctxt->context->depth -= 1;
11958 return (total);
11959}
11960
11961#ifdef XP_OPTIMIZED_FILTER_FIRST
11962static int
11963xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11964 xmlXPathStepOpPtr op, xmlNodePtr * first)
11965{
11966 int total = 0;
11967 xmlXPathCompExprPtr comp;
11968 xmlXPathObjectPtr obj;
11969 xmlNodeSetPtr set;
11970
11971 CHECK_ERROR0;
11972 comp = ctxt->comp;
11973 /*
11974 * Optimization for ()[last()] selection i.e. the last elem
11975 */
11976 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11977 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11978 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11979 int f = comp->steps[op->ch2].ch1;
11980
11981 if ((f != -1) &&
11982 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11983 (comp->steps[f].value5 == NULL) &&
11984 (comp->steps[f].value == 0) &&
11985 (comp->steps[f].value4 != NULL) &&
11986 (xmlStrEqual
11987 (comp->steps[f].value4, BAD_CAST "last"))) {
11988 xmlNodePtr last = NULL;
11989
11990 total +=
11991 xmlXPathCompOpEvalLast(ctxt,
11992 &comp->steps[op->ch1],
11993 &last);
11994 CHECK_ERROR0;
11995 /*
11996 * The nodeset should be in document order,
11997 * Keep only the last value
11998 */
11999 if ((ctxt->value != NULL) &&
12000 (ctxt->value->type == XPATH_NODESET) &&
12001 (ctxt->value->nodesetval != NULL) &&
12002 (ctxt->value->nodesetval->nodeTab != NULL) &&
12003 (ctxt->value->nodesetval->nodeNr > 1)) {
12004 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12005 *first = *(ctxt->value->nodesetval->nodeTab);
12006 }
12007 return (total);
12008 }
12009 }
12010
12011 if (op->ch1 != -1)
12012 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12013 CHECK_ERROR0;
12014 if (op->ch2 == -1)
12015 return (total);
12016 if (ctxt->value == NULL)
12017 return (total);
12018
12019#ifdef LIBXML_XPTR_LOCS_ENABLED
12020 /*
12021 * Hum are we filtering the result of an XPointer expression
12022 */
12023 if (ctxt->value->type == XPATH_LOCATIONSET) {
12024 xmlLocationSetPtr locset = ctxt->value->user;
12025
12026 if (locset != NULL) {
12027 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12028 if (locset->locNr > 0)
12029 *first = (xmlNodePtr) locset->locTab[0]->user;
12030 }
12031
12032 return (total);
12033 }
12034#endif /* LIBXML_XPTR_LOCS_ENABLED */
12035
12036 /*
12037 * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12038 * the stack. We have to temporarily remove the nodeset object from the
12039 * stack to avoid freeing it prematurely.
12040 */
12041 CHECK_TYPE0(XPATH_NODESET);
12042 obj = valuePop(ctxt);
12043 set = obj->nodesetval;
12044 if (set != NULL) {
12045 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12046 if (set->nodeNr > 0)
12047 *first = set->nodeTab[0];
12048 }
12049 valuePush(ctxt, obj);
12050
12051 return (total);
12052}
12053#endif /* XP_OPTIMIZED_FILTER_FIRST */
12054
12055/**
12056 * xmlXPathCompOpEval:
12057 * @ctxt: the XPath parser context with the compiled expression
12058 * @op: an XPath compiled operation
12059 *
12060 * Evaluate the Precompiled XPath operation
12061 * Returns the number of nodes traversed
12062 */
12063static int
12064xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12065{
12066 int total = 0;
12067 int equal, ret;
12068 xmlXPathCompExprPtr comp;
12069 xmlXPathObjectPtr arg1, arg2;
12070
12071 CHECK_ERROR0;
12072 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12073 return(0);
12074 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12075 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12076 ctxt->context->depth += 1;
12077 comp = ctxt->comp;
12078 switch (op->op) {
12079 case XPATH_OP_END:
12080 break;
12081 case XPATH_OP_AND:
12082 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12083 CHECK_ERROR0;
12084 xmlXPathBooleanFunction(ctxt, 1);
12085 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12086 break;
12087 arg2 = valuePop(ctxt);
12088 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12089 if (ctxt->error) {
12090 xmlXPathFreeObject(arg2);
12091 break;
12092 }
12093 xmlXPathBooleanFunction(ctxt, 1);
12094 if (ctxt->value != NULL)
12095 ctxt->value->boolval &= arg2->boolval;
12096 xmlXPathReleaseObject(ctxt->context, arg2);
12097 break;
12098 case XPATH_OP_OR:
12099 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12100 CHECK_ERROR0;
12101 xmlXPathBooleanFunction(ctxt, 1);
12102 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12103 break;
12104 arg2 = valuePop(ctxt);
12105 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12106 if (ctxt->error) {
12107 xmlXPathFreeObject(arg2);
12108 break;
12109 }
12110 xmlXPathBooleanFunction(ctxt, 1);
12111 if (ctxt->value != NULL)
12112 ctxt->value->boolval |= arg2->boolval;
12113 xmlXPathReleaseObject(ctxt->context, arg2);
12114 break;
12115 case XPATH_OP_EQUAL:
12116 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12117 CHECK_ERROR0;
12118 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12119 CHECK_ERROR0;
12120 if (op->value)
12121 equal = xmlXPathEqualValues(ctxt);
12122 else
12123 equal = xmlXPathNotEqualValues(ctxt);
12124 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12125 break;
12126 case XPATH_OP_CMP:
12127 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12128 CHECK_ERROR0;
12129 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12130 CHECK_ERROR0;
12131 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
12132 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
12133 break;
12134 case XPATH_OP_PLUS:
12135 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12136 CHECK_ERROR0;
12137 if (op->ch2 != -1) {
12138 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12139 }
12140 CHECK_ERROR0;
12141 if (op->value == 0)
12142 xmlXPathSubValues(ctxt);
12143 else if (op->value == 1)
12144 xmlXPathAddValues(ctxt);
12145 else if (op->value == 2)
12146 xmlXPathValueFlipSign(ctxt);
12147 else if (op->value == 3) {
12148 CAST_TO_NUMBER;
12149 CHECK_TYPE0(XPATH_NUMBER);
12150 }
12151 break;
12152 case XPATH_OP_MULT:
12153 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12154 CHECK_ERROR0;
12155 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12156 CHECK_ERROR0;
12157 if (op->value == 0)
12158 xmlXPathMultValues(ctxt);
12159 else if (op->value == 1)
12160 xmlXPathDivValues(ctxt);
12161 else if (op->value == 2)
12162 xmlXPathModValues(ctxt);
12163 break;
12164 case XPATH_OP_UNION:
12165 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12166 CHECK_ERROR0;
12167 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12168 CHECK_ERROR0;
12169
12170 arg2 = valuePop(ctxt);
12171 arg1 = valuePop(ctxt);
12172 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12173 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12174 xmlXPathReleaseObject(ctxt->context, arg1);
12175 xmlXPathReleaseObject(ctxt->context, arg2);
12176 XP_ERROR0(XPATH_INVALID_TYPE);
12177 }
12178 if ((ctxt->context->opLimit != 0) &&
12179 (((arg1->nodesetval != NULL) &&
12180 (xmlXPathCheckOpLimit(ctxt,
12181 arg1->nodesetval->nodeNr) < 0)) ||
12182 ((arg2->nodesetval != NULL) &&
12183 (xmlXPathCheckOpLimit(ctxt,
12184 arg2->nodesetval->nodeNr) < 0)))) {
12185 xmlXPathReleaseObject(ctxt->context, arg1);
12186 xmlXPathReleaseObject(ctxt->context, arg2);
12187 break;
12188 }
12189
12190 if ((arg1->nodesetval == NULL) ||
12191 ((arg2->nodesetval != NULL) &&
12192 (arg2->nodesetval->nodeNr != 0)))
12193 {
12194 /* TODO: Check memory error. */
12195 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12196 arg2->nodesetval);
12197 }
12198
12199 valuePush(ctxt, arg1);
12200 xmlXPathReleaseObject(ctxt->context, arg2);
12201 break;
12202 case XPATH_OP_ROOT:
12203 xmlXPathRoot(ctxt);
12204 break;
12205 case XPATH_OP_NODE:
12206 if (op->ch1 != -1)
12207 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12208 CHECK_ERROR0;
12209 if (op->ch2 != -1)
12210 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12211 CHECK_ERROR0;
12212 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12213 ctxt->context->node));
12214 break;
12215 case XPATH_OP_COLLECT:{
12216 if (op->ch1 == -1)
12217 break;
12218
12219 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12220 CHECK_ERROR0;
12221
12222 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
12223 break;
12224 }
12225 case XPATH_OP_VALUE:
12226 valuePush(ctxt,
12227 xmlXPathCacheObjectCopy(ctxt->context,
12228 (xmlXPathObjectPtr) op->value4));
12229 break;
12230 case XPATH_OP_VARIABLE:{
12231 xmlXPathObjectPtr val;
12232
12233 if (op->ch1 != -1)
12234 total +=
12235 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12236 if (op->value5 == NULL) {
12237 val = xmlXPathVariableLookup(ctxt->context, op->value4);
12238 if (val == NULL)
12239 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
12240 valuePush(ctxt, val);
12241 } else {
12242 const xmlChar *URI;
12243
12244 URI = xmlXPathNsLookup(ctxt->context, op->value5);
12245 if (URI == NULL) {
12246 xmlGenericError(xmlGenericErrorContext,
12247 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
12248 (char *) op->value4, (char *)op->value5);
12249 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
12250 break;
12251 }
12252 val = xmlXPathVariableLookupNS(ctxt->context,
12253 op->value4, URI);
12254 if (val == NULL)
12255 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
12256 valuePush(ctxt, val);
12257 }
12258 break;
12259 }
12260 case XPATH_OP_FUNCTION:{
12261 xmlXPathFunction func;
12262 const xmlChar *oldFunc, *oldFuncURI;
12263 int i;
12264 int frame;
12265
12266 frame = ctxt->valueNr;
12267 if (op->ch1 != -1) {
12268 total +=
12269 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12270 if (ctxt->error != XPATH_EXPRESSION_OK)
12271 break;
12272 }
12273 if (ctxt->valueNr < frame + op->value) {
12274 xmlGenericError(xmlGenericErrorContext,
12275 "xmlXPathCompOpEval: parameter error\n");
12276 ctxt->error = XPATH_INVALID_OPERAND;
12277 break;
12278 }
12279 for (i = 0; i < op->value; i++) {
12280 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
12281 xmlGenericError(xmlGenericErrorContext,
12282 "xmlXPathCompOpEval: parameter error\n");
12283 ctxt->error = XPATH_INVALID_OPERAND;
12284 break;
12285 }
12286 }
12287 if (op->cache != NULL)
12288 func = op->cache;
12289 else {
12290 const xmlChar *URI = NULL;
12291
12292 if (op->value5 == NULL)
12293 func =
12294 xmlXPathFunctionLookup(ctxt->context,
12295 op->value4);
12296 else {
12297 URI = xmlXPathNsLookup(ctxt->context, op->value5);
12298 if (URI == NULL) {
12299 xmlGenericError(xmlGenericErrorContext,
12300 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
12301 (char *)op->value4, (char *)op->value5);
12302 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
12303 break;
12304 }
12305 func = xmlXPathFunctionLookupNS(ctxt->context,
12306 op->value4, URI);
12307 }
12308 if (func == NULL) {
12309 xmlGenericError(xmlGenericErrorContext,
12310 "xmlXPathCompOpEval: function %s not found\n",
12311 (char *)op->value4);
12312 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
12313 }
12314 op->cache = func;
12315 op->cacheURI = (void *) URI;
12316 }
12317 oldFunc = ctxt->context->function;
12318 oldFuncURI = ctxt->context->functionURI;
12319 ctxt->context->function = op->value4;
12320 ctxt->context->functionURI = op->cacheURI;
12321 func(ctxt, op->value);
12322 ctxt->context->function = oldFunc;
12323 ctxt->context->functionURI = oldFuncURI;
12324 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
12325 (ctxt->valueNr != frame + 1))
12326 XP_ERROR0(XPATH_STACK_ERROR);
12327 break;
12328 }
12329 case XPATH_OP_ARG:
12330 if (op->ch1 != -1) {
12331 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12332 CHECK_ERROR0;
12333 }
12334 if (op->ch2 != -1) {
12335 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12336 CHECK_ERROR0;
12337 }
12338 break;
12339 case XPATH_OP_PREDICATE:
12340 case XPATH_OP_FILTER:{
12341 xmlXPathObjectPtr obj;
12342 xmlNodeSetPtr set;
12343
12344 /*
12345 * Optimization for ()[1] selection i.e. the first elem
12346 */
12347 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12348#ifdef XP_OPTIMIZED_FILTER_FIRST
12349 /*
12350 * FILTER TODO: Can we assume that the inner processing
12351 * will result in an ordered list if we have an
12352 * XPATH_OP_FILTER?
12353 * What about an additional field or flag on
12354 * xmlXPathObject like @sorted ? This way we wouldn't need
12355 * to assume anything, so it would be more robust and
12356 * easier to optimize.
12357 */
12358 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
12359 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
12360#else
12361 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12362#endif
12363 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
12364 xmlXPathObjectPtr val;
12365
12366 val = comp->steps[op->ch2].value4;
12367 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
12368 (val->floatval == 1.0)) {
12369 xmlNodePtr first = NULL;
12370
12371 total +=
12372 xmlXPathCompOpEvalFirst(ctxt,
12373 &comp->steps[op->ch1],
12374 &first);
12375 CHECK_ERROR0;
12376 /*
12377 * The nodeset should be in document order,
12378 * Keep only the first value
12379 */
12380 if ((ctxt->value != NULL) &&
12381 (ctxt->value->type == XPATH_NODESET) &&
12382 (ctxt->value->nodesetval != NULL) &&
12383 (ctxt->value->nodesetval->nodeNr > 1))
12384 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
12385 1, 1);
12386 break;
12387 }
12388 }
12389 /*
12390 * Optimization for ()[last()] selection i.e. the last elem
12391 */
12392 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12393 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12394 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12395 int f = comp->steps[op->ch2].ch1;
12396
12397 if ((f != -1) &&
12398 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12399 (comp->steps[f].value5 == NULL) &&
12400 (comp->steps[f].value == 0) &&
12401 (comp->steps[f].value4 != NULL) &&
12402 (xmlStrEqual
12403 (comp->steps[f].value4, BAD_CAST "last"))) {
12404 xmlNodePtr last = NULL;
12405
12406 total +=
12407 xmlXPathCompOpEvalLast(ctxt,
12408 &comp->steps[op->ch1],
12409 &last);
12410 CHECK_ERROR0;
12411 /*
12412 * The nodeset should be in document order,
12413 * Keep only the last value
12414 */
12415 if ((ctxt->value != NULL) &&
12416 (ctxt->value->type == XPATH_NODESET) &&
12417 (ctxt->value->nodesetval != NULL) &&
12418 (ctxt->value->nodesetval->nodeTab != NULL) &&
12419 (ctxt->value->nodesetval->nodeNr > 1))
12420 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12421 break;
12422 }
12423 }
12424 /*
12425 * Process inner predicates first.
12426 * Example "index[parent::book][1]":
12427 * ...
12428 * PREDICATE <-- we are here "[1]"
12429 * PREDICATE <-- process "[parent::book]" first
12430 * SORT
12431 * COLLECT 'parent' 'name' 'node' book
12432 * NODE
12433 * ELEM Object is a number : 1
12434 */
12435 if (op->ch1 != -1)
12436 total +=
12437 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12438 CHECK_ERROR0;
12439 if (op->ch2 == -1)
12440 break;
12441 if (ctxt->value == NULL)
12442 break;
12443
12444#ifdef LIBXML_XPTR_LOCS_ENABLED
12445 /*
12446 * Hum are we filtering the result of an XPointer expression
12447 */
12448 if (ctxt->value->type == XPATH_LOCATIONSET) {
12449 xmlLocationSetPtr locset = ctxt->value->user;
12450 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
12451 1, locset->locNr);
12452 break;
12453 }
12454#endif /* LIBXML_XPTR_LOCS_ENABLED */
12455
12456 /*
12457 * In case of errors, xmlXPathNodeSetFilter can pop additional
12458 * nodes from the stack. We have to temporarily remove the
12459 * nodeset object from the stack to avoid freeing it
12460 * prematurely.
12461 */
12462 CHECK_TYPE0(XPATH_NODESET);
12463 obj = valuePop(ctxt);
12464 set = obj->nodesetval;
12465 if (set != NULL)
12466 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
12467 1, set->nodeNr, 1);
12468 valuePush(ctxt, obj);
12469 break;
12470 }
12471 case XPATH_OP_SORT:
12472 if (op->ch1 != -1)
12473 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12474 CHECK_ERROR0;
12475 if ((ctxt->value != NULL) &&
12476 (ctxt->value->type == XPATH_NODESET) &&
12477 (ctxt->value->nodesetval != NULL) &&
12478 (ctxt->value->nodesetval->nodeNr > 1))
12479 {
12480 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12481 }
12482 break;
12483#ifdef LIBXML_XPTR_LOCS_ENABLED
12484 case XPATH_OP_RANGETO:{
12485 xmlXPathObjectPtr range;
12486 xmlXPathObjectPtr res, obj;
12487 xmlXPathObjectPtr tmp;
12488 xmlLocationSetPtr newlocset = NULL;
12489 xmlLocationSetPtr oldlocset;
12490 xmlNodeSetPtr oldset;
12491 xmlNodePtr oldnode = ctxt->context->node;
12492 int oldcs = ctxt->context->contextSize;
12493 int oldpp = ctxt->context->proximityPosition;
12494 int i, j;
12495
12496 if (op->ch1 != -1) {
12497 total +=
12498 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12499 CHECK_ERROR0;
12500 }
12501 if (ctxt->value == NULL) {
12502 XP_ERROR0(XPATH_INVALID_OPERAND);
12503 }
12504 if (op->ch2 == -1)
12505 break;
12506
12507 if (ctxt->value->type == XPATH_LOCATIONSET) {
12508 /*
12509 * Extract the old locset, and then evaluate the result of the
12510 * expression for all the element in the locset. use it to grow
12511 * up a new locset.
12512 */
12513 CHECK_TYPE0(XPATH_LOCATIONSET);
12514
12515 if ((ctxt->value->user == NULL) ||
12516 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
12517 break;
12518
12519 obj = valuePop(ctxt);
12520 oldlocset = obj->user;
12521
12522 newlocset = xmlXPtrLocationSetCreate(NULL);
12523
12524 for (i = 0; i < oldlocset->locNr; i++) {
12525 /*
12526 * Run the evaluation with a node list made of a
12527 * single item in the nodelocset.
12528 */
12529 ctxt->context->node = oldlocset->locTab[i]->user;
12530 ctxt->context->contextSize = oldlocset->locNr;
12531 ctxt->context->proximityPosition = i + 1;
12532 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12533 ctxt->context->node);
12534 valuePush(ctxt, tmp);
12535
12536 if (op->ch2 != -1)
12537 total +=
12538 xmlXPathCompOpEval(ctxt,
12539 &comp->steps[op->ch2]);
12540 if (ctxt->error != XPATH_EXPRESSION_OK) {
12541 xmlXPtrFreeLocationSet(newlocset);
12542 goto rangeto_error;
12543 }
12544
12545 res = valuePop(ctxt);
12546 if (res->type == XPATH_LOCATIONSET) {
12547 xmlLocationSetPtr rloc =
12548 (xmlLocationSetPtr)res->user;
12549 for (j=0; j<rloc->locNr; j++) {
12550 range = xmlXPtrNewRange(
12551 oldlocset->locTab[i]->user,
12552 oldlocset->locTab[i]->index,
12553 rloc->locTab[j]->user2,
12554 rloc->locTab[j]->index2);
12555 if (range != NULL) {
12556 xmlXPtrLocationSetAdd(newlocset, range);
12557 }
12558 }
12559 } else {
12560 range = xmlXPtrNewRangeNodeObject(
12561 (xmlNodePtr)oldlocset->locTab[i]->user, res);
12562 if (range != NULL) {
12563 xmlXPtrLocationSetAdd(newlocset,range);
12564 }
12565 }
12566
12567 /*
12568 * Cleanup
12569 */
12570 if (res != NULL) {
12571 xmlXPathReleaseObject(ctxt->context, res);
12572 }
12573 if (ctxt->value == tmp) {
12574 res = valuePop(ctxt);
12575 xmlXPathReleaseObject(ctxt->context, res);
12576 }
12577 }
12578 } else { /* Not a location set */
12579 CHECK_TYPE0(XPATH_NODESET);
12580 obj = valuePop(ctxt);
12581 oldset = obj->nodesetval;
12582
12583 newlocset = xmlXPtrLocationSetCreate(NULL);
12584
12585 if (oldset != NULL) {
12586 for (i = 0; i < oldset->nodeNr; i++) {
12587 /*
12588 * Run the evaluation with a node list made of a single item
12589 * in the nodeset.
12590 */
12591 ctxt->context->node = oldset->nodeTab[i];
12592 /*
12593 * OPTIMIZE TODO: Avoid recreation for every iteration.
12594 */
12595 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12596 ctxt->context->node);
12597 valuePush(ctxt, tmp);
12598
12599 if (op->ch2 != -1)
12600 total +=
12601 xmlXPathCompOpEval(ctxt,
12602 &comp->steps[op->ch2]);
12603 if (ctxt->error != XPATH_EXPRESSION_OK) {
12604 xmlXPtrFreeLocationSet(newlocset);
12605 goto rangeto_error;
12606 }
12607
12608 res = valuePop(ctxt);
12609 range =
12610 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
12611 res);
12612 if (range != NULL) {
12613 xmlXPtrLocationSetAdd(newlocset, range);
12614 }
12615
12616 /*
12617 * Cleanup
12618 */
12619 if (res != NULL) {
12620 xmlXPathReleaseObject(ctxt->context, res);
12621 }
12622 if (ctxt->value == tmp) {
12623 res = valuePop(ctxt);
12624 xmlXPathReleaseObject(ctxt->context, res);
12625 }
12626 }
12627 }
12628 }
12629
12630 /*
12631 * The result is used as the new evaluation set.
12632 */
12633 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12634rangeto_error:
12635 xmlXPathReleaseObject(ctxt->context, obj);
12636 ctxt->context->node = oldnode;
12637 ctxt->context->contextSize = oldcs;
12638 ctxt->context->proximityPosition = oldpp;
12639 break;
12640 }
12641#endif /* LIBXML_XPTR_LOCS_ENABLED */
12642 default:
12643 xmlGenericError(xmlGenericErrorContext,
12644 "XPath: unknown precompiled operation %d\n", op->op);
12645 ctxt->error = XPATH_INVALID_OPERAND;
12646 break;
12647 }
12648
12649 ctxt->context->depth -= 1;
12650 return (total);
12651}
12652
12653/**
12654 * xmlXPathCompOpEvalToBoolean:
12655 * @ctxt: the XPath parser context
12656 *
12657 * Evaluates if the expression evaluates to true.
12658 *
12659 * Returns 1 if true, 0 if false and -1 on API or internal errors.
12660 */
12661static int
12662xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
12663 xmlXPathStepOpPtr op,
12664 int isPredicate)
12665{
12666 xmlXPathObjectPtr resObj = NULL;
12667
12668start:
12669 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12670 return(0);
12671 /* comp = ctxt->comp; */
12672 switch (op->op) {
12673 case XPATH_OP_END:
12674 return (0);
12675 case XPATH_OP_VALUE:
12676 resObj = (xmlXPathObjectPtr) op->value4;
12677 if (isPredicate)
12678 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
12679 return(xmlXPathCastToBoolean(resObj));
12680 case XPATH_OP_SORT:
12681 /*
12682 * We don't need sorting for boolean results. Skip this one.
12683 */
12684 if (op->ch1 != -1) {
12685 op = &ctxt->comp->steps[op->ch1];
12686 goto start;
12687 }
12688 return(0);
12689 case XPATH_OP_COLLECT:
12690 if (op->ch1 == -1)
12691 return(0);
12692
12693 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
12694 if (ctxt->error != XPATH_EXPRESSION_OK)
12695 return(-1);
12696
12697 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
12698 if (ctxt->error != XPATH_EXPRESSION_OK)
12699 return(-1);
12700
12701 resObj = valuePop(ctxt);
12702 if (resObj == NULL)
12703 return(-1);
12704 break;
12705 default:
12706 /*
12707 * Fallback to call xmlXPathCompOpEval().
12708 */
12709 xmlXPathCompOpEval(ctxt, op);
12710 if (ctxt->error != XPATH_EXPRESSION_OK)
12711 return(-1);
12712
12713 resObj = valuePop(ctxt);
12714 if (resObj == NULL)
12715 return(-1);
12716 break;
12717 }
12718
12719 if (resObj) {
12720 int res;
12721
12722 if (resObj->type == XPATH_BOOLEAN) {
12723 res = resObj->boolval;
12724 } else if (isPredicate) {
12725 /*
12726 * For predicates a result of type "number" is handled
12727 * differently:
12728 * SPEC XPath 1.0:
12729 * "If the result is a number, the result will be converted
12730 * to true if the number is equal to the context position
12731 * and will be converted to false otherwise;"
12732 */
12733 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
12734 } else {
12735 res = xmlXPathCastToBoolean(resObj);
12736 }
12737 xmlXPathReleaseObject(ctxt->context, resObj);
12738 return(res);
12739 }
12740
12741 return(0);
12742}
12743
12744#ifdef XPATH_STREAMING
12745/**
12746 * xmlXPathRunStreamEval:
12747 * @ctxt: the XPath parser context with the compiled expression
12748 *
12749 * Evaluate the Precompiled Streamable XPath expression in the given context.
12750 */
12751static int
12752xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
12753 xmlXPathObjectPtr *resultSeq, int toBool)
12754{
12755 int max_depth, min_depth;
12756 int from_root;
12757 int ret, depth;
12758 int eval_all_nodes;
12759 xmlNodePtr cur = NULL, limit = NULL;
12760 xmlStreamCtxtPtr patstream = NULL;
12761
12762 if ((ctxt == NULL) || (comp == NULL))
12763 return(-1);
12764 max_depth = xmlPatternMaxDepth(comp);
12765 if (max_depth == -1)
12766 return(-1);
12767 if (max_depth == -2)
12768 max_depth = 10000;
12769 min_depth = xmlPatternMinDepth(comp);
12770 if (min_depth == -1)
12771 return(-1);
12772 from_root = xmlPatternFromRoot(comp);
12773 if (from_root < 0)
12774 return(-1);
12775#if 0
12776 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
12777#endif
12778
12779 if (! toBool) {
12780 if (resultSeq == NULL)
12781 return(-1);
12782 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
12783 if (*resultSeq == NULL)
12784 return(-1);
12785 }
12786
12787 /*
12788 * handle the special cases of "/" amd "." being matched
12789 */
12790 if (min_depth == 0) {
12791 if (from_root) {
12792 /* Select "/" */
12793 if (toBool)
12794 return(1);
12795 /* TODO: Check memory error. */
12796 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12797 (xmlNodePtr) ctxt->doc);
12798 } else {
12799 /* Select "self::node()" */
12800 if (toBool)
12801 return(1);
12802 /* TODO: Check memory error. */
12803 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
12804 }
12805 }
12806 if (max_depth == 0) {
12807 return(0);
12808 }
12809
12810 if (from_root) {
12811 cur = (xmlNodePtr)ctxt->doc;
12812 } else if (ctxt->node != NULL) {
12813 switch (ctxt->node->type) {
12814 case XML_ELEMENT_NODE:
12815 case XML_DOCUMENT_NODE:
12816 case XML_DOCUMENT_FRAG_NODE:
12817 case XML_HTML_DOCUMENT_NODE:
12818 cur = ctxt->node;
12819 break;
12820 case XML_ATTRIBUTE_NODE:
12821 case XML_TEXT_NODE:
12822 case XML_CDATA_SECTION_NODE:
12823 case XML_ENTITY_REF_NODE:
12824 case XML_ENTITY_NODE:
12825 case XML_PI_NODE:
12826 case XML_COMMENT_NODE:
12827 case XML_NOTATION_NODE:
12828 case XML_DTD_NODE:
12829 case XML_DOCUMENT_TYPE_NODE:
12830 case XML_ELEMENT_DECL:
12831 case XML_ATTRIBUTE_DECL:
12832 case XML_ENTITY_DECL:
12833 case XML_NAMESPACE_DECL:
12834 case XML_XINCLUDE_START:
12835 case XML_XINCLUDE_END:
12836 break;
12837 }
12838 limit = cur;
12839 }
12840 if (cur == NULL) {
12841 return(0);
12842 }
12843
12844 patstream = xmlPatternGetStreamCtxt(comp);
12845 if (patstream == NULL) {
12846 /*
12847 * QUESTION TODO: Is this an error?
12848 */
12849 return(0);
12850 }
12851
12852 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
12853
12854 if (from_root) {
12855 ret = xmlStreamPush(patstream, NULL, NULL);
12856 if (ret < 0) {
12857 } else if (ret == 1) {
12858 if (toBool)
12859 goto return_1;
12860 /* TODO: Check memory error. */
12861 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
12862 }
12863 }
12864 depth = 0;
12865 goto scan_children;
12866next_node:
12867 do {
12868 if (ctxt->opLimit != 0) {
12869 if (ctxt->opCount >= ctxt->opLimit) {
12870 xmlGenericError(xmlGenericErrorContext,
12871 "XPath operation limit exceeded\n");
12872 xmlFreeStreamCtxt(patstream);
12873 return(-1);
12874 }
12875 ctxt->opCount++;
12876 }
12877
12878 switch (cur->type) {
12879 case XML_ELEMENT_NODE:
12880 case XML_TEXT_NODE:
12881 case XML_CDATA_SECTION_NODE:
12882 case XML_COMMENT_NODE:
12883 case XML_PI_NODE:
12884 if (cur->type == XML_ELEMENT_NODE) {
12885 ret = xmlStreamPush(patstream, cur->name,
12886 (cur->ns ? cur->ns->href : NULL));
12887 } else if (eval_all_nodes)
12888 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
12889 else
12890 break;
12891
12892 if (ret < 0) {
12893 /* NOP. */
12894 } else if (ret == 1) {
12895 if (toBool)
12896 goto return_1;
12897 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
12898 < 0) {
12899 ctxt->lastError.domain = XML_FROM_XPATH;
12900 ctxt->lastError.code = XML_ERR_NO_MEMORY;
12901 }
12902 }
12903 if ((cur->children == NULL) || (depth >= max_depth)) {
12904 ret = xmlStreamPop(patstream);
12905 while (cur->next != NULL) {
12906 cur = cur->next;
12907 if ((cur->type != XML_ENTITY_DECL) &&
12908 (cur->type != XML_DTD_NODE))
12909 goto next_node;
12910 }
12911 }
12912 default:
12913 break;
12914 }
12915
12916scan_children:
12917 if (cur->type == XML_NAMESPACE_DECL) break;
12918 if ((cur->children != NULL) && (depth < max_depth)) {
12919 /*
12920 * Do not descend on entities declarations
12921 */
12922 if (cur->children->type != XML_ENTITY_DECL) {
12923 cur = cur->children;
12924 depth++;
12925 /*
12926 * Skip DTDs
12927 */
12928 if (cur->type != XML_DTD_NODE)
12929 continue;
12930 }
12931 }
12932
12933 if (cur == limit)
12934 break;
12935
12936 while (cur->next != NULL) {
12937 cur = cur->next;
12938 if ((cur->type != XML_ENTITY_DECL) &&
12939 (cur->type != XML_DTD_NODE))
12940 goto next_node;
12941 }
12942
12943 do {
12944 cur = cur->parent;
12945 depth--;
12946 if ((cur == NULL) || (cur == limit) ||
12947 (cur->type == XML_DOCUMENT_NODE))
12948 goto done;
12949 if (cur->type == XML_ELEMENT_NODE) {
12950 ret = xmlStreamPop(patstream);
12951 } else if ((eval_all_nodes) &&
12952 ((cur->type == XML_TEXT_NODE) ||
12953 (cur->type == XML_CDATA_SECTION_NODE) ||
12954 (cur->type == XML_COMMENT_NODE) ||
12955 (cur->type == XML_PI_NODE)))
12956 {
12957 ret = xmlStreamPop(patstream);
12958 }
12959 if (cur->next != NULL) {
12960 cur = cur->next;
12961 break;
12962 }
12963 } while (cur != NULL);
12964
12965 } while ((cur != NULL) && (depth >= 0));
12966
12967done:
12968
12969 if (patstream)
12970 xmlFreeStreamCtxt(patstream);
12971 return(0);
12972
12973return_1:
12974 if (patstream)
12975 xmlFreeStreamCtxt(patstream);
12976 return(1);
12977}
12978#endif /* XPATH_STREAMING */
12979
12980/**
12981 * xmlXPathRunEval:
12982 * @ctxt: the XPath parser context with the compiled expression
12983 * @toBool: evaluate to a boolean result
12984 *
12985 * Evaluate the Precompiled XPath expression in the given context.
12986 */
12987static int
12988xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12989{
12990 xmlXPathCompExprPtr comp;
12991 int oldDepth;
12992
12993 if ((ctxt == NULL) || (ctxt->comp == NULL))
12994 return(-1);
12995
12996 if (ctxt->valueTab == NULL) {
12997 /* Allocate the value stack */
12998 ctxt->valueTab = (xmlXPathObjectPtr *)
12999 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13000 if (ctxt->valueTab == NULL) {
13001 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13002 return(-1);
13003 }
13004 ctxt->valueNr = 0;
13005 ctxt->valueMax = 10;
13006 ctxt->value = NULL;
13007 }
13008#ifdef XPATH_STREAMING
13009 if (ctxt->comp->stream) {
13010 int res;
13011
13012 if (toBool) {
13013 /*
13014 * Evaluation to boolean result.
13015 */
13016 res = xmlXPathRunStreamEval(ctxt->context,
13017 ctxt->comp->stream, NULL, 1);
13018 if (res != -1)
13019 return(res);
13020 } else {
13021 xmlXPathObjectPtr resObj = NULL;
13022
13023 /*
13024 * Evaluation to a sequence.
13025 */
13026 res = xmlXPathRunStreamEval(ctxt->context,
13027 ctxt->comp->stream, &resObj, 0);
13028
13029 if ((res != -1) && (resObj != NULL)) {
13030 valuePush(ctxt, resObj);
13031 return(0);
13032 }
13033 if (resObj != NULL)
13034 xmlXPathReleaseObject(ctxt->context, resObj);
13035 }
13036 /*
13037 * QUESTION TODO: This falls back to normal XPath evaluation
13038 * if res == -1. Is this intended?
13039 */
13040 }
13041#endif
13042 comp = ctxt->comp;
13043 if (comp->last < 0) {
13044 xmlGenericError(xmlGenericErrorContext,
13045 "xmlXPathRunEval: last is less than zero\n");
13046 return(-1);
13047 }
13048 oldDepth = ctxt->context->depth;
13049 if (toBool)
13050 return(xmlXPathCompOpEvalToBoolean(ctxt,
13051 &comp->steps[comp->last], 0));
13052 else
13053 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13054 ctxt->context->depth = oldDepth;
13055
13056 return(0);
13057}
13058
13059/************************************************************************
13060 * *
13061 * Public interfaces *
13062 * *
13063 ************************************************************************/
13064
13065/**
13066 * xmlXPathEvalPredicate:
13067 * @ctxt: the XPath context
13068 * @res: the Predicate Expression evaluation result
13069 *
13070 * Evaluate a predicate result for the current node.
13071 * A PredicateExpr is evaluated by evaluating the Expr and converting
13072 * the result to a boolean. If the result is a number, the result will
13073 * be converted to true if the number is equal to the position of the
13074 * context node in the context node list (as returned by the position
13075 * function) and will be converted to false otherwise; if the result
13076 * is not a number, then the result will be converted as if by a call
13077 * to the boolean function.
13078 *
13079 * Returns 1 if predicate is true, 0 otherwise
13080 */
13081int
13082xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13083 if ((ctxt == NULL) || (res == NULL)) return(0);
13084 switch (res->type) {
13085 case XPATH_BOOLEAN:
13086 return(res->boolval);
13087 case XPATH_NUMBER:
13088 return(res->floatval == ctxt->proximityPosition);
13089 case XPATH_NODESET:
13090 case XPATH_XSLT_TREE:
13091 if (res->nodesetval == NULL)
13092 return(0);
13093 return(res->nodesetval->nodeNr != 0);
13094 case XPATH_STRING:
13095 return((res->stringval != NULL) &&
13096 (xmlStrlen(res->stringval) != 0));
13097 default:
13098 STRANGE
13099 }
13100 return(0);
13101}
13102
13103/**
13104 * xmlXPathEvaluatePredicateResult:
13105 * @ctxt: the XPath Parser context
13106 * @res: the Predicate Expression evaluation result
13107 *
13108 * Evaluate a predicate result for the current node.
13109 * A PredicateExpr is evaluated by evaluating the Expr and converting
13110 * the result to a boolean. If the result is a number, the result will
13111 * be converted to true if the number is equal to the position of the
13112 * context node in the context node list (as returned by the position
13113 * function) and will be converted to false otherwise; if the result
13114 * is not a number, then the result will be converted as if by a call
13115 * to the boolean function.
13116 *
13117 * Returns 1 if predicate is true, 0 otherwise
13118 */
13119int
13120xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13121 xmlXPathObjectPtr res) {
13122 if ((ctxt == NULL) || (res == NULL)) return(0);
13123 switch (res->type) {
13124 case XPATH_BOOLEAN:
13125 return(res->boolval);
13126 case XPATH_NUMBER:
13127#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
13128 return((res->floatval == ctxt->context->proximityPosition) &&
13129 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
13130#else
13131 return(res->floatval == ctxt->context->proximityPosition);
13132#endif
13133 case XPATH_NODESET:
13134 case XPATH_XSLT_TREE:
13135 if (res->nodesetval == NULL)
13136 return(0);
13137 return(res->nodesetval->nodeNr != 0);
13138 case XPATH_STRING:
13139 return((res->stringval != NULL) && (res->stringval[0] != 0));
13140#ifdef LIBXML_XPTR_LOCS_ENABLED
13141 case XPATH_LOCATIONSET:{
13142 xmlLocationSetPtr ptr = res->user;
13143 if (ptr == NULL)
13144 return(0);
13145 return (ptr->locNr != 0);
13146 }
13147#endif
13148 default:
13149 STRANGE
13150 }
13151 return(0);
13152}
13153
13154#ifdef XPATH_STREAMING
13155/**
13156 * xmlXPathTryStreamCompile:
13157 * @ctxt: an XPath context
13158 * @str: the XPath expression
13159 *
13160 * Try to compile the XPath expression as a streamable subset.
13161 *
13162 * Returns the compiled expression or NULL if failed to compile.
13163 */
13164static xmlXPathCompExprPtr
13165xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13166 /*
13167 * Optimization: use streaming patterns when the XPath expression can
13168 * be compiled to a stream lookup
13169 */
13170 xmlPatternPtr stream;
13171 xmlXPathCompExprPtr comp;
13172 xmlDictPtr dict = NULL;
13173 const xmlChar **namespaces = NULL;
13174 xmlNsPtr ns;
13175 int i, j;
13176
13177 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
13178 (!xmlStrchr(str, '@'))) {
13179 const xmlChar *tmp;
13180
13181 /*
13182 * We don't try to handle expressions using the verbose axis
13183 * specifiers ("::"), just the simplified form at this point.
13184 * Additionally, if there is no list of namespaces available and
13185 * there's a ":" in the expression, indicating a prefixed QName,
13186 * then we won't try to compile either. xmlPatterncompile() needs
13187 * to have a list of namespaces at compilation time in order to
13188 * compile prefixed name tests.
13189 */
13190 tmp = xmlStrchr(str, ':');
13191 if ((tmp != NULL) &&
13192 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
13193 return(NULL);
13194
13195 if (ctxt != NULL) {
13196 dict = ctxt->dict;
13197 if (ctxt->nsNr > 0) {
13198 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
13199 if (namespaces == NULL) {
13200 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
13201 return(NULL);
13202 }
13203 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
13204 ns = ctxt->namespaces[j];
13205 namespaces[i++] = ns->href;
13206 namespaces[i++] = ns->prefix;
13207 }
13208 namespaces[i++] = NULL;
13209 namespaces[i] = NULL;
13210 }
13211 }
13212
13213 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
13214 if (namespaces != NULL) {
13215 xmlFree((xmlChar **)namespaces);
13216 }
13217 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
13218 comp = xmlXPathNewCompExpr();
13219 if (comp == NULL) {
13220 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
13221 xmlFreePattern(stream);
13222 return(NULL);
13223 }
13224 comp->stream = stream;
13225 comp->dict = dict;
13226 if (comp->dict)
13227 xmlDictReference(comp->dict);
13228 return(comp);
13229 }
13230 xmlFreePattern(stream);
13231 }
13232 return(NULL);
13233}
13234#endif /* XPATH_STREAMING */
13235
13236static void
13237xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
13238 xmlXPathStepOpPtr op)
13239{
13240 xmlXPathCompExprPtr comp = pctxt->comp;
13241 xmlXPathContextPtr ctxt;
13242
13243 /*
13244 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
13245 * internal representation.
13246 */
13247
13248 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
13249 (op->ch1 != -1) &&
13250 (op->ch2 == -1 /* no predicate */))
13251 {
13252 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
13253
13254 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
13255 ((xmlXPathAxisVal) prevop->value ==
13256 AXIS_DESCENDANT_OR_SELF) &&
13257 (prevop->ch2 == -1) &&
13258 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
13259 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
13260 {
13261 /*
13262 * This is a "descendant-or-self::node()" without predicates.
13263 * Try to eliminate it.
13264 */
13265
13266 switch ((xmlXPathAxisVal) op->value) {
13267 case AXIS_CHILD:
13268 case AXIS_DESCENDANT:
13269 /*
13270 * Convert "descendant-or-self::node()/child::" or
13271 * "descendant-or-self::node()/descendant::" to
13272 * "descendant::"
13273 */
13274 op->ch1 = prevop->ch1;
13275 op->value = AXIS_DESCENDANT;
13276 break;
13277 case AXIS_SELF:
13278 case AXIS_DESCENDANT_OR_SELF:
13279 /*
13280 * Convert "descendant-or-self::node()/self::" or
13281 * "descendant-or-self::node()/descendant-or-self::" to
13282 * to "descendant-or-self::"
13283 */
13284 op->ch1 = prevop->ch1;
13285 op->value = AXIS_DESCENDANT_OR_SELF;
13286 break;
13287 default:
13288 break;
13289 }
13290 }
13291 }
13292
13293 /* OP_VALUE has invalid ch1. */
13294 if (op->op == XPATH_OP_VALUE)
13295 return;
13296
13297 /* Recurse */
13298 ctxt = pctxt->context;
13299 if (ctxt != NULL) {
13300 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
13301 return;
13302 ctxt->depth += 1;
13303 }
13304 if (op->ch1 != -1)
13305 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
13306 if (op->ch2 != -1)
13307 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
13308 if (ctxt != NULL)
13309 ctxt->depth -= 1;
13310}
13311
13312/**
13313 * xmlXPathCtxtCompile:
13314 * @ctxt: an XPath context
13315 * @str: the XPath expression
13316 *
13317 * Compile an XPath expression
13318 *
13319 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13320 * the caller has to free the object.
13321 */
13322xmlXPathCompExprPtr
13323xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13324 xmlXPathParserContextPtr pctxt;
13325 xmlXPathCompExprPtr comp;
13326 int oldDepth = 0;
13327
13328#ifdef XPATH_STREAMING
13329 comp = xmlXPathTryStreamCompile(ctxt, str);
13330 if (comp != NULL)
13331 return(comp);
13332#endif
13333
13334 xmlInitParser();
13335
13336 pctxt = xmlXPathNewParserContext(str, ctxt);
13337 if (pctxt == NULL)
13338 return NULL;
13339 if (ctxt != NULL)
13340 oldDepth = ctxt->depth;
13341 xmlXPathCompileExpr(pctxt, 1);
13342 if (ctxt != NULL)
13343 ctxt->depth = oldDepth;
13344
13345 if( pctxt->error != XPATH_EXPRESSION_OK )
13346 {
13347 xmlXPathFreeParserContext(pctxt);
13348 return(NULL);
13349 }
13350
13351 if (*pctxt->cur != 0) {
13352 /*
13353 * aleksey: in some cases this line prints *second* error message
13354 * (see bug #78858) and probably this should be fixed.
13355 * However, we are not sure that all error messages are printed
13356 * out in other places. It's not critical so we leave it as-is for now
13357 */
13358 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13359 comp = NULL;
13360 } else {
13361 comp = pctxt->comp;
13362 if ((comp->nbStep > 1) && (comp->last >= 0)) {
13363 if (ctxt != NULL)
13364 oldDepth = ctxt->depth;
13365 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
13366 if (ctxt != NULL)
13367 ctxt->depth = oldDepth;
13368 }
13369 pctxt->comp = NULL;
13370 }
13371 xmlXPathFreeParserContext(pctxt);
13372
13373 if (comp != NULL) {
13374 comp->expr = xmlStrdup(str);
13375 }
13376 return(comp);
13377}
13378
13379/**
13380 * xmlXPathCompile:
13381 * @str: the XPath expression
13382 *
13383 * Compile an XPath expression
13384 *
13385 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13386 * the caller has to free the object.
13387 */
13388xmlXPathCompExprPtr
13389xmlXPathCompile(const xmlChar *str) {
13390 return(xmlXPathCtxtCompile(NULL, str));
13391}
13392
13393/**
13394 * xmlXPathCompiledEvalInternal:
13395 * @comp: the compiled XPath expression
13396 * @ctxt: the XPath context
13397 * @resObj: the resulting XPath object or NULL
13398 * @toBool: 1 if only a boolean result is requested
13399 *
13400 * Evaluate the Precompiled XPath expression in the given context.
13401 * The caller has to free @resObj.
13402 *
13403 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13404 * the caller has to free the object.
13405 */
13406static int
13407xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
13408 xmlXPathContextPtr ctxt,
13409 xmlXPathObjectPtr *resObjPtr,
13410 int toBool)
13411{
13412 xmlXPathParserContextPtr pctxt;
13413 xmlXPathObjectPtr resObj;
13414#ifndef LIBXML_THREAD_ENABLED
13415 static int reentance = 0;
13416#endif
13417 int res;
13418
13419 CHECK_CTXT_NEG(ctxt)
13420
13421 if (comp == NULL)
13422 return(-1);
13423 xmlInitParser();
13424
13425#ifndef LIBXML_THREAD_ENABLED
13426 reentance++;
13427 if (reentance > 1)
13428 xmlXPathDisableOptimizer = 1;
13429#endif
13430
13431 pctxt = xmlXPathCompParserContext(comp, ctxt);
13432 if (pctxt == NULL)
13433 return(-1);
13434 res = xmlXPathRunEval(pctxt, toBool);
13435
13436 if (pctxt->error != XPATH_EXPRESSION_OK) {
13437 resObj = NULL;
13438 } else {
13439 resObj = valuePop(pctxt);
13440 if (resObj == NULL) {
13441 if (!toBool)
13442 xmlGenericError(xmlGenericErrorContext,
13443 "xmlXPathCompiledEval: No result on the stack.\n");
13444 } else if (pctxt->valueNr > 0) {
13445 xmlGenericError(xmlGenericErrorContext,
13446 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
13447 pctxt->valueNr);
13448 }
13449 }
13450
13451 if (resObjPtr)
13452 *resObjPtr = resObj;
13453 else
13454 xmlXPathReleaseObject(ctxt, resObj);
13455
13456 pctxt->comp = NULL;
13457 xmlXPathFreeParserContext(pctxt);
13458#ifndef LIBXML_THREAD_ENABLED
13459 reentance--;
13460#endif
13461
13462 return(res);
13463}
13464
13465/**
13466 * xmlXPathCompiledEval:
13467 * @comp: the compiled XPath expression
13468 * @ctx: the XPath context
13469 *
13470 * Evaluate the Precompiled XPath expression in the given context.
13471 *
13472 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13473 * the caller has to free the object.
13474 */
13475xmlXPathObjectPtr
13476xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
13477{
13478 xmlXPathObjectPtr res = NULL;
13479
13480 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
13481 return(res);
13482}
13483
13484/**
13485 * xmlXPathCompiledEvalToBoolean:
13486 * @comp: the compiled XPath expression
13487 * @ctxt: the XPath context
13488 *
13489 * Applies the XPath boolean() function on the result of the given
13490 * compiled expression.
13491 *
13492 * Returns 1 if the expression evaluated to true, 0 if to false and
13493 * -1 in API and internal errors.
13494 */
13495int
13496xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
13497 xmlXPathContextPtr ctxt)
13498{
13499 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
13500}
13501
13502/**
13503 * xmlXPathEvalExpr:
13504 * @ctxt: the XPath Parser context
13505 *
13506 * Parse and evaluate an XPath expression in the given context,
13507 * then push the result on the context stack
13508 */
13509void
13510xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
13511#ifdef XPATH_STREAMING
13512 xmlXPathCompExprPtr comp;
13513#endif
13514 int oldDepth = 0;
13515
13516 if (ctxt == NULL) return;
13517
13518#ifdef XPATH_STREAMING
13519 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
13520 if (comp != NULL) {
13521 if (ctxt->comp != NULL)
13522 xmlXPathFreeCompExpr(ctxt->comp);
13523 ctxt->comp = comp;
13524 } else
13525#endif
13526 {
13527 if (ctxt->context != NULL)
13528 oldDepth = ctxt->context->depth;
13529 xmlXPathCompileExpr(ctxt, 1);
13530 if (ctxt->context != NULL)
13531 ctxt->context->depth = oldDepth;
13532 CHECK_ERROR;
13533
13534 /* Check for trailing characters. */
13535 if (*ctxt->cur != 0)
13536 XP_ERROR(XPATH_EXPR_ERROR);
13537
13538 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
13539 if (ctxt->context != NULL)
13540 oldDepth = ctxt->context->depth;
13541 xmlXPathOptimizeExpression(ctxt,
13542 &ctxt->comp->steps[ctxt->comp->last]);
13543 if (ctxt->context != NULL)
13544 ctxt->context->depth = oldDepth;
13545 }
13546 }
13547
13548 xmlXPathRunEval(ctxt, 0);
13549}
13550
13551/**
13552 * xmlXPathEval:
13553 * @str: the XPath expression
13554 * @ctx: the XPath context
13555 *
13556 * Evaluate the XPath Location Path in the given context.
13557 *
13558 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13559 * the caller has to free the object.
13560 */
13561xmlXPathObjectPtr
13562xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
13563 xmlXPathParserContextPtr ctxt;
13564 xmlXPathObjectPtr res;
13565
13566 CHECK_CTXT(ctx)
13567
13568 xmlInitParser();
13569
13570 ctxt = xmlXPathNewParserContext(str, ctx);
13571 if (ctxt == NULL)
13572 return NULL;
13573 xmlXPathEvalExpr(ctxt);
13574
13575 if (ctxt->error != XPATH_EXPRESSION_OK) {
13576 res = NULL;
13577 } else {
13578 res = valuePop(ctxt);
13579 if (res == NULL) {
13580 xmlGenericError(xmlGenericErrorContext,
13581 "xmlXPathCompiledEval: No result on the stack.\n");
13582 } else if (ctxt->valueNr > 0) {
13583 xmlGenericError(xmlGenericErrorContext,
13584 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
13585 ctxt->valueNr);
13586 }
13587 }
13588
13589 xmlXPathFreeParserContext(ctxt);
13590 return(res);
13591}
13592
13593/**
13594 * xmlXPathSetContextNode:
13595 * @node: the node to to use as the context node
13596 * @ctx: the XPath context
13597 *
13598 * Sets 'node' as the context node. The node must be in the same
13599 * document as that associated with the context.
13600 *
13601 * Returns -1 in case of error or 0 if successful
13602 */
13603int
13604xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
13605 if ((node == NULL) || (ctx == NULL))
13606 return(-1);
13607
13608 if (node->doc == ctx->doc) {
13609 ctx->node = node;
13610 return(0);
13611 }
13612 return(-1);
13613}
13614
13615/**
13616 * xmlXPathNodeEval:
13617 * @node: the node to to use as the context node
13618 * @str: the XPath expression
13619 * @ctx: the XPath context
13620 *
13621 * Evaluate the XPath Location Path in the given context. The node 'node'
13622 * is set as the context node. The context node is not restored.
13623 *
13624 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13625 * the caller has to free the object.
13626 */
13627xmlXPathObjectPtr
13628xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
13629 if (str == NULL)
13630 return(NULL);
13631 if (xmlXPathSetContextNode(node, ctx) < 0)
13632 return(NULL);
13633 return(xmlXPathEval(str, ctx));
13634}
13635
13636/**
13637 * xmlXPathEvalExpression:
13638 * @str: the XPath expression
13639 * @ctxt: the XPath context
13640 *
13641 * Alias for xmlXPathEval().
13642 *
13643 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13644 * the caller has to free the object.
13645 */
13646xmlXPathObjectPtr
13647xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
13648 return(xmlXPathEval(str, ctxt));
13649}
13650
13651/************************************************************************
13652 * *
13653 * Extra functions not pertaining to the XPath spec *
13654 * *
13655 ************************************************************************/
13656/**
13657 * xmlXPathEscapeUriFunction:
13658 * @ctxt: the XPath Parser context
13659 * @nargs: the number of arguments
13660 *
13661 * Implement the escape-uri() XPath function
13662 * string escape-uri(string $str, bool $escape-reserved)
13663 *
13664 * This function applies the URI escaping rules defined in section 2 of [RFC
13665 * 2396] to the string supplied as $uri-part, which typically represents all
13666 * or part of a URI. The effect of the function is to replace any special
13667 * character in the string by an escape sequence of the form %xx%yy...,
13668 * where xxyy... is the hexadecimal representation of the octets used to
13669 * represent the character in UTF-8.
13670 *
13671 * The set of characters that are escaped depends on the setting of the
13672 * boolean argument $escape-reserved.
13673 *
13674 * If $escape-reserved is true, all characters are escaped other than lower
13675 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
13676 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
13677 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
13678 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
13679 * A-F).
13680 *
13681 * If $escape-reserved is false, the behavior differs in that characters
13682 * referred to in [RFC 2396] as reserved characters are not escaped. These
13683 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
13684 *
13685 * [RFC 2396] does not define whether escaped URIs should use lower case or
13686 * upper case for hexadecimal digits. To ensure that escaped URIs can be
13687 * compared using string comparison functions, this function must always use
13688 * the upper-case letters A-F.
13689 *
13690 * Generally, $escape-reserved should be set to true when escaping a string
13691 * that is to form a single part of a URI, and to false when escaping an
13692 * entire URI or URI reference.
13693 *
13694 * In the case of non-ascii characters, the string is encoded according to
13695 * utf-8 and then converted according to RFC 2396.
13696 *
13697 * Examples
13698 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
13699 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
13700 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
13701 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
13702 *
13703 */
13704static void
13705xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
13706 xmlXPathObjectPtr str;
13707 int escape_reserved;
13708 xmlBufPtr target;
13709 xmlChar *cptr;
13710 xmlChar escape[4];
13711
13712 CHECK_ARITY(2);
13713
13714 escape_reserved = xmlXPathPopBoolean(ctxt);
13715
13716 CAST_TO_STRING;
13717 str = valuePop(ctxt);
13718
13719 target = xmlBufCreate();
13720
13721 escape[0] = '%';
13722 escape[3] = 0;
13723
13724 if (target) {
13725 for (cptr = str->stringval; *cptr; cptr++) {
13726 if ((*cptr >= 'A' && *cptr <= 'Z') ||
13727 (*cptr >= 'a' && *cptr <= 'z') ||
13728 (*cptr >= '0' && *cptr <= '9') ||
13729 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
13730 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
13731 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
13732 (*cptr == '%' &&
13733 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
13734 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
13735 (cptr[1] >= '0' && cptr[1] <= '9')) &&
13736 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
13737 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
13738 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
13739 (!escape_reserved &&
13740 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
13741 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
13742 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
13743 *cptr == ','))) {
13744 xmlBufAdd(target, cptr, 1);
13745 } else {
13746 if ((*cptr >> 4) < 10)
13747 escape[1] = '0' + (*cptr >> 4);
13748 else
13749 escape[1] = 'A' - 10 + (*cptr >> 4);
13750 if ((*cptr & 0xF) < 10)
13751 escape[2] = '0' + (*cptr & 0xF);
13752 else
13753 escape[2] = 'A' - 10 + (*cptr & 0xF);
13754
13755 xmlBufAdd(target, &escape[0], 3);
13756 }
13757 }
13758 }
13759 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
13760 xmlBufContent(target)));
13761 xmlBufFree(target);
13762 xmlXPathReleaseObject(ctxt->context, str);
13763}
13764
13765/**
13766 * xmlXPathRegisterAllFunctions:
13767 * @ctxt: the XPath context
13768 *
13769 * Registers all default XPath functions in this context
13770 */
13771void
13772xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
13773{
13774 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
13775 xmlXPathBooleanFunction);
13776 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
13777 xmlXPathCeilingFunction);
13778 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
13779 xmlXPathCountFunction);
13780 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
13781 xmlXPathConcatFunction);
13782 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
13783 xmlXPathContainsFunction);
13784 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
13785 xmlXPathIdFunction);
13786 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
13787 xmlXPathFalseFunction);
13788 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
13789 xmlXPathFloorFunction);
13790 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
13791 xmlXPathLastFunction);
13792 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
13793 xmlXPathLangFunction);
13794 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
13795 xmlXPathLocalNameFunction);
13796 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
13797 xmlXPathNotFunction);
13798 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
13799 xmlXPathNameFunction);
13800 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
13801 xmlXPathNamespaceURIFunction);
13802 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
13803 xmlXPathNormalizeFunction);
13804 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
13805 xmlXPathNumberFunction);
13806 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
13807 xmlXPathPositionFunction);
13808 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
13809 xmlXPathRoundFunction);
13810 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
13811 xmlXPathStringFunction);
13812 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
13813 xmlXPathStringLengthFunction);
13814 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
13815 xmlXPathStartsWithFunction);
13816 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
13817 xmlXPathSubstringFunction);
13818 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
13819 xmlXPathSubstringBeforeFunction);
13820 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
13821 xmlXPathSubstringAfterFunction);
13822 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
13823 xmlXPathSumFunction);
13824 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
13825 xmlXPathTrueFunction);
13826 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
13827 xmlXPathTranslateFunction);
13828
13829 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
13830 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
13831 xmlXPathEscapeUriFunction);
13832}
13833
13834#endif /* LIBXML_XPATH_ENABLED */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use