ReactOS 0.4.16-dev-2-g02a6913
xpath.c
Go to the documentation of this file.
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/valid.h>
35#include <libxml/xpath.h>
38#include <libxml/hash.h>
39#ifdef LIBXML_XPTR_LOCS_ENABLED
40#include <libxml/xpointer.h>
41#endif
42#ifdef LIBXML_DEBUG_ENABLED
43#include <libxml/debugXML.h>
44#endif
45#include <libxml/xmlerror.h>
46#include <libxml/threads.h>
47#include <libxml/globals.h>
48#ifdef LIBXML_PATTERN_ENABLED
49#include <libxml/pattern.h>
50#endif
51
52#include "buf.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
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* XP_DEBUG_OBJ_USAGE:
92* Internal flag to enable tracking of how much XPath objects have been
93* created.
94*/
95/* #define XP_DEBUG_OBJ_USAGE */
96
97/*
98 * XPATH_MAX_STEPS:
99 * when compiling an XPath expression we arbitrary limit the maximum
100 * number of step operation in the compiled expression. 1000000 is
101 * an insanely large value which should never be reached under normal
102 * circumstances
103 */
104#define XPATH_MAX_STEPS 1000000
105
106/*
107 * XPATH_MAX_STACK_DEPTH:
108 * when evaluating an XPath expression we arbitrary limit the maximum
109 * number of object allowed to be pushed on the stack. 1000000 is
110 * an insanely large value which should never be reached under normal
111 * circumstances
112 */
113#define XPATH_MAX_STACK_DEPTH 1000000
114
115/*
116 * XPATH_MAX_NODESET_LENGTH:
117 * when evaluating an XPath expression nodesets are created and we
118 * arbitrary limit the maximum length of those node set. 10000000 is
119 * an insanely large value which should never be reached under normal
120 * circumstances, one would first need to construct an in memory tree
121 * with more than 10 millions nodes.
122 */
123#define XPATH_MAX_NODESET_LENGTH 10000000
124
125/*
126 * XPATH_MAX_RECRUSION_DEPTH:
127 * Maximum amount of nested functions calls when parsing or evaluating
128 * expressions
129 */
130#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
131#define XPATH_MAX_RECURSION_DEPTH 500
132#else
133#define XPATH_MAX_RECURSION_DEPTH 5000
134#endif
135
136/*
137 * TODO:
138 * There are a few spots where some tests are done which depend upon ascii
139 * data. These should be enhanced for full UTF8 support (see particularly
140 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
141 */
142
143#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
155static int
157 int depth1, depth2;
158 int misc = 0, precedence1 = 0, precedence2 = 0;
159 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
161 ptrdiff_t l1, l2;
162
163 if ((node1 == NULL) || (node2 == NULL))
164 return(-2);
165
166 if (node1 == node2)
167 return(0);
168
169 /*
170 * a couple of optimizations which will avoid computations in most cases
171 */
172 switch (node1->type) {
173 case XML_ELEMENT_NODE:
174 if (node2->type == XML_ELEMENT_NODE) {
175 if ((0 > (ptrdiff_t) node1->content) &&
176 (0 > (ptrdiff_t) node2->content) &&
177 (node1->doc == node2->doc))
178 {
179 l1 = -((ptrdiff_t) node1->content);
180 l2 = -((ptrdiff_t) node2->content);
181 if (l1 < l2)
182 return(1);
183 if (l1 > l2)
184 return(-1);
185 } else
186 goto turtle_comparison;
187 }
188 break;
190 precedence1 = 1; /* element is owner */
191 miscNode1 = node1;
192 node1 = node1->parent;
193 misc = 1;
194 break;
195 case XML_TEXT_NODE:
197 case XML_COMMENT_NODE:
198 case XML_PI_NODE: {
199 miscNode1 = node1;
200 /*
201 * Find nearest element node.
202 */
203 if (node1->prev != NULL) {
204 do {
205 node1 = node1->prev;
206 if (node1->type == XML_ELEMENT_NODE) {
207 precedence1 = 3; /* element in prev-sibl axis */
208 break;
209 }
210 if (node1->prev == NULL) {
211 precedence1 = 2; /* element is parent */
212 /*
213 * URGENT TODO: Are there any cases, where the
214 * parent of such a node is not an element node?
215 */
216 node1 = node1->parent;
217 break;
218 }
219 } while (1);
220 } else {
221 precedence1 = 2; /* element is parent */
222 node1 = node1->parent;
223 }
224 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
225 (0 <= (ptrdiff_t) node1->content)) {
226 /*
227 * Fallback for whatever case.
228 */
229 node1 = miscNode1;
230 precedence1 = 0;
231 } else
232 misc = 1;
233 }
234 break;
236 /*
237 * TODO: why do we return 1 for namespace nodes?
238 */
239 return(1);
240 default:
241 break;
242 }
243 switch (node2->type) {
244 case XML_ELEMENT_NODE:
245 break;
247 precedence2 = 1; /* element is owner */
248 miscNode2 = node2;
249 node2 = node2->parent;
250 misc = 1;
251 break;
252 case XML_TEXT_NODE:
254 case XML_COMMENT_NODE:
255 case XML_PI_NODE: {
256 miscNode2 = node2;
257 if (node2->prev != NULL) {
258 do {
259 node2 = node2->prev;
260 if (node2->type == XML_ELEMENT_NODE) {
261 precedence2 = 3; /* element in prev-sibl axis */
262 break;
263 }
264 if (node2->prev == NULL) {
265 precedence2 = 2; /* element is parent */
266 node2 = node2->parent;
267 break;
268 }
269 } while (1);
270 } else {
271 precedence2 = 2; /* element is parent */
272 node2 = node2->parent;
273 }
274 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
275 (0 <= (ptrdiff_t) node2->content))
276 {
277 node2 = miscNode2;
278 precedence2 = 0;
279 } else
280 misc = 1;
281 }
282 break;
284 return(1);
285 default:
286 break;
287 }
288 if (misc) {
289 if (node1 == node2) {
290 if (precedence1 == precedence2) {
291 /*
292 * The ugly case; but normally there aren't many
293 * adjacent non-element nodes around.
294 */
295 cur = miscNode2->prev;
296 while (cur != NULL) {
297 if (cur == miscNode1)
298 return(1);
299 if (cur->type == XML_ELEMENT_NODE)
300 return(-1);
301 cur = cur->prev;
302 }
303 return (-1);
304 } else {
305 /*
306 * Evaluate based on higher precedence wrt to the element.
307 * TODO: This assumes attributes are sorted before content.
308 * Is this 100% correct?
309 */
310 if (precedence1 < precedence2)
311 return(1);
312 else
313 return(-1);
314 }
315 }
316 /*
317 * Special case: One of the helper-elements is contained by the other.
318 * <foo>
319 * <node2>
320 * <node1>Text-1(precedence1 == 2)</node1>
321 * </node2>
322 * Text-6(precedence2 == 3)
323 * </foo>
324 */
325 if ((precedence2 == 3) && (precedence1 > 1)) {
326 cur = node1->parent;
327 while (cur) {
328 if (cur == node2)
329 return(1);
330 cur = cur->parent;
331 }
332 }
333 if ((precedence1 == 3) && (precedence2 > 1)) {
334 cur = node2->parent;
335 while (cur) {
336 if (cur == node1)
337 return(-1);
338 cur = cur->parent;
339 }
340 }
341 }
342
343 /*
344 * Speedup using document order if available.
345 */
346 if ((node1->type == XML_ELEMENT_NODE) &&
347 (node2->type == XML_ELEMENT_NODE) &&
348 (0 > (ptrdiff_t) node1->content) &&
349 (0 > (ptrdiff_t) node2->content) &&
350 (node1->doc == node2->doc)) {
351
352 l1 = -((ptrdiff_t) node1->content);
353 l2 = -((ptrdiff_t) node2->content);
354 if (l1 < l2)
355 return(1);
356 if (l1 > l2)
357 return(-1);
358 }
359
360turtle_comparison:
361
362 if (node1 == node2->prev)
363 return(1);
364 if (node1 == node2->next)
365 return(-1);
366 /*
367 * compute depth to root
368 */
369 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
370 if (cur->parent == node1)
371 return(1);
372 depth2++;
373 }
374 root = cur;
375 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
376 if (cur->parent == node2)
377 return(-1);
378 depth1++;
379 }
380 /*
381 * Distinct document (or distinct entities :-( ) case.
382 */
383 if (root != cur) {
384 return(-2);
385 }
386 /*
387 * get the nearest common ancestor.
388 */
389 while (depth1 > depth2) {
390 depth1--;
391 node1 = node1->parent;
392 }
393 while (depth2 > depth1) {
394 depth2--;
395 node2 = node2->parent;
396 }
397 while (node1->parent != node2->parent) {
398 node1 = node1->parent;
399 node2 = node2->parent;
400 /* should not happen but just in case ... */
401 if ((node1 == NULL) || (node2 == NULL))
402 return(-2);
403 }
404 /*
405 * Find who's first.
406 */
407 if (node1 == node2->prev)
408 return(1);
409 if (node1 == node2->next)
410 return(-1);
411 /*
412 * Speedup using document order if available.
413 */
414 if ((node1->type == XML_ELEMENT_NODE) &&
415 (node2->type == XML_ELEMENT_NODE) &&
416 (0 > (ptrdiff_t) node1->content) &&
417 (0 > (ptrdiff_t) node2->content) &&
418 (node1->doc == node2->doc)) {
419
420 l1 = -((ptrdiff_t) node1->content);
421 l2 = -((ptrdiff_t) node2->content);
422 if (l1 < l2)
423 return(1);
424 if (l1 > l2)
425 return(-1);
426 }
427
428 for (cur = node1->next;cur != NULL;cur = cur->next)
429 if (cur == node2)
430 return(1);
431 return(-1); /* assume there is no sibling list corruption */
432}
433#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
434
435/*
436 * Wrapper for the Timsort algorithm from timsort.h
437 */
438#ifdef WITH_TIM_SORT
439#define SORT_NAME libxml_domnode
440#define SORT_TYPE xmlNodePtr
451static
453#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
455 {
456 int res = xmlXPathCmpNodesExt(x, y);
457 return res == -2 ? res : -res;
458 }
459#else
460 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
461 {
462 int res = xmlXPathCmpNodes(x, y);
463 return res == -2 ? res : -res;
464 }
465#endif
466#define SORT_CMP(x, y) (wrap_cmp(x, y))
467#include "timsort.h"
468#endif /* WITH_TIM_SORT */
469
470#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
471
472/************************************************************************
473 * *
474 * Floating point stuff *
475 * *
476 ************************************************************************/
477
478double xmlXPathNAN = 0.0;
479double xmlXPathPINF = 0.0;
480double xmlXPathNINF = 0.0;
481
490ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
491void
492xmlXPathInit(void) {
493#if defined(NAN) && defined(INFINITY)
494 xmlXPathNAN = NAN;
495 xmlXPathPINF = INFINITY;
496 xmlXPathNINF = -INFINITY;
497#else
498 /* MSVC doesn't allow division by zero in constant expressions. */
499 double zero = 0.0;
500 xmlXPathNAN = 0.0 / zero;
501 xmlXPathPINF = 1.0 / zero;
502 xmlXPathNINF = -xmlXPathPINF;
503#endif
504}
505
512int
513xmlXPathIsNaN(double val) {
514#ifdef isnan
515 return isnan(val);
516#else
517 return !(val == val);
518#endif
519}
520
527int
528xmlXPathIsInf(double val) {
529#ifdef isinf
530 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
531#else
532 if (val >= xmlXPathPINF)
533 return 1;
534 if (val <= -xmlXPathPINF)
535 return -1;
536 return 0;
537#endif
538}
539
540#endif /* SCHEMAS or XPATH */
541
542#ifdef LIBXML_XPATH_ENABLED
543
544/*
545 * TODO: when compatibility allows remove all "fake node libxslt" strings
546 * the test should just be name[0] = ' '
547 */
548#ifdef DEBUG_XPATH_EXPRESSION
549#define DEBUG_STEP
550#define DEBUG_EXPR
551#define DEBUG_EVAL_COUNTS
552#endif
553
554static xmlNs xmlXPathXMLNamespaceStruct = {
555 NULL,
558 BAD_CAST "xml",
559 NULL,
560 NULL
561};
562static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
563#ifndef LIBXML_THREAD_ENABLED
564/*
565 * Optimizer is disabled only when threaded apps are detected while
566 * the library ain't compiled for thread safety.
567 */
568static int xmlXPathDisableOptimizer = 0;
569#endif
570
571/************************************************************************
572 * *
573 * Error handling routines *
574 * *
575 ************************************************************************/
576
583#define XP_ERRORNULL(X) \
584 { xmlXPathErr(ctxt, X); return(NULL); }
585
586/*
587 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
588 */
589static const char* const xmlXPathErrorMessages[] = {
590 "Ok\n",
591 "Number encoding\n",
592 "Unfinished literal\n",
593 "Start of literal\n",
594 "Expected $ for variable reference\n",
595 "Undefined variable\n",
596 "Invalid predicate\n",
597 "Invalid expression\n",
598 "Missing closing curly brace\n",
599 "Unregistered function\n",
600 "Invalid operand\n",
601 "Invalid type\n",
602 "Invalid number of arguments\n",
603 "Invalid context size\n",
604 "Invalid context position\n",
605 "Memory allocation error\n",
606 "Syntax error\n",
607 "Resource error\n",
608 "Sub resource error\n",
609 "Undefined namespace prefix\n",
610 "Encoding error\n",
611 "Char out of XML range\n",
612 "Invalid or incomplete context\n",
613 "Stack usage error\n",
614 "Forbidden variable\n",
615 "Operation limit exceeded\n",
616 "Recursion limit exceeded\n",
617 "?? Unknown error ??\n" /* Must be last in the list! */
618};
619#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
620 sizeof(xmlXPathErrorMessages[0])) - 1)
628static void
629xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
630{
631 if (ctxt != NULL) {
632 xmlResetError(&ctxt->lastError);
633 if (extra) {
634 xmlChar buf[200];
635
636 xmlStrPrintf(buf, 200,
637 "Memory allocation failed : %s\n",
638 extra);
639 ctxt->lastError.message = (char *) xmlStrdup(buf);
640 } else {
641 ctxt->lastError.message = (char *)
642 xmlStrdup(BAD_CAST "Memory allocation failed\n");
643 }
644 ctxt->lastError.domain = XML_FROM_XPATH;
645 ctxt->lastError.code = XML_ERR_NO_MEMORY;
646 if (ctxt->error != NULL)
647 ctxt->error(ctxt->userData, &ctxt->lastError);
648 } else {
649 if (extra)
650 __xmlRaiseError(NULL, NULL, NULL,
653 extra, NULL, NULL, 0, 0,
654 "Memory allocation failed : %s\n", extra);
655 else
656 __xmlRaiseError(NULL, NULL, NULL,
659 NULL, NULL, NULL, 0, 0,
660 "Memory allocation failed\n");
661 }
662}
663
671static void
672xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
673{
674 if (ctxt == NULL)
675 xmlXPathErrMemory(NULL, extra);
676 else {
677 ctxt->error = XPATH_MEMORY_ERROR;
678 xmlXPathErrMemory(ctxt->context, extra);
679 }
680}
681
689void
690xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
691{
692 if ((error < 0) || (error > MAXERRNO))
693 error = MAXERRNO;
694 if (ctxt == NULL) {
695 __xmlRaiseError(NULL, NULL, NULL,
697 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
699 NULL, NULL, NULL, 0, 0,
700 "%s", xmlXPathErrorMessages[error]);
701 return;
702 }
703 ctxt->error = error;
704 if (ctxt->context == NULL) {
705 __xmlRaiseError(NULL, NULL, NULL,
707 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
709 (const char *) ctxt->base, NULL, NULL,
710 ctxt->cur - ctxt->base, 0,
711 "%s", xmlXPathErrorMessages[error]);
712 return;
713 }
714
715 /* cleanup current last error */
716 xmlResetError(&ctxt->context->lastError);
717
718 ctxt->context->lastError.domain = XML_FROM_XPATH;
719 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
720 XPATH_EXPRESSION_OK;
721 ctxt->context->lastError.level = XML_ERR_ERROR;
722 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
723 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
724 ctxt->context->lastError.node = ctxt->context->debugNode;
725 if (ctxt->context->error != NULL) {
726 ctxt->context->error(ctxt->context->userData,
727 &ctxt->context->lastError);
728 } else {
729 __xmlRaiseError(NULL, NULL, NULL,
730 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
731 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
733 (const char *) ctxt->base, NULL, NULL,
734 ctxt->cur - ctxt->base, 0,
735 "%s", xmlXPathErrorMessages[error]);
736 }
737
738}
739
749void
750xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
751 int line ATTRIBUTE_UNUSED, int no) {
752 xmlXPathErr(ctxt, no);
753}
754
763static int
764xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
765 xmlXPathContextPtr xpctxt = ctxt->context;
766
767 if ((opCount > xpctxt->opLimit) ||
768 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
769 xpctxt->opCount = xpctxt->opLimit;
770 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
771 return(-1);
772 }
773
774 xpctxt->opCount += opCount;
775 return(0);
776}
777
778#define OP_LIMIT_EXCEEDED(ctxt, n) \
779 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
780
781/************************************************************************
782 * *
783 * Utilities *
784 * *
785 ************************************************************************/
786
792typedef struct _xmlPointerList xmlPointerList;
793typedef xmlPointerList *xmlPointerListPtr;
794struct _xmlPointerList {
795 void **items;
796 int number;
797 int size;
798};
799/*
800* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
801* and here, we should make the functions public.
802*/
803static int
804xmlPointerListAddSize(xmlPointerListPtr list,
805 void *item,
806 int initialSize)
807{
808 if (list->items == NULL) {
809 if (initialSize <= 0)
810 initialSize = 1;
811 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
812 if (list->items == NULL) {
813 xmlXPathErrMemory(NULL,
814 "xmlPointerListCreate: allocating item\n");
815 return(-1);
816 }
817 list->number = 0;
818 list->size = initialSize;
819 } else if (list->size <= list->number) {
820 if (list->size > 50000000) {
821 xmlXPathErrMemory(NULL,
822 "xmlPointerListAddSize: re-allocating item\n");
823 return(-1);
824 }
825 list->size *= 2;
826 list->items = (void **) xmlRealloc(list->items,
827 list->size * sizeof(void *));
828 if (list->items == NULL) {
829 xmlXPathErrMemory(NULL,
830 "xmlPointerListAddSize: re-allocating item\n");
831 list->size = 0;
832 return(-1);
833 }
834 }
835 list->items[list->number++] = item;
836 return(0);
837}
838
846static xmlPointerListPtr
847xmlPointerListCreate(int initialSize)
848{
849 xmlPointerListPtr ret;
850
851 ret = xmlMalloc(sizeof(xmlPointerList));
852 if (ret == NULL) {
853 xmlXPathErrMemory(NULL,
854 "xmlPointerListCreate: allocating item\n");
855 return (NULL);
856 }
857 memset(ret, 0, sizeof(xmlPointerList));
858 if (initialSize > 0) {
859 xmlPointerListAddSize(ret, NULL, initialSize);
860 ret->number = 0;
861 }
862 return (ret);
863}
864
871static void
872xmlPointerListFree(xmlPointerListPtr list)
873{
874 if (list == NULL)
875 return;
876 if (list->items != NULL)
877 xmlFree(list->items);
878 xmlFree(list);
879}
880
881/************************************************************************
882 * *
883 * Parser Types *
884 * *
885 ************************************************************************/
886
887/*
888 * Types are private:
889 */
890
891typedef enum {
892 XPATH_OP_END=0,
893 XPATH_OP_AND,
894 XPATH_OP_OR,
895 XPATH_OP_EQUAL,
896 XPATH_OP_CMP,
897 XPATH_OP_PLUS,
898 XPATH_OP_MULT,
899 XPATH_OP_UNION,
900 XPATH_OP_ROOT,
901 XPATH_OP_NODE,
902 XPATH_OP_COLLECT,
903 XPATH_OP_VALUE, /* 11 */
904 XPATH_OP_VARIABLE,
905 XPATH_OP_FUNCTION,
906 XPATH_OP_ARG,
907 XPATH_OP_PREDICATE,
908 XPATH_OP_FILTER, /* 16 */
909 XPATH_OP_SORT /* 17 */
910#ifdef LIBXML_XPTR_LOCS_ENABLED
911 ,XPATH_OP_RANGETO
912#endif
913} xmlXPathOp;
914
915typedef enum {
916 AXIS_ANCESTOR = 1,
917 AXIS_ANCESTOR_OR_SELF,
920 AXIS_DESCENDANT,
921 AXIS_DESCENDANT_OR_SELF,
922 AXIS_FOLLOWING,
923 AXIS_FOLLOWING_SIBLING,
924 AXIS_NAMESPACE,
925 AXIS_PARENT,
926 AXIS_PRECEDING,
927 AXIS_PRECEDING_SIBLING,
928 AXIS_SELF
929} xmlXPathAxisVal;
930
931typedef enum {
932 NODE_TEST_NONE = 0,
933 NODE_TEST_TYPE = 1,
934 NODE_TEST_PI = 2,
935 NODE_TEST_ALL = 3,
936 NODE_TEST_NS = 4,
937 NODE_TEST_NAME = 5
938} xmlXPathTestVal;
939
940typedef enum {
941 NODE_TYPE_NODE = 0,
942 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
943 NODE_TYPE_TEXT = XML_TEXT_NODE,
944 NODE_TYPE_PI = XML_PI_NODE
945} xmlXPathTypeVal;
946
947typedef struct _xmlXPathStepOp xmlXPathStepOp;
948typedef xmlXPathStepOp *xmlXPathStepOpPtr;
949struct _xmlXPathStepOp {
950 xmlXPathOp op; /* The identifier of the operation */
951 int ch1; /* First child */
952 int ch2; /* Second child */
953 int value;
954 int value2;
955 int value3;
956 void *value4;
957 void *value5;
958 xmlXPathFunction cache;
959 void *cacheURI;
960};
961
962struct _xmlXPathCompExpr {
963 int nbStep; /* Number of steps in this expression */
964 int maxStep; /* Maximum number of steps allocated */
965 xmlXPathStepOp *steps; /* ops for computation of this expression */
966 int last; /* index of last step in expression */
967 xmlChar *expr; /* the expression being computed */
968 xmlDictPtr dict; /* the dictionary to use if any */
969#ifdef DEBUG_EVAL_COUNTS
970 int nb;
972#endif
973#ifdef XPATH_STREAMING
974 xmlPatternPtr stream;
975#endif
976};
977
978/************************************************************************
979 * *
980 * Forward declarations *
981 * *
982 ************************************************************************/
983static void
984xmlXPathFreeValueTree(xmlNodeSetPtr obj);
985static void
986xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
987static int
988xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
989 xmlXPathStepOpPtr op, xmlNodePtr *first);
990static int
991xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
992 xmlXPathStepOpPtr op,
993 int isPredicate);
994static void
995xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
996
997/************************************************************************
998 * *
999 * Parser Type functions *
1000 * *
1001 ************************************************************************/
1002
1010static xmlXPathCompExprPtr
1011xmlXPathNewCompExpr(void) {
1012 xmlXPathCompExprPtr cur;
1013
1014 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1015 if (cur == NULL) {
1016 xmlXPathErrMemory(NULL, "allocating component\n");
1017 return(NULL);
1018 }
1019 memset(cur, 0, sizeof(xmlXPathCompExpr));
1020 cur->maxStep = 10;
1021 cur->nbStep = 0;
1022 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1023 sizeof(xmlXPathStepOp));
1024 if (cur->steps == NULL) {
1025 xmlXPathErrMemory(NULL, "allocating steps\n");
1026 xmlFree(cur);
1027 return(NULL);
1028 }
1029 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1030 cur->last = -1;
1031#ifdef DEBUG_EVAL_COUNTS
1032 cur->nb = 0;
1033#endif
1034 return(cur);
1035}
1036
1043void
1044xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1045{
1046 xmlXPathStepOpPtr op;
1047 int i;
1048
1049 if (comp == NULL)
1050 return;
1051 if (comp->dict == NULL) {
1052 for (i = 0; i < comp->nbStep; i++) {
1053 op = &comp->steps[i];
1054 if (op->value4 != NULL) {
1055 if (op->op == XPATH_OP_VALUE)
1056 xmlXPathFreeObject(op->value4);
1057 else
1058 xmlFree(op->value4);
1059 }
1060 if (op->value5 != NULL)
1061 xmlFree(op->value5);
1062 }
1063 } else {
1064 for (i = 0; i < comp->nbStep; i++) {
1065 op = &comp->steps[i];
1066 if (op->value4 != NULL) {
1067 if (op->op == XPATH_OP_VALUE)
1068 xmlXPathFreeObject(op->value4);
1069 }
1070 }
1071 xmlDictFree(comp->dict);
1072 }
1073 if (comp->steps != NULL) {
1074 xmlFree(comp->steps);
1075 }
1076#ifdef DEBUG_EVAL_COUNTS
1077 if (comp->string != NULL) {
1078 xmlFree(comp->string);
1079 }
1080#endif
1081#ifdef XPATH_STREAMING
1082 if (comp->stream != NULL) {
1083 xmlFreePatternList(comp->stream);
1084 }
1085#endif
1086 if (comp->expr != NULL) {
1087 xmlFree(comp->expr);
1088 }
1089
1090 xmlFree(comp);
1091}
1092
1109static int
1110xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1111 xmlXPathOp op, int value,
1112 int value2, int value3, void *value4, void *value5) {
1113 xmlXPathCompExprPtr comp = ctxt->comp;
1114 if (comp->nbStep >= comp->maxStep) {
1115 xmlXPathStepOp *real;
1116
1117 if (comp->maxStep >= XPATH_MAX_STEPS) {
1118 xmlXPathPErrMemory(ctxt, "adding step\n");
1119 return(-1);
1120 }
1121 comp->maxStep *= 2;
1122 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1123 comp->maxStep * sizeof(xmlXPathStepOp));
1124 if (real == NULL) {
1125 comp->maxStep /= 2;
1126 xmlXPathPErrMemory(ctxt, "adding step\n");
1127 return(-1);
1128 }
1129 comp->steps = real;
1130 }
1131 comp->last = comp->nbStep;
1132 comp->steps[comp->nbStep].ch1 = ch1;
1133 comp->steps[comp->nbStep].ch2 = ch2;
1134 comp->steps[comp->nbStep].op = op;
1135 comp->steps[comp->nbStep].value = value;
1136 comp->steps[comp->nbStep].value2 = value2;
1137 comp->steps[comp->nbStep].value3 = value3;
1138 if ((comp->dict != NULL) &&
1139 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1140 (op == XPATH_OP_COLLECT))) {
1141 if (value4 != NULL) {
1142 comp->steps[comp->nbStep].value4 = (xmlChar *)
1143 (void *)xmlDictLookup(comp->dict, value4, -1);
1144 xmlFree(value4);
1145 } else
1146 comp->steps[comp->nbStep].value4 = NULL;
1147 if (value5 != NULL) {
1148 comp->steps[comp->nbStep].value5 = (xmlChar *)
1149 (void *)xmlDictLookup(comp->dict, value5, -1);
1150 xmlFree(value5);
1151 } else
1152 comp->steps[comp->nbStep].value5 = NULL;
1153 } else {
1154 comp->steps[comp->nbStep].value4 = value4;
1155 comp->steps[comp->nbStep].value5 = value5;
1156 }
1157 comp->steps[comp->nbStep].cache = NULL;
1158 return(comp->nbStep++);
1159}
1160
1168static void
1169xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1170 int tmp;
1171
1172#ifndef LIBXML_THREAD_ENABLED
1173 /*
1174 * Since this manipulates possibly shared variables, this is
1175 * disabled if one detects that the library is used in a multithreaded
1176 * application
1177 */
1178 if (xmlXPathDisableOptimizer)
1179 return;
1180#endif
1181
1182 tmp = op->ch1;
1183 op->ch1 = op->ch2;
1184 op->ch2 = tmp;
1185}
1186
1187#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1188 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1189 (op), (val), (val2), (val3), (val4), (val5))
1190#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1191 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1192 (op), (val), (val2), (val3), (val4), (val5))
1193
1194#define PUSH_LEAVE_EXPR(op, val, val2) \
1195xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1196
1197#define PUSH_UNARY_EXPR(op, ch, val, val2) \
1198xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1199
1200#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1201xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1202 (val), (val2), 0 ,NULL ,NULL)
1203
1204/************************************************************************
1205 * *
1206 * XPath object cache structures *
1207 * *
1208 ************************************************************************/
1209
1210/* #define XP_DEFAULT_CACHE_ON */
1211
1212#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1213
1214typedef struct _xmlXPathContextCache xmlXPathContextCache;
1215typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1216struct _xmlXPathContextCache {
1217 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1218 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1219 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1220 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1221 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1222 int maxNodeset;
1223 int maxString;
1224 int maxBoolean;
1225 int maxNumber;
1226 int maxMisc;
1227#ifdef XP_DEBUG_OBJ_USAGE
1228 int dbgCachedAll;
1229 int dbgCachedNodeset;
1230 int dbgCachedString;
1231 int dbgCachedBool;
1232 int dbgCachedNumber;
1233 int dbgCachedPoint;
1234 int dbgCachedRange;
1235 int dbgCachedLocset;
1236 int dbgCachedUsers;
1237 int dbgCachedXSLTTree;
1238 int dbgCachedUndefined;
1239
1240
1241 int dbgReusedAll;
1242 int dbgReusedNodeset;
1243 int dbgReusedString;
1244 int dbgReusedBool;
1245 int dbgReusedNumber;
1246 int dbgReusedPoint;
1247 int dbgReusedRange;
1248 int dbgReusedLocset;
1249 int dbgReusedUsers;
1250 int dbgReusedXSLTTree;
1251 int dbgReusedUndefined;
1252
1253#endif
1254};
1255
1256/************************************************************************
1257 * *
1258 * Debugging related functions *
1259 * *
1260 ************************************************************************/
1261
1262#define STRANGE \
1263 xmlGenericError(xmlGenericErrorContext, \
1264 "Internal error at %s:%d\n", \
1265 __FILE__, __LINE__);
1266
1267#ifdef LIBXML_DEBUG_ENABLED
1268static void
1269xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1270 int i;
1271 char shift[100];
1272
1273 for (i = 0;((i < depth) && (i < 25));i++)
1274 shift[2 * i] = shift[2 * i + 1] = ' ';
1275 shift[2 * i] = shift[2 * i + 1] = 0;
1276 if (cur == NULL) {
1277 fprintf(output, "%s", shift);
1278 fprintf(output, "Node is NULL !\n");
1279 return;
1280
1281 }
1282
1283 if ((cur->type == XML_DOCUMENT_NODE) ||
1284 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1285 fprintf(output, "%s", shift);
1286 fprintf(output, " /\n");
1287 } else if (cur->type == XML_ATTRIBUTE_NODE)
1288 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1289 else
1290 xmlDebugDumpOneNode(output, cur, depth);
1291}
1292static void
1293xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1294 xmlNodePtr tmp;
1295 int i;
1296 char shift[100];
1297
1298 for (i = 0;((i < depth) && (i < 25));i++)
1299 shift[2 * i] = shift[2 * i + 1] = ' ';
1300 shift[2 * i] = shift[2 * i + 1] = 0;
1301 if (cur == NULL) {
1302 fprintf(output, "%s", shift);
1303 fprintf(output, "Node is NULL !\n");
1304 return;
1305
1306 }
1307
1308 while (cur != NULL) {
1309 tmp = cur;
1310 cur = cur->next;
1311 xmlDebugDumpOneNode(output, tmp, depth);
1312 }
1313}
1314
1315static void
1316xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1317 int i;
1318 char shift[100];
1319
1320 for (i = 0;((i < depth) && (i < 25));i++)
1321 shift[2 * i] = shift[2 * i + 1] = ' ';
1322 shift[2 * i] = shift[2 * i + 1] = 0;
1323
1324 if (cur == NULL) {
1325 fprintf(output, "%s", shift);
1326 fprintf(output, "NodeSet is NULL !\n");
1327 return;
1328
1329 }
1330
1331 if (cur != NULL) {
1332 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1333 for (i = 0;i < cur->nodeNr;i++) {
1334 fprintf(output, "%s", shift);
1335 fprintf(output, "%d", i + 1);
1336 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1337 }
1338 }
1339}
1340
1341static void
1342xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1343 int i;
1344 char shift[100];
1345
1346 for (i = 0;((i < depth) && (i < 25));i++)
1347 shift[2 * i] = shift[2 * i + 1] = ' ';
1348 shift[2 * i] = shift[2 * i + 1] = 0;
1349
1350 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1351 fprintf(output, "%s", shift);
1352 fprintf(output, "Value Tree is NULL !\n");
1353 return;
1354
1355 }
1356
1357 fprintf(output, "%s", shift);
1358 fprintf(output, "%d", i + 1);
1359 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1360}
1361#if defined(LIBXML_XPTR_LOCS_ENABLED)
1362static void
1363xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1364 int i;
1365 char shift[100];
1366
1367 for (i = 0;((i < depth) && (i < 25));i++)
1368 shift[2 * i] = shift[2 * i + 1] = ' ';
1369 shift[2 * i] = shift[2 * i + 1] = 0;
1370
1371 if (cur == NULL) {
1372 fprintf(output, "%s", shift);
1373 fprintf(output, "LocationSet is NULL !\n");
1374 return;
1375
1376 }
1377
1378 for (i = 0;i < cur->locNr;i++) {
1379 fprintf(output, "%s", shift);
1380 fprintf(output, "%d : ", i + 1);
1381 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1382 }
1383}
1384#endif /* LIBXML_XPTR_LOCS_ENABLED */
1385
1394void
1395xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1396 int i;
1397 char shift[100];
1398
1399 if (output == NULL) return;
1400
1401 for (i = 0;((i < depth) && (i < 25));i++)
1402 shift[2 * i] = shift[2 * i + 1] = ' ';
1403 shift[2 * i] = shift[2 * i + 1] = 0;
1404
1405
1406 fprintf(output, "%s", shift);
1407
1408 if (cur == NULL) {
1409 fprintf(output, "Object is empty (NULL)\n");
1410 return;
1411 }
1412 switch(cur->type) {
1413 case XPATH_UNDEFINED:
1414 fprintf(output, "Object is uninitialized\n");
1415 break;
1416 case XPATH_NODESET:
1417 fprintf(output, "Object is a Node Set :\n");
1418 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1419 break;
1420 case XPATH_XSLT_TREE:
1421 fprintf(output, "Object is an XSLT value tree :\n");
1422 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1423 break;
1424 case XPATH_BOOLEAN:
1425 fprintf(output, "Object is a Boolean : ");
1426 if (cur->boolval) fprintf(output, "true\n");
1427 else fprintf(output, "false\n");
1428 break;
1429 case XPATH_NUMBER:
1430 switch (xmlXPathIsInf(cur->floatval)) {
1431 case 1:
1432 fprintf(output, "Object is a number : Infinity\n");
1433 break;
1434 case -1:
1435 fprintf(output, "Object is a number : -Infinity\n");
1436 break;
1437 default:
1438 if (xmlXPathIsNaN(cur->floatval)) {
1439 fprintf(output, "Object is a number : NaN\n");
1440 } else if (cur->floatval == 0) {
1441 /* Omit sign for negative zero. */
1442 fprintf(output, "Object is a number : 0\n");
1443 } else {
1444 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1445 }
1446 }
1447 break;
1448 case XPATH_STRING:
1449 fprintf(output, "Object is a string : ");
1450 xmlDebugDumpString(output, cur->stringval);
1451 fprintf(output, "\n");
1452 break;
1453#ifdef LIBXML_XPTR_LOCS_ENABLED
1454 case XPATH_POINT:
1455 fprintf(output, "Object is a point : index %d in node", cur->index);
1456 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1457 fprintf(output, "\n");
1458 break;
1459 case XPATH_RANGE:
1460 if ((cur->user2 == NULL) ||
1461 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1462 fprintf(output, "Object is a collapsed range :\n");
1463 fprintf(output, "%s", shift);
1464 if (cur->index >= 0)
1465 fprintf(output, "index %d in ", cur->index);
1466 fprintf(output, "node\n");
1467 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1468 depth + 1);
1469 } else {
1470 fprintf(output, "Object is a range :\n");
1471 fprintf(output, "%s", shift);
1472 fprintf(output, "From ");
1473 if (cur->index >= 0)
1474 fprintf(output, "index %d in ", cur->index);
1475 fprintf(output, "node\n");
1476 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1477 depth + 1);
1478 fprintf(output, "%s", shift);
1479 fprintf(output, "To ");
1480 if (cur->index2 >= 0)
1481 fprintf(output, "index %d in ", cur->index2);
1482 fprintf(output, "node\n");
1483 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1484 depth + 1);
1485 fprintf(output, "\n");
1486 }
1487 break;
1488 case XPATH_LOCATIONSET:
1489 fprintf(output, "Object is a Location Set:\n");
1490 xmlXPathDebugDumpLocationSet(output,
1491 (xmlLocationSetPtr) cur->user, depth);
1492 break;
1493#endif /* LIBXML_XPTR_LOCS_ENABLED */
1494 case XPATH_USERS:
1495 fprintf(output, "Object is user defined\n");
1496 break;
1497 }
1498}
1499
1500static void
1501xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1502 xmlXPathStepOpPtr op, int depth) {
1503 int i;
1504 char shift[100];
1505
1506 for (i = 0;((i < depth) && (i < 25));i++)
1507 shift[2 * i] = shift[2 * i + 1] = ' ';
1508 shift[2 * i] = shift[2 * i + 1] = 0;
1509
1510 fprintf(output, "%s", shift);
1511 if (op == NULL) {
1512 fprintf(output, "Step is NULL\n");
1513 return;
1514 }
1515 switch (op->op) {
1516 case XPATH_OP_END:
1517 fprintf(output, "END"); break;
1518 case XPATH_OP_AND:
1519 fprintf(output, "AND"); break;
1520 case XPATH_OP_OR:
1521 fprintf(output, "OR"); break;
1522 case XPATH_OP_EQUAL:
1523 if (op->value)
1524 fprintf(output, "EQUAL =");
1525 else
1526 fprintf(output, "EQUAL !=");
1527 break;
1528 case XPATH_OP_CMP:
1529 if (op->value)
1530 fprintf(output, "CMP <");
1531 else
1532 fprintf(output, "CMP >");
1533 if (!op->value2)
1534 fprintf(output, "=");
1535 break;
1536 case XPATH_OP_PLUS:
1537 if (op->value == 0)
1538 fprintf(output, "PLUS -");
1539 else if (op->value == 1)
1540 fprintf(output, "PLUS +");
1541 else if (op->value == 2)
1542 fprintf(output, "PLUS unary -");
1543 else if (op->value == 3)
1544 fprintf(output, "PLUS unary - -");
1545 break;
1546 case XPATH_OP_MULT:
1547 if (op->value == 0)
1548 fprintf(output, "MULT *");
1549 else if (op->value == 1)
1550 fprintf(output, "MULT div");
1551 else
1552 fprintf(output, "MULT mod");
1553 break;
1554 case XPATH_OP_UNION:
1555 fprintf(output, "UNION"); break;
1556 case XPATH_OP_ROOT:
1557 fprintf(output, "ROOT"); break;
1558 case XPATH_OP_NODE:
1559 fprintf(output, "NODE"); break;
1560 case XPATH_OP_SORT:
1561 fprintf(output, "SORT"); break;
1562 case XPATH_OP_COLLECT: {
1563 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1564 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1565 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1566 const xmlChar *prefix = op->value4;
1567 const xmlChar *name = op->value5;
1568
1569 fprintf(output, "COLLECT ");
1570 switch (axis) {
1571 case AXIS_ANCESTOR:
1572 fprintf(output, " 'ancestors' "); break;
1573 case AXIS_ANCESTOR_OR_SELF:
1574 fprintf(output, " 'ancestors-or-self' "); break;
1575 case AXIS_ATTRIBUTE:
1576 fprintf(output, " 'attributes' "); break;
1577 case AXIS_CHILD:
1578 fprintf(output, " 'child' "); break;
1579 case AXIS_DESCENDANT:
1580 fprintf(output, " 'descendant' "); break;
1581 case AXIS_DESCENDANT_OR_SELF:
1582 fprintf(output, " 'descendant-or-self' "); break;
1583 case AXIS_FOLLOWING:
1584 fprintf(output, " 'following' "); break;
1585 case AXIS_FOLLOWING_SIBLING:
1586 fprintf(output, " 'following-siblings' "); break;
1587 case AXIS_NAMESPACE:
1588 fprintf(output, " 'namespace' "); break;
1589 case AXIS_PARENT:
1590 fprintf(output, " 'parent' "); break;
1591 case AXIS_PRECEDING:
1592 fprintf(output, " 'preceding' "); break;
1593 case AXIS_PRECEDING_SIBLING:
1594 fprintf(output, " 'preceding-sibling' "); break;
1595 case AXIS_SELF:
1596 fprintf(output, " 'self' "); break;
1597 }
1598 switch (test) {
1599 case NODE_TEST_NONE:
1600 fprintf(output, "'none' "); break;
1601 case NODE_TEST_TYPE:
1602 fprintf(output, "'type' "); break;
1603 case NODE_TEST_PI:
1604 fprintf(output, "'PI' "); break;
1605 case NODE_TEST_ALL:
1606 fprintf(output, "'all' "); break;
1607 case NODE_TEST_NS:
1608 fprintf(output, "'namespace' "); break;
1609 case NODE_TEST_NAME:
1610 fprintf(output, "'name' "); break;
1611 }
1612 switch (type) {
1613 case NODE_TYPE_NODE:
1614 fprintf(output, "'node' "); break;
1615 case NODE_TYPE_COMMENT:
1616 fprintf(output, "'comment' "); break;
1617 case NODE_TYPE_TEXT:
1618 fprintf(output, "'text' "); break;
1619 case NODE_TYPE_PI:
1620 fprintf(output, "'PI' "); break;
1621 }
1622 if (prefix != NULL)
1623 fprintf(output, "%s:", prefix);
1624 if (name != NULL)
1625 fprintf(output, "%s", (const char *) name);
1626 break;
1627
1628 }
1629 case XPATH_OP_VALUE: {
1630 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1631
1632 fprintf(output, "ELEM ");
1633 xmlXPathDebugDumpObject(output, object, 0);
1634 goto finish;
1635 }
1636 case XPATH_OP_VARIABLE: {
1637 const xmlChar *prefix = op->value5;
1638 const xmlChar *name = op->value4;
1639
1640 if (prefix != NULL)
1641 fprintf(output, "VARIABLE %s:%s", prefix, name);
1642 else
1643 fprintf(output, "VARIABLE %s", name);
1644 break;
1645 }
1646 case XPATH_OP_FUNCTION: {
1647 int nbargs = op->value;
1648 const xmlChar *prefix = op->value5;
1649 const xmlChar *name = op->value4;
1650
1651 if (prefix != NULL)
1652 fprintf(output, "FUNCTION %s:%s(%d args)",
1653 prefix, name, nbargs);
1654 else
1655 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1656 break;
1657 }
1658 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1659 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1660 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1661#ifdef LIBXML_XPTR_LOCS_ENABLED
1662 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1663#endif
1664 default:
1665 fprintf(output, "UNKNOWN %d\n", op->op); return;
1666 }
1667 fprintf(output, "\n");
1668finish:
1669 if (op->ch1 >= 0)
1670 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1671 if (op->ch2 >= 0)
1672 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1673}
1674
1683void
1684xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1685 int depth) {
1686 int i;
1687 char shift[100];
1688
1689 if ((output == NULL) || (comp == NULL)) return;
1690
1691 for (i = 0;((i < depth) && (i < 25));i++)
1692 shift[2 * i] = shift[2 * i + 1] = ' ';
1693 shift[2 * i] = shift[2 * i + 1] = 0;
1694
1695 fprintf(output, "%s", shift);
1696
1697#ifdef XPATH_STREAMING
1698 if (comp->stream) {
1699 fprintf(output, "Streaming Expression\n");
1700 } else
1701#endif
1702 {
1703 fprintf(output, "Compiled Expression : %d elements\n",
1704 comp->nbStep);
1705 i = comp->last;
1706 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1707 }
1708}
1709
1710#ifdef XP_DEBUG_OBJ_USAGE
1711
1712/*
1713* XPath object usage related debugging variables.
1714*/
1715static int xmlXPathDebugObjCounterUndefined = 0;
1716static int xmlXPathDebugObjCounterNodeset = 0;
1717static int xmlXPathDebugObjCounterBool = 0;
1718static int xmlXPathDebugObjCounterNumber = 0;
1719static int xmlXPathDebugObjCounterString = 0;
1720static int xmlXPathDebugObjCounterPoint = 0;
1721static int xmlXPathDebugObjCounterRange = 0;
1722static int xmlXPathDebugObjCounterLocset = 0;
1723static int xmlXPathDebugObjCounterUsers = 0;
1724static int xmlXPathDebugObjCounterXSLTTree = 0;
1725static int xmlXPathDebugObjCounterAll = 0;
1726
1727static int xmlXPathDebugObjTotalUndefined = 0;
1728static int xmlXPathDebugObjTotalNodeset = 0;
1729static int xmlXPathDebugObjTotalBool = 0;
1730static int xmlXPathDebugObjTotalNumber = 0;
1731static int xmlXPathDebugObjTotalString = 0;
1732static int xmlXPathDebugObjTotalPoint = 0;
1733static int xmlXPathDebugObjTotalRange = 0;
1734static int xmlXPathDebugObjTotalLocset = 0;
1735static int xmlXPathDebugObjTotalUsers = 0;
1736static int xmlXPathDebugObjTotalXSLTTree = 0;
1737static int xmlXPathDebugObjTotalAll = 0;
1738
1739static int xmlXPathDebugObjMaxUndefined = 0;
1740static int xmlXPathDebugObjMaxNodeset = 0;
1741static int xmlXPathDebugObjMaxBool = 0;
1742static int xmlXPathDebugObjMaxNumber = 0;
1743static int xmlXPathDebugObjMaxString = 0;
1744static int xmlXPathDebugObjMaxPoint = 0;
1745static int xmlXPathDebugObjMaxRange = 0;
1746static int xmlXPathDebugObjMaxLocset = 0;
1747static int xmlXPathDebugObjMaxUsers = 0;
1748static int xmlXPathDebugObjMaxXSLTTree = 0;
1749static int xmlXPathDebugObjMaxAll = 0;
1750
1751static void
1752xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1753{
1754 if (ctxt != NULL) {
1755 if (ctxt->cache != NULL) {
1756 xmlXPathContextCachePtr cache =
1757 (xmlXPathContextCachePtr) ctxt->cache;
1758
1759 cache->dbgCachedAll = 0;
1760 cache->dbgCachedNodeset = 0;
1761 cache->dbgCachedString = 0;
1762 cache->dbgCachedBool = 0;
1763 cache->dbgCachedNumber = 0;
1764 cache->dbgCachedPoint = 0;
1765 cache->dbgCachedRange = 0;
1766 cache->dbgCachedLocset = 0;
1767 cache->dbgCachedUsers = 0;
1768 cache->dbgCachedXSLTTree = 0;
1769 cache->dbgCachedUndefined = 0;
1770
1771 cache->dbgReusedAll = 0;
1772 cache->dbgReusedNodeset = 0;
1773 cache->dbgReusedString = 0;
1774 cache->dbgReusedBool = 0;
1775 cache->dbgReusedNumber = 0;
1776 cache->dbgReusedPoint = 0;
1777 cache->dbgReusedRange = 0;
1778 cache->dbgReusedLocset = 0;
1779 cache->dbgReusedUsers = 0;
1780 cache->dbgReusedXSLTTree = 0;
1781 cache->dbgReusedUndefined = 0;
1782 }
1783 }
1784
1785 xmlXPathDebugObjCounterUndefined = 0;
1786 xmlXPathDebugObjCounterNodeset = 0;
1787 xmlXPathDebugObjCounterBool = 0;
1788 xmlXPathDebugObjCounterNumber = 0;
1789 xmlXPathDebugObjCounterString = 0;
1790 xmlXPathDebugObjCounterPoint = 0;
1791 xmlXPathDebugObjCounterRange = 0;
1792 xmlXPathDebugObjCounterLocset = 0;
1793 xmlXPathDebugObjCounterUsers = 0;
1794 xmlXPathDebugObjCounterXSLTTree = 0;
1795 xmlXPathDebugObjCounterAll = 0;
1796
1797 xmlXPathDebugObjTotalUndefined = 0;
1798 xmlXPathDebugObjTotalNodeset = 0;
1799 xmlXPathDebugObjTotalBool = 0;
1800 xmlXPathDebugObjTotalNumber = 0;
1801 xmlXPathDebugObjTotalString = 0;
1802 xmlXPathDebugObjTotalPoint = 0;
1803 xmlXPathDebugObjTotalRange = 0;
1804 xmlXPathDebugObjTotalLocset = 0;
1805 xmlXPathDebugObjTotalUsers = 0;
1806 xmlXPathDebugObjTotalXSLTTree = 0;
1807 xmlXPathDebugObjTotalAll = 0;
1808
1809 xmlXPathDebugObjMaxUndefined = 0;
1810 xmlXPathDebugObjMaxNodeset = 0;
1811 xmlXPathDebugObjMaxBool = 0;
1812 xmlXPathDebugObjMaxNumber = 0;
1813 xmlXPathDebugObjMaxString = 0;
1814 xmlXPathDebugObjMaxPoint = 0;
1815 xmlXPathDebugObjMaxRange = 0;
1816 xmlXPathDebugObjMaxLocset = 0;
1817 xmlXPathDebugObjMaxUsers = 0;
1818 xmlXPathDebugObjMaxXSLTTree = 0;
1819 xmlXPathDebugObjMaxAll = 0;
1820
1821}
1822
1823static void
1824xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1825 xmlXPathObjectType objType)
1826{
1827 int isCached = 0;
1828
1829 if (ctxt != NULL) {
1830 if (ctxt->cache != NULL) {
1831 xmlXPathContextCachePtr cache =
1832 (xmlXPathContextCachePtr) ctxt->cache;
1833
1834 isCached = 1;
1835
1836 cache->dbgReusedAll++;
1837 switch (objType) {
1838 case XPATH_UNDEFINED:
1839 cache->dbgReusedUndefined++;
1840 break;
1841 case XPATH_NODESET:
1842 cache->dbgReusedNodeset++;
1843 break;
1844 case XPATH_BOOLEAN:
1845 cache->dbgReusedBool++;
1846 break;
1847 case XPATH_NUMBER:
1848 cache->dbgReusedNumber++;
1849 break;
1850 case XPATH_STRING:
1851 cache->dbgReusedString++;
1852 break;
1853#ifdef LIBXML_XPTR_LOCS_ENABLED
1854 case XPATH_POINT:
1855 cache->dbgReusedPoint++;
1856 break;
1857 case XPATH_RANGE:
1858 cache->dbgReusedRange++;
1859 break;
1860 case XPATH_LOCATIONSET:
1861 cache->dbgReusedLocset++;
1862 break;
1863#endif /* LIBXML_XPTR_LOCS_ENABLED */
1864 case XPATH_USERS:
1865 cache->dbgReusedUsers++;
1866 break;
1867 case XPATH_XSLT_TREE:
1868 cache->dbgReusedXSLTTree++;
1869 break;
1870 default:
1871 break;
1872 }
1873 }
1874 }
1875
1876 switch (objType) {
1877 case XPATH_UNDEFINED:
1878 if (! isCached)
1879 xmlXPathDebugObjTotalUndefined++;
1880 xmlXPathDebugObjCounterUndefined++;
1881 if (xmlXPathDebugObjCounterUndefined >
1882 xmlXPathDebugObjMaxUndefined)
1883 xmlXPathDebugObjMaxUndefined =
1884 xmlXPathDebugObjCounterUndefined;
1885 break;
1886 case XPATH_NODESET:
1887 if (! isCached)
1888 xmlXPathDebugObjTotalNodeset++;
1889 xmlXPathDebugObjCounterNodeset++;
1890 if (xmlXPathDebugObjCounterNodeset >
1891 xmlXPathDebugObjMaxNodeset)
1892 xmlXPathDebugObjMaxNodeset =
1893 xmlXPathDebugObjCounterNodeset;
1894 break;
1895 case XPATH_BOOLEAN:
1896 if (! isCached)
1897 xmlXPathDebugObjTotalBool++;
1898 xmlXPathDebugObjCounterBool++;
1899 if (xmlXPathDebugObjCounterBool >
1900 xmlXPathDebugObjMaxBool)
1901 xmlXPathDebugObjMaxBool =
1902 xmlXPathDebugObjCounterBool;
1903 break;
1904 case XPATH_NUMBER:
1905 if (! isCached)
1906 xmlXPathDebugObjTotalNumber++;
1907 xmlXPathDebugObjCounterNumber++;
1908 if (xmlXPathDebugObjCounterNumber >
1909 xmlXPathDebugObjMaxNumber)
1910 xmlXPathDebugObjMaxNumber =
1911 xmlXPathDebugObjCounterNumber;
1912 break;
1913 case XPATH_STRING:
1914 if (! isCached)
1915 xmlXPathDebugObjTotalString++;
1916 xmlXPathDebugObjCounterString++;
1917 if (xmlXPathDebugObjCounterString >
1918 xmlXPathDebugObjMaxString)
1919 xmlXPathDebugObjMaxString =
1920 xmlXPathDebugObjCounterString;
1921 break;
1922#ifdef LIBXML_XPTR_LOCS_ENABLED
1923 case XPATH_POINT:
1924 if (! isCached)
1925 xmlXPathDebugObjTotalPoint++;
1926 xmlXPathDebugObjCounterPoint++;
1927 if (xmlXPathDebugObjCounterPoint >
1928 xmlXPathDebugObjMaxPoint)
1929 xmlXPathDebugObjMaxPoint =
1930 xmlXPathDebugObjCounterPoint;
1931 break;
1932 case XPATH_RANGE:
1933 if (! isCached)
1934 xmlXPathDebugObjTotalRange++;
1935 xmlXPathDebugObjCounterRange++;
1936 if (xmlXPathDebugObjCounterRange >
1937 xmlXPathDebugObjMaxRange)
1938 xmlXPathDebugObjMaxRange =
1939 xmlXPathDebugObjCounterRange;
1940 break;
1941 case XPATH_LOCATIONSET:
1942 if (! isCached)
1943 xmlXPathDebugObjTotalLocset++;
1944 xmlXPathDebugObjCounterLocset++;
1945 if (xmlXPathDebugObjCounterLocset >
1946 xmlXPathDebugObjMaxLocset)
1947 xmlXPathDebugObjMaxLocset =
1948 xmlXPathDebugObjCounterLocset;
1949 break;
1950#endif /* LIBXML_XPTR_LOCS_ENABLED */
1951 case XPATH_USERS:
1952 if (! isCached)
1953 xmlXPathDebugObjTotalUsers++;
1954 xmlXPathDebugObjCounterUsers++;
1955 if (xmlXPathDebugObjCounterUsers >
1956 xmlXPathDebugObjMaxUsers)
1957 xmlXPathDebugObjMaxUsers =
1958 xmlXPathDebugObjCounterUsers;
1959 break;
1960 case XPATH_XSLT_TREE:
1961 if (! isCached)
1962 xmlXPathDebugObjTotalXSLTTree++;
1963 xmlXPathDebugObjCounterXSLTTree++;
1964 if (xmlXPathDebugObjCounterXSLTTree >
1965 xmlXPathDebugObjMaxXSLTTree)
1966 xmlXPathDebugObjMaxXSLTTree =
1967 xmlXPathDebugObjCounterXSLTTree;
1968 break;
1969 default:
1970 break;
1971 }
1972 if (! isCached)
1973 xmlXPathDebugObjTotalAll++;
1974 xmlXPathDebugObjCounterAll++;
1975 if (xmlXPathDebugObjCounterAll >
1976 xmlXPathDebugObjMaxAll)
1977 xmlXPathDebugObjMaxAll =
1978 xmlXPathDebugObjCounterAll;
1979}
1980
1981static void
1982xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1983 xmlXPathObjectType objType)
1984{
1985 int isCached = 0;
1986
1987 if (ctxt != NULL) {
1988 if (ctxt->cache != NULL) {
1989 xmlXPathContextCachePtr cache =
1990 (xmlXPathContextCachePtr) ctxt->cache;
1991
1992 isCached = 1;
1993
1994 cache->dbgCachedAll++;
1995 switch (objType) {
1996 case XPATH_UNDEFINED:
1997 cache->dbgCachedUndefined++;
1998 break;
1999 case XPATH_NODESET:
2000 cache->dbgCachedNodeset++;
2001 break;
2002 case XPATH_BOOLEAN:
2003 cache->dbgCachedBool++;
2004 break;
2005 case XPATH_NUMBER:
2006 cache->dbgCachedNumber++;
2007 break;
2008 case XPATH_STRING:
2009 cache->dbgCachedString++;
2010 break;
2011#ifdef LIBXML_XPTR_LOCS_ENABLED
2012 case XPATH_POINT:
2013 cache->dbgCachedPoint++;
2014 break;
2015 case XPATH_RANGE:
2016 cache->dbgCachedRange++;
2017 break;
2018 case XPATH_LOCATIONSET:
2019 cache->dbgCachedLocset++;
2020 break;
2021#endif /* LIBXML_XPTR_LOCS_ENABLED */
2022 case XPATH_USERS:
2023 cache->dbgCachedUsers++;
2024 break;
2025 case XPATH_XSLT_TREE:
2026 cache->dbgCachedXSLTTree++;
2027 break;
2028 default:
2029 break;
2030 }
2031
2032 }
2033 }
2034 switch (objType) {
2035 case XPATH_UNDEFINED:
2036 xmlXPathDebugObjCounterUndefined--;
2037 break;
2038 case XPATH_NODESET:
2039 xmlXPathDebugObjCounterNodeset--;
2040 break;
2041 case XPATH_BOOLEAN:
2042 xmlXPathDebugObjCounterBool--;
2043 break;
2044 case XPATH_NUMBER:
2045 xmlXPathDebugObjCounterNumber--;
2046 break;
2047 case XPATH_STRING:
2048 xmlXPathDebugObjCounterString--;
2049 break;
2050#ifdef LIBXML_XPTR_LOCS_ENABLED
2051 case XPATH_POINT:
2052 xmlXPathDebugObjCounterPoint--;
2053 break;
2054 case XPATH_RANGE:
2055 xmlXPathDebugObjCounterRange--;
2056 break;
2057 case XPATH_LOCATIONSET:
2058 xmlXPathDebugObjCounterLocset--;
2059 break;
2060#endif /* LIBXML_XPTR_LOCS_ENABLED */
2061 case XPATH_USERS:
2062 xmlXPathDebugObjCounterUsers--;
2063 break;
2064 case XPATH_XSLT_TREE:
2065 xmlXPathDebugObjCounterXSLTTree--;
2066 break;
2067 default:
2068 break;
2069 }
2070 xmlXPathDebugObjCounterAll--;
2071}
2072
2073static void
2074xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2075{
2076 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2077 reqXSLTTree, reqUndefined;
2078 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2079 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2080 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2081 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2082 int leftObjs = xmlXPathDebugObjCounterAll;
2083
2084 reqAll = xmlXPathDebugObjTotalAll;
2085 reqNodeset = xmlXPathDebugObjTotalNodeset;
2086 reqString = xmlXPathDebugObjTotalString;
2087 reqBool = xmlXPathDebugObjTotalBool;
2088 reqNumber = xmlXPathDebugObjTotalNumber;
2089 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2090 reqUndefined = xmlXPathDebugObjTotalUndefined;
2091
2092 printf("# XPath object usage:\n");
2093
2094 if (ctxt != NULL) {
2095 if (ctxt->cache != NULL) {
2096 xmlXPathContextCachePtr cache =
2097 (xmlXPathContextCachePtr) ctxt->cache;
2098
2099 reAll = cache->dbgReusedAll;
2100 reqAll += reAll;
2101 reNodeset = cache->dbgReusedNodeset;
2102 reqNodeset += reNodeset;
2103 reString = cache->dbgReusedString;
2104 reqString += reString;
2105 reBool = cache->dbgReusedBool;
2106 reqBool += reBool;
2107 reNumber = cache->dbgReusedNumber;
2108 reqNumber += reNumber;
2109 reXSLTTree = cache->dbgReusedXSLTTree;
2110 reqXSLTTree += reXSLTTree;
2111 reUndefined = cache->dbgReusedUndefined;
2112 reqUndefined += reUndefined;
2113
2114 caAll = cache->dbgCachedAll;
2115 caBool = cache->dbgCachedBool;
2116 caNodeset = cache->dbgCachedNodeset;
2117 caString = cache->dbgCachedString;
2118 caNumber = cache->dbgCachedNumber;
2119 caXSLTTree = cache->dbgCachedXSLTTree;
2120 caUndefined = cache->dbgCachedUndefined;
2121
2122 if (cache->nodesetObjs)
2123 leftObjs -= cache->nodesetObjs->number;
2124 if (cache->stringObjs)
2125 leftObjs -= cache->stringObjs->number;
2126 if (cache->booleanObjs)
2127 leftObjs -= cache->booleanObjs->number;
2128 if (cache->numberObjs)
2129 leftObjs -= cache->numberObjs->number;
2130 if (cache->miscObjs)
2131 leftObjs -= cache->miscObjs->number;
2132 }
2133 }
2134
2135 printf("# all\n");
2136 printf("# total : %d\n", reqAll);
2137 printf("# left : %d\n", leftObjs);
2138 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2139 printf("# reused : %d\n", reAll);
2140 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2141
2142 printf("# node-sets\n");
2143 printf("# total : %d\n", reqNodeset);
2144 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2145 printf("# reused : %d\n", reNodeset);
2146 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2147
2148 printf("# strings\n");
2149 printf("# total : %d\n", reqString);
2150 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2151 printf("# reused : %d\n", reString);
2152 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2153
2154 printf("# booleans\n");
2155 printf("# total : %d\n", reqBool);
2156 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2157 printf("# reused : %d\n", reBool);
2158 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2159
2160 printf("# numbers\n");
2161 printf("# total : %d\n", reqNumber);
2162 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2163 printf("# reused : %d\n", reNumber);
2164 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2165
2166 printf("# XSLT result tree fragments\n");
2167 printf("# total : %d\n", reqXSLTTree);
2168 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2169 printf("# reused : %d\n", reXSLTTree);
2170 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2171
2172 printf("# undefined\n");
2173 printf("# total : %d\n", reqUndefined);
2174 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2175 printf("# reused : %d\n", reUndefined);
2176 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2177
2178}
2179
2180#endif /* XP_DEBUG_OBJ_USAGE */
2181
2182#endif /* LIBXML_DEBUG_ENABLED */
2183
2184/************************************************************************
2185 * *
2186 * XPath object caching *
2187 * *
2188 ************************************************************************/
2189
2197static xmlXPathContextCachePtr
2198xmlXPathNewCache(void)
2199{
2200 xmlXPathContextCachePtr ret;
2201
2202 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2203 if (ret == NULL) {
2204 xmlXPathErrMemory(NULL, "creating object cache\n");
2205 return(NULL);
2206 }
2207 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2208 ret->maxNodeset = 100;
2209 ret->maxString = 100;
2210 ret->maxBoolean = 100;
2211 ret->maxNumber = 100;
2212 ret->maxMisc = 100;
2213 return(ret);
2214}
2215
2216static void
2217xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2218{
2219 int i;
2220 xmlXPathObjectPtr obj;
2221
2222 if (list == NULL)
2223 return;
2224
2225 for (i = 0; i < list->number; i++) {
2226 obj = list->items[i];
2227 /*
2228 * Note that it is already assured that we don't need to
2229 * look out for namespace nodes in the node-set.
2230 */
2231 if (obj->nodesetval != NULL) {
2232 if (obj->nodesetval->nodeTab != NULL)
2233 xmlFree(obj->nodesetval->nodeTab);
2234 xmlFree(obj->nodesetval);
2235 }
2236 xmlFree(obj);
2237#ifdef XP_DEBUG_OBJ_USAGE
2238 xmlXPathDebugObjCounterAll--;
2239#endif
2240 }
2241 xmlPointerListFree(list);
2242}
2243
2244static void
2245xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2246{
2247 if (cache == NULL)
2248 return;
2249 if (cache->nodesetObjs)
2250 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2251 if (cache->stringObjs)
2252 xmlXPathCacheFreeObjectList(cache->stringObjs);
2253 if (cache->booleanObjs)
2254 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2255 if (cache->numberObjs)
2256 xmlXPathCacheFreeObjectList(cache->numberObjs);
2257 if (cache->miscObjs)
2258 xmlXPathCacheFreeObjectList(cache->miscObjs);
2259 xmlFree(cache);
2260}
2261
2284int
2285xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2286 int active,
2287 int value,
2288 int options)
2289{
2290 if (ctxt == NULL)
2291 return(-1);
2292 if (active) {
2293 xmlXPathContextCachePtr cache;
2294
2295 if (ctxt->cache == NULL) {
2296 ctxt->cache = xmlXPathNewCache();
2297 if (ctxt->cache == NULL)
2298 return(-1);
2299 }
2300 cache = (xmlXPathContextCachePtr) ctxt->cache;
2301 if (options == 0) {
2302 if (value < 0)
2303 value = 100;
2304 cache->maxNodeset = value;
2305 cache->maxString = value;
2306 cache->maxNumber = value;
2307 cache->maxBoolean = value;
2308 cache->maxMisc = value;
2309 }
2310 } else if (ctxt->cache != NULL) {
2311 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2312 ctxt->cache = NULL;
2313 }
2314 return(0);
2315}
2316
2327static xmlXPathObjectPtr
2328xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2329{
2330 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2331 xmlXPathContextCachePtr cache =
2332 (xmlXPathContextCachePtr) ctxt->cache;
2333
2334 if ((cache->miscObjs != NULL) &&
2335 (cache->miscObjs->number != 0))
2336 {
2337 xmlXPathObjectPtr ret;
2338
2339 ret = (xmlXPathObjectPtr)
2340 cache->miscObjs->items[--cache->miscObjs->number];
2341 ret->type = XPATH_NODESET;
2342 ret->nodesetval = val;
2343#ifdef XP_DEBUG_OBJ_USAGE
2344 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2345#endif
2346 return(ret);
2347 }
2348 }
2349
2350 return(xmlXPathWrapNodeSet(val));
2351
2352}
2353
2364static xmlXPathObjectPtr
2365xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2366{
2367 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2368 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2369
2370 if ((cache->stringObjs != NULL) &&
2371 (cache->stringObjs->number != 0))
2372 {
2373
2374 xmlXPathObjectPtr ret;
2375
2376 ret = (xmlXPathObjectPtr)
2377 cache->stringObjs->items[--cache->stringObjs->number];
2378 ret->type = XPATH_STRING;
2379 ret->stringval = val;
2380#ifdef XP_DEBUG_OBJ_USAGE
2381 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2382#endif
2383 return(ret);
2384 } else if ((cache->miscObjs != NULL) &&
2385 (cache->miscObjs->number != 0))
2386 {
2387 xmlXPathObjectPtr ret;
2388 /*
2389 * Fallback to misc-cache.
2390 */
2391 ret = (xmlXPathObjectPtr)
2392 cache->miscObjs->items[--cache->miscObjs->number];
2393
2394 ret->type = XPATH_STRING;
2395 ret->stringval = val;
2396#ifdef XP_DEBUG_OBJ_USAGE
2397 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2398#endif
2399 return(ret);
2400 }
2401 }
2402 return(xmlXPathWrapString(val));
2403}
2404
2416static xmlXPathObjectPtr
2417xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2418{
2419 if ((ctxt != NULL) && (ctxt->cache)) {
2420 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2421
2422 if ((cache->nodesetObjs != NULL) &&
2423 (cache->nodesetObjs->number != 0))
2424 {
2425 xmlXPathObjectPtr ret;
2426 /*
2427 * Use the nodeset-cache.
2428 */
2429 ret = (xmlXPathObjectPtr)
2430 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2431 ret->type = XPATH_NODESET;
2432 ret->boolval = 0;
2433 if (val) {
2434 if ((ret->nodesetval->nodeMax == 0) ||
2435 (val->type == XML_NAMESPACE_DECL))
2436 {
2437 /* TODO: Check memory error. */
2438 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2439 } else {
2440 ret->nodesetval->nodeTab[0] = val;
2441 ret->nodesetval->nodeNr = 1;
2442 }
2443 }
2444#ifdef XP_DEBUG_OBJ_USAGE
2445 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2446#endif
2447 return(ret);
2448 } else if ((cache->miscObjs != NULL) &&
2449 (cache->miscObjs->number != 0))
2450 {
2451 xmlXPathObjectPtr ret;
2452 /*
2453 * Fallback to misc-cache.
2454 */
2455
2456 ret = (xmlXPathObjectPtr)
2457 cache->miscObjs->items[--cache->miscObjs->number];
2458
2459 ret->type = XPATH_NODESET;
2460 ret->boolval = 0;
2461 ret->nodesetval = xmlXPathNodeSetCreate(val);
2462 if (ret->nodesetval == NULL) {
2463 ctxt->lastError.domain = XML_FROM_XPATH;
2464 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2465 return(NULL);
2466 }
2467#ifdef XP_DEBUG_OBJ_USAGE
2468 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2469#endif
2470 return(ret);
2471 }
2472 }
2473 return(xmlXPathNewNodeSet(val));
2474}
2475
2486static xmlXPathObjectPtr
2487xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2488{
2489 if ((ctxt != NULL) && (ctxt->cache)) {
2490 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2491
2492 if ((cache->stringObjs != NULL) &&
2493 (cache->stringObjs->number != 0))
2494 {
2495 xmlXPathObjectPtr ret;
2496
2497 ret = (xmlXPathObjectPtr)
2498 cache->stringObjs->items[--cache->stringObjs->number];
2499
2500 ret->type = XPATH_STRING;
2501 ret->stringval = xmlStrdup(BAD_CAST val);
2502#ifdef XP_DEBUG_OBJ_USAGE
2503 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2504#endif
2505 return(ret);
2506 } else if ((cache->miscObjs != NULL) &&
2507 (cache->miscObjs->number != 0))
2508 {
2509 xmlXPathObjectPtr ret;
2510
2511 ret = (xmlXPathObjectPtr)
2512 cache->miscObjs->items[--cache->miscObjs->number];
2513
2514 ret->type = XPATH_STRING;
2515 ret->stringval = xmlStrdup(BAD_CAST val);
2516#ifdef XP_DEBUG_OBJ_USAGE
2517 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2518#endif
2519 return(ret);
2520 }
2521 }
2522 return(xmlXPathNewCString(val));
2523}
2524
2535static xmlXPathObjectPtr
2536xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2537{
2538 if ((ctxt != NULL) && (ctxt->cache)) {
2539 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2540
2541 if ((cache->stringObjs != NULL) &&
2542 (cache->stringObjs->number != 0))
2543 {
2544 xmlXPathObjectPtr ret;
2545
2546 ret = (xmlXPathObjectPtr)
2547 cache->stringObjs->items[--cache->stringObjs->number];
2548 ret->type = XPATH_STRING;
2549 if (val != NULL)
2550 ret->stringval = xmlStrdup(val);
2551 else
2552 ret->stringval = xmlStrdup((const xmlChar *)"");
2553#ifdef XP_DEBUG_OBJ_USAGE
2554 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2555#endif
2556 return(ret);
2557 } else if ((cache->miscObjs != NULL) &&
2558 (cache->miscObjs->number != 0))
2559 {
2560 xmlXPathObjectPtr ret;
2561
2562 ret = (xmlXPathObjectPtr)
2563 cache->miscObjs->items[--cache->miscObjs->number];
2564
2565 ret->type = XPATH_STRING;
2566 if (val != NULL)
2567 ret->stringval = xmlStrdup(val);
2568 else
2569 ret->stringval = xmlStrdup((const xmlChar *)"");
2570#ifdef XP_DEBUG_OBJ_USAGE
2571 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2572#endif
2573 return(ret);
2574 }
2575 }
2576 return(xmlXPathNewString(val));
2577}
2578
2589static xmlXPathObjectPtr
2590xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2591{
2592 if ((ctxt != NULL) && (ctxt->cache)) {
2593 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594
2595 if ((cache->booleanObjs != NULL) &&
2596 (cache->booleanObjs->number != 0))
2597 {
2598 xmlXPathObjectPtr ret;
2599
2600 ret = (xmlXPathObjectPtr)
2601 cache->booleanObjs->items[--cache->booleanObjs->number];
2602 ret->type = XPATH_BOOLEAN;
2603 ret->boolval = (val != 0);
2604#ifdef XP_DEBUG_OBJ_USAGE
2605 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606#endif
2607 return(ret);
2608 } else if ((cache->miscObjs != NULL) &&
2609 (cache->miscObjs->number != 0))
2610 {
2611 xmlXPathObjectPtr ret;
2612
2613 ret = (xmlXPathObjectPtr)
2614 cache->miscObjs->items[--cache->miscObjs->number];
2615
2616 ret->type = XPATH_BOOLEAN;
2617 ret->boolval = (val != 0);
2618#ifdef XP_DEBUG_OBJ_USAGE
2619 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2620#endif
2621 return(ret);
2622 }
2623 }
2624 return(xmlXPathNewBoolean(val));
2625}
2626
2637static xmlXPathObjectPtr
2638xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2639{
2640 if ((ctxt != NULL) && (ctxt->cache)) {
2641 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642
2643 if ((cache->numberObjs != NULL) &&
2644 (cache->numberObjs->number != 0))
2645 {
2646 xmlXPathObjectPtr ret;
2647
2648 ret = (xmlXPathObjectPtr)
2649 cache->numberObjs->items[--cache->numberObjs->number];
2650 ret->type = XPATH_NUMBER;
2651 ret->floatval = val;
2652#ifdef XP_DEBUG_OBJ_USAGE
2653 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654#endif
2655 return(ret);
2656 } else if ((cache->miscObjs != NULL) &&
2657 (cache->miscObjs->number != 0))
2658 {
2659 xmlXPathObjectPtr ret;
2660
2661 ret = (xmlXPathObjectPtr)
2662 cache->miscObjs->items[--cache->miscObjs->number];
2663
2664 ret->type = XPATH_NUMBER;
2665 ret->floatval = val;
2666#ifdef XP_DEBUG_OBJ_USAGE
2667 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668#endif
2669 return(ret);
2670 }
2671 }
2672 return(xmlXPathNewFloat(val));
2673}
2674
2687static xmlXPathObjectPtr
2688xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689 xmlChar *res = NULL;
2690
2691 if (val == NULL)
2692 return(xmlXPathCacheNewCString(ctxt, ""));
2693
2694 switch (val->type) {
2695 case XPATH_UNDEFINED:
2696#ifdef DEBUG_EXPR
2697 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698#endif
2699 break;
2700 case XPATH_NODESET:
2701 case XPATH_XSLT_TREE:
2702 res = xmlXPathCastNodeSetToString(val->nodesetval);
2703 break;
2704 case XPATH_STRING:
2705 return(val);
2706 case XPATH_BOOLEAN:
2707 res = xmlXPathCastBooleanToString(val->boolval);
2708 break;
2709 case XPATH_NUMBER:
2710 res = xmlXPathCastNumberToString(val->floatval);
2711 break;
2712 case XPATH_USERS:
2713#ifdef LIBXML_XPTR_LOCS_ENABLED
2714 case XPATH_POINT:
2715 case XPATH_RANGE:
2716 case XPATH_LOCATIONSET:
2717#endif /* LIBXML_XPTR_LOCS_ENABLED */
2718 TODO;
2719 break;
2720 }
2721 xmlXPathReleaseObject(ctxt, val);
2722 if (res == NULL)
2723 return(xmlXPathCacheNewCString(ctxt, ""));
2724 return(xmlXPathCacheWrapString(ctxt, res));
2725}
2726
2737static xmlXPathObjectPtr
2738xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2739{
2740 if (val == NULL)
2741 return(NULL);
2742
2743 if (XP_HAS_CACHE(ctxt)) {
2744 switch (val->type) {
2745 case XPATH_NODESET:
2746 return(xmlXPathCacheWrapNodeSet(ctxt,
2747 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748 case XPATH_STRING:
2749 return(xmlXPathCacheNewString(ctxt, val->stringval));
2750 case XPATH_BOOLEAN:
2751 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752 case XPATH_NUMBER:
2753 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754 default:
2755 break;
2756 }
2757 }
2758 return(xmlXPathObjectCopy(val));
2759}
2760
2772static xmlXPathObjectPtr
2773xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774 xmlXPathObjectPtr ret;
2775
2776 if (val == NULL)
2777 return(xmlXPathCacheNewBoolean(ctxt, 0));
2778 if (val->type == XPATH_BOOLEAN)
2779 return(val);
2780 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781 xmlXPathReleaseObject(ctxt, val);
2782 return(ret);
2783}
2784
2796static xmlXPathObjectPtr
2797xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798 xmlXPathObjectPtr ret;
2799
2800 if (val == NULL)
2801 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802 if (val->type == XPATH_NUMBER)
2803 return(val);
2804 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805 xmlXPathReleaseObject(ctxt, val);
2806 return(ret);
2807}
2808
2809/************************************************************************
2810 * *
2811 * Parser stacks related functions and macros *
2812 * *
2813 ************************************************************************/
2814
2823static int
2824xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2825 int ret;
2826
2827 if (ctxt == NULL)
2828 return(0);
2829 ret = ctxt->valueFrame;
2830 ctxt->valueFrame = ctxt->valueNr;
2831 return(ret);
2832}
2833
2841static void
2842xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2843 if (ctxt == NULL)
2844 return;
2845 if (ctxt->valueNr < ctxt->valueFrame) {
2846 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2847 }
2848 ctxt->valueFrame = frame;
2849}
2850
2859xmlXPathObjectPtr
2860valuePop(xmlXPathParserContextPtr ctxt)
2861{
2862 xmlXPathObjectPtr ret;
2863
2864 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2865 return (NULL);
2866
2867 if (ctxt->valueNr <= ctxt->valueFrame) {
2868 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2869 return (NULL);
2870 }
2871
2872 ctxt->valueNr--;
2873 if (ctxt->valueNr > 0)
2874 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2875 else
2876 ctxt->value = NULL;
2877 ret = ctxt->valueTab[ctxt->valueNr];
2878 ctxt->valueTab[ctxt->valueNr] = NULL;
2879 return (ret);
2880}
2891int
2892valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2893{
2894 if (ctxt == NULL) return(-1);
2895 if (value == NULL) {
2896 /*
2897 * A NULL value typically indicates that a memory allocation failed,
2898 * so we set ctxt->error here to propagate the error.
2899 */
2900 ctxt->error = XPATH_MEMORY_ERROR;
2901 return(-1);
2902 }
2903 if (ctxt->valueNr >= ctxt->valueMax) {
2904 xmlXPathObjectPtr *tmp;
2905
2906 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2907 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2908 return (-1);
2909 }
2910 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2911 2 * ctxt->valueMax *
2912 sizeof(ctxt->valueTab[0]));
2913 if (tmp == NULL) {
2914 xmlXPathPErrMemory(ctxt, "pushing value\n");
2915 return (-1);
2916 }
2917 ctxt->valueMax *= 2;
2918 ctxt->valueTab = tmp;
2919 }
2920 ctxt->valueTab[ctxt->valueNr] = value;
2921 ctxt->value = value;
2922 return (ctxt->valueNr++);
2923}
2924
2934int
2935xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2936 xmlXPathObjectPtr obj;
2937 int ret;
2938
2939 obj = valuePop(ctxt);
2940 if (obj == NULL) {
2941 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2942 return(0);
2943 }
2944 if (obj->type != XPATH_BOOLEAN)
2945 ret = xmlXPathCastToBoolean(obj);
2946 else
2947 ret = obj->boolval;
2948 xmlXPathReleaseObject(ctxt->context, obj);
2949 return(ret);
2950}
2951
2961double
2962xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2963 xmlXPathObjectPtr obj;
2964 double ret;
2965
2966 obj = valuePop(ctxt);
2967 if (obj == NULL) {
2968 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2969 return(0);
2970 }
2971 if (obj->type != XPATH_NUMBER)
2972 ret = xmlXPathCastToNumber(obj);
2973 else
2974 ret = obj->floatval;
2975 xmlXPathReleaseObject(ctxt->context, obj);
2976 return(ret);
2977}
2978
2988xmlChar *
2989xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2990 xmlXPathObjectPtr obj;
2991 xmlChar * ret;
2992
2993 obj = valuePop(ctxt);
2994 if (obj == NULL) {
2995 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2996 return(NULL);
2997 }
2998 ret = xmlXPathCastToString(obj); /* this does required strdup */
2999 /* TODO: needs refactoring somewhere else */
3000 if (obj->stringval == ret)
3001 obj->stringval = NULL;
3002 xmlXPathReleaseObject(ctxt->context, obj);
3003 return(ret);
3004}
3005
3015xmlNodeSetPtr
3016xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3017 xmlXPathObjectPtr obj;
3018 xmlNodeSetPtr ret;
3019
3020 if (ctxt == NULL) return(NULL);
3021 if (ctxt->value == NULL) {
3022 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3023 return(NULL);
3024 }
3025 if (!xmlXPathStackIsNodeSet(ctxt)) {
3026 xmlXPathSetTypeError(ctxt);
3027 return(NULL);
3028 }
3029 obj = valuePop(ctxt);
3030 ret = obj->nodesetval;
3031#if 0
3032 /* to fix memory leak of not clearing obj->user */
3033 if (obj->boolval && obj->user != NULL)
3035#endif
3036 obj->nodesetval = NULL;
3037 xmlXPathReleaseObject(ctxt->context, obj);
3038 return(ret);
3039}
3040
3050void *
3051xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3052 xmlXPathObjectPtr obj;
3053 void * ret;
3054
3055 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3056 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3057 return(NULL);
3058 }
3059 if (ctxt->value->type != XPATH_USERS) {
3060 xmlXPathSetTypeError(ctxt);
3061 return(NULL);
3062 }
3063 obj = valuePop(ctxt);
3064 ret = obj->user;
3065 obj->user = NULL;
3066 xmlXPathReleaseObject(ctxt->context, obj);
3067 return(ret);
3068}
3069
3070/*
3071 * Macros for accessing the content. Those should be used only by the parser,
3072 * and not exported.
3073 *
3074 * Dirty macros, i.e. one need to make assumption on the context to use them
3075 *
3076 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3077 * CUR returns the current xmlChar value, i.e. a 8 bit value
3078 * in ISO-Latin or UTF-8.
3079 * This should be used internally by the parser
3080 * only to compare to ASCII values otherwise it would break when
3081 * running with UTF-8 encoding.
3082 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3083 * to compare on ASCII based substring.
3084 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3085 * strings within the parser.
3086 * CURRENT Returns the current char value, with the full decoding of
3087 * UTF-8 if we are using this mode. It returns an int.
3088 * NEXT Skip to the next character, this does the proper decoding
3089 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3090 * It returns the pointer to the current xmlChar.
3091 */
3092
3093#define CUR (*ctxt->cur)
3094#define SKIP(val) ctxt->cur += (val)
3095#define NXT(val) ctxt->cur[(val)]
3096#define CUR_PTR ctxt->cur
3097#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3098
3099#define COPY_BUF(l,b,i,v) \
3100 if (l == 1) b[i++] = (xmlChar) v; \
3101 else i += xmlCopyChar(l,&b[i],v)
3102
3103#define NEXTL(l) ctxt->cur += l
3104
3105#define SKIP_BLANKS \
3106 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3107
3108#define CURRENT (*ctxt->cur)
3109#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3110
3111
3112#ifndef DBL_DIG
3113#define DBL_DIG 16
3114#endif
3115#ifndef DBL_EPSILON
3116#define DBL_EPSILON 1E-9
3117#endif
3118
3119#define UPPER_DOUBLE 1E9
3120#define LOWER_DOUBLE 1E-5
3121#define LOWER_DOUBLE_EXP 5
3122
3123#define INTEGER_DIGITS DBL_DIG
3124#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3125#define EXPONENT_DIGITS (3 + 2)
3126
3135static void
3136xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3137{
3138 switch (xmlXPathIsInf(number)) {
3139 case 1:
3140 if (buffersize > (int)sizeof("Infinity"))
3141 snprintf(buffer, buffersize, "Infinity");
3142 break;
3143 case -1:
3144 if (buffersize > (int)sizeof("-Infinity"))
3145 snprintf(buffer, buffersize, "-Infinity");
3146 break;
3147 default:
3148 if (xmlXPathIsNaN(number)) {
3149 if (buffersize > (int)sizeof("NaN"))
3150 snprintf(buffer, buffersize, "NaN");
3151 } else if (number == 0) {
3152 /* Omit sign for negative zero. */
3153 snprintf(buffer, buffersize, "0");
3154 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3155 (number == (int) number)) {
3156 char work[30];
3157 char *ptr, *cur;
3158 int value = (int) number;
3159
3160 ptr = &buffer[0];
3161 if (value == 0) {
3162 *ptr++ = '0';
3163 } else {
3164 snprintf(work, 29, "%d", value);
3165 cur = &work[0];
3166 while ((*cur) && (ptr - buffer < buffersize)) {
3167 *ptr++ = *cur++;
3168 }
3169 }
3170 if (ptr - buffer < buffersize) {
3171 *ptr = 0;
3172 } else if (buffersize > 0) {
3173 ptr--;
3174 *ptr = 0;
3175 }
3176 } else {
3177 /*
3178 For the dimension of work,
3179 DBL_DIG is number of significant digits
3180 EXPONENT is only needed for "scientific notation"
3181 3 is sign, decimal point, and terminating zero
3182 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3183 Note that this dimension is slightly (a few characters)
3184 larger than actually necessary.
3185 */
3186 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3187 int integer_place, fraction_place;
3188 char *ptr;
3189 char *after_fraction;
3190 double absolute_value;
3191 int size;
3192
3193 absolute_value = fabs(number);
3194
3195 /*
3196 * First choose format - scientific or regular floating point.
3197 * In either case, result is in work, and after_fraction points
3198 * just past the fractional part.
3199 */
3200 if ( ((absolute_value > UPPER_DOUBLE) ||
3201 (absolute_value < LOWER_DOUBLE)) &&
3202 (absolute_value != 0.0) ) {
3203 /* Use scientific notation */
3204 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3205 fraction_place = DBL_DIG - 1;
3206 size = snprintf(work, sizeof(work),"%*.*e",
3207 integer_place, fraction_place, number);
3208 while ((size > 0) && (work[size] != 'e')) size--;
3209
3210 }
3211 else {
3212 /* Use regular notation */
3213 if (absolute_value > 0.0) {
3214 integer_place = (int)log10(absolute_value);
3215 if (integer_place > 0)
3216 fraction_place = DBL_DIG - integer_place - 1;
3217 else
3218 fraction_place = DBL_DIG - integer_place;
3219 } else {
3220 fraction_place = 1;
3221 }
3222 size = snprintf(work, sizeof(work), "%0.*f",
3223 fraction_place, number);
3224 }
3225
3226 /* Remove leading spaces sometimes inserted by snprintf */
3227 while (work[0] == ' ') {
3228 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3229 size--;
3230 }
3231
3232 /* Remove fractional trailing zeroes */
3233 after_fraction = work + size;
3234 ptr = after_fraction;
3235 while (*(--ptr) == '0')
3236 ;
3237 if (*ptr != '.')
3238 ptr++;
3239 while ((*ptr++ = *after_fraction++) != 0);
3240
3241 /* Finally copy result back to caller */
3242 size = strlen(work) + 1;
3243 if (size > buffersize) {
3244 work[buffersize - 1] = 0;
3245 size = buffersize;
3246 }
3247 memmove(buffer, work, size);
3248 }
3249 break;
3250 }
3251}
3252
3253
3254/************************************************************************
3255 * *
3256 * Routines to handle NodeSets *
3257 * *
3258 ************************************************************************/
3259
3273long
3274xmlXPathOrderDocElems(xmlDocPtr doc) {
3275 ptrdiff_t count = 0;
3277
3278 if (doc == NULL)
3279 return(-1);
3280 cur = doc->children;
3281 while (cur != NULL) {
3282 if (cur->type == XML_ELEMENT_NODE) {
3283 cur->content = (void *) (-(++count));
3284 if (cur->children != NULL) {
3285 cur = cur->children;
3286 continue;
3287 }
3288 }
3289 if (cur->next != NULL) {
3290 cur = cur->next;
3291 continue;
3292 }
3293 do {
3294 cur = cur->parent;
3295 if (cur == NULL)
3296 break;
3297 if (cur == (xmlNodePtr) doc) {
3298 cur = NULL;
3299 break;
3300 }
3301 if (cur->next != NULL) {
3302 cur = cur->next;
3303 break;
3304 }
3305 } while (cur != NULL);
3306 }
3307 return((long) count);
3308}
3309
3320int
3321xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3322 int depth1, depth2;
3323 int attr1 = 0, attr2 = 0;
3324 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3326
3327 if ((node1 == NULL) || (node2 == NULL))
3328 return(-2);
3329 /*
3330 * a couple of optimizations which will avoid computations in most cases
3331 */
3332 if (node1 == node2) /* trivial case */
3333 return(0);
3334 if (node1->type == XML_ATTRIBUTE_NODE) {
3335 attr1 = 1;
3336 attrNode1 = node1;
3337 node1 = node1->parent;
3338 }
3339 if (node2->type == XML_ATTRIBUTE_NODE) {
3340 attr2 = 1;
3341 attrNode2 = node2;
3342 node2 = node2->parent;
3343 }
3344 if (node1 == node2) {
3345 if (attr1 == attr2) {
3346 /* not required, but we keep attributes in order */
3347 if (attr1 != 0) {
3348 cur = attrNode2->prev;
3349 while (cur != NULL) {
3350 if (cur == attrNode1)
3351 return (1);
3352 cur = cur->prev;
3353 }
3354 return (-1);
3355 }
3356 return(0);
3357 }
3358 if (attr2 == 1)
3359 return(1);
3360 return(-1);
3361 }
3362 if ((node1->type == XML_NAMESPACE_DECL) ||
3363 (node2->type == XML_NAMESPACE_DECL))
3364 return(1);
3365 if (node1 == node2->prev)
3366 return(1);
3367 if (node1 == node2->next)
3368 return(-1);
3369
3370 /*
3371 * Speedup using document order if available.
3372 */
3373 if ((node1->type == XML_ELEMENT_NODE) &&
3374 (node2->type == XML_ELEMENT_NODE) &&
3375 (0 > (ptrdiff_t) node1->content) &&
3376 (0 > (ptrdiff_t) node2->content) &&
3377 (node1->doc == node2->doc)) {
3378 ptrdiff_t l1, l2;
3379
3380 l1 = -((ptrdiff_t) node1->content);
3381 l2 = -((ptrdiff_t) node2->content);
3382 if (l1 < l2)
3383 return(1);
3384 if (l1 > l2)
3385 return(-1);
3386 }
3387
3388 /*
3389 * compute depth to root
3390 */
3391 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3392 if (cur->parent == node1)
3393 return(1);
3394 depth2++;
3395 }
3396 root = cur;
3397 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3398 if (cur->parent == node2)
3399 return(-1);
3400 depth1++;
3401 }
3402 /*
3403 * Distinct document (or distinct entities :-( ) case.
3404 */
3405 if (root != cur) {
3406 return(-2);
3407 }
3408 /*
3409 * get the nearest common ancestor.
3410 */
3411 while (depth1 > depth2) {
3412 depth1--;
3413 node1 = node1->parent;
3414 }
3415 while (depth2 > depth1) {
3416 depth2--;
3417 node2 = node2->parent;
3418 }
3419 while (node1->parent != node2->parent) {
3420 node1 = node1->parent;
3421 node2 = node2->parent;
3422 /* should not happen but just in case ... */
3423 if ((node1 == NULL) || (node2 == NULL))
3424 return(-2);
3425 }
3426 /*
3427 * Find who's first.
3428 */
3429 if (node1 == node2->prev)
3430 return(1);
3431 if (node1 == node2->next)
3432 return(-1);
3433 /*
3434 * Speedup using document order if available.
3435 */
3436 if ((node1->type == XML_ELEMENT_NODE) &&
3437 (node2->type == XML_ELEMENT_NODE) &&
3438 (0 > (ptrdiff_t) node1->content) &&
3439 (0 > (ptrdiff_t) node2->content) &&
3440 (node1->doc == node2->doc)) {
3441 ptrdiff_t l1, l2;
3442
3443 l1 = -((ptrdiff_t) node1->content);
3444 l2 = -((ptrdiff_t) node2->content);
3445 if (l1 < l2)
3446 return(1);
3447 if (l1 > l2)
3448 return(-1);
3449 }
3450
3451 for (cur = node1->next;cur != NULL;cur = cur->next)
3452 if (cur == node2)
3453 return(1);
3454 return(-1); /* assume there is no sibling list corruption */
3455}
3456
3463void
3464xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3465#ifndef WITH_TIM_SORT
3466 int i, j, incr, len;
3467 xmlNodePtr tmp;
3468#endif
3469
3470 if (set == NULL)
3471 return;
3472
3473#ifndef WITH_TIM_SORT
3474 /*
3475 * Use the old Shell's sort implementation to sort the node-set
3476 * Timsort ought to be quite faster
3477 */
3478 len = set->nodeNr;
3479 for (incr = len / 2; incr > 0; incr /= 2) {
3480 for (i = incr; i < len; i++) {
3481 j = i - incr;
3482 while (j >= 0) {
3483#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3484 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3485 set->nodeTab[j + incr]) == -1)
3486#else
3487 if (xmlXPathCmpNodes(set->nodeTab[j],
3488 set->nodeTab[j + incr]) == -1)
3489#endif
3490 {
3491 tmp = set->nodeTab[j];
3492 set->nodeTab[j] = set->nodeTab[j + incr];
3493 set->nodeTab[j + incr] = tmp;
3494 j -= incr;
3495 } else
3496 break;
3497 }
3498 }
3499 }
3500#else /* WITH_TIM_SORT */
3501 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3502#endif /* WITH_TIM_SORT */
3503}
3504
3505#define XML_NODESET_DEFAULT 10
3517static xmlNodePtr
3518xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3519 xmlNsPtr cur;
3520
3521 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3522 return(NULL);
3523 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3524 return((xmlNodePtr) ns);
3525
3526 /*
3527 * Allocate a new Namespace and fill the fields.
3528 */
3529 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3530 if (cur == NULL) {
3531 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3532 return(NULL);
3533 }
3534 memset(cur, 0, sizeof(xmlNs));
3535 cur->type = XML_NAMESPACE_DECL;
3536 if (ns->href != NULL)
3537 cur->href = xmlStrdup(ns->href);
3538 if (ns->prefix != NULL)
3539 cur->prefix = xmlStrdup(ns->prefix);
3540 cur->next = (xmlNsPtr) node;
3541 return((xmlNodePtr) cur);
3542}
3543
3552void
3553xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3554 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3555 return;
3556
3557 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3558 if (ns->href != NULL)
3559 xmlFree((xmlChar *)ns->href);
3560 if (ns->prefix != NULL)
3561 xmlFree((xmlChar *)ns->prefix);
3562 xmlFree(ns);
3563 }
3564}
3565
3574xmlNodeSetPtr
3575xmlXPathNodeSetCreate(xmlNodePtr val) {
3576 xmlNodeSetPtr ret;
3577
3578 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3579 if (ret == NULL) {
3580 xmlXPathErrMemory(NULL, "creating nodeset\n");
3581 return(NULL);
3582 }
3583 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3584 if (val != NULL) {
3585 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3586 sizeof(xmlNodePtr));
3587 if (ret->nodeTab == NULL) {
3588 xmlXPathErrMemory(NULL, "creating nodeset\n");
3589 xmlFree(ret);
3590 return(NULL);
3591 }
3592 memset(ret->nodeTab, 0 ,
3593 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3594 ret->nodeMax = XML_NODESET_DEFAULT;
3595 if (val->type == XML_NAMESPACE_DECL) {
3596 xmlNsPtr ns = (xmlNsPtr) val;
3597
3598 /* TODO: Check memory error. */
3599 ret->nodeTab[ret->nodeNr++] =
3600 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3601 } else
3602 ret->nodeTab[ret->nodeNr++] = val;
3603 }
3604 return(ret);
3605}
3606
3616int
3617xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3618 int i;
3619
3620 if ((cur == NULL) || (val == NULL)) return(0);
3621 if (val->type == XML_NAMESPACE_DECL) {
3622 for (i = 0; i < cur->nodeNr; i++) {
3623 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3624 xmlNsPtr ns1, ns2;
3625
3626 ns1 = (xmlNsPtr) val;
3627 ns2 = (xmlNsPtr) cur->nodeTab[i];
3628 if (ns1 == ns2)
3629 return(1);
3630 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3631 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3632 return(1);
3633 }
3634 }
3635 } else {
3636 for (i = 0; i < cur->nodeNr; i++) {
3637 if (cur->nodeTab[i] == val)
3638 return(1);
3639 }
3640 }
3641 return(0);
3642}
3643
3654int
3655xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3656 int i;
3657
3658
3659 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3660 (ns->type != XML_NAMESPACE_DECL) ||
3661 (node->type != XML_ELEMENT_NODE))
3662 return(-1);
3663
3664 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3665 /*
3666 * prevent duplicates
3667 */
3668 for (i = 0;i < cur->nodeNr;i++) {
3669 if ((cur->nodeTab[i] != NULL) &&
3670 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3671 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3672 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3673 return(0);
3674 }
3675
3676 /*
3677 * grow the nodeTab if needed
3678 */
3679 if (cur->nodeMax == 0) {
3680 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3681 sizeof(xmlNodePtr));
3682 if (cur->nodeTab == NULL) {
3683 xmlXPathErrMemory(NULL, "growing nodeset\n");
3684 return(-1);
3685 }
3686 memset(cur->nodeTab, 0 ,
3687 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3688 cur->nodeMax = XML_NODESET_DEFAULT;
3689 } else if (cur->nodeNr == cur->nodeMax) {
3691
3692 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3693 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3694 return(-1);
3695 }
3696 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3697 sizeof(xmlNodePtr));
3698 if (temp == NULL) {
3699 xmlXPathErrMemory(NULL, "growing nodeset\n");
3700 return(-1);
3701 }
3702 cur->nodeMax *= 2;
3703 cur->nodeTab = temp;
3704 }
3705 /* TODO: Check memory error. */
3706 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3707 return(0);
3708}
3709
3719int
3720xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3721 int i;
3722
3723 if ((cur == NULL) || (val == NULL)) return(-1);
3724
3725 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3726 /*
3727 * prevent duplicates
3728 */
3729 for (i = 0;i < cur->nodeNr;i++)
3730 if (cur->nodeTab[i] == val) return(0);
3731
3732 /*
3733 * grow the nodeTab if needed
3734 */
3735 if (cur->nodeMax == 0) {
3736 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3737 sizeof(xmlNodePtr));
3738 if (cur->nodeTab == NULL) {
3739 xmlXPathErrMemory(NULL, "growing nodeset\n");
3740 return(-1);
3741 }
3742 memset(cur->nodeTab, 0 ,
3743 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3744 cur->nodeMax = XML_NODESET_DEFAULT;
3745 } else if (cur->nodeNr == cur->nodeMax) {
3747
3748 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3749 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3750 return(-1);
3751 }
3752 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3753 sizeof(xmlNodePtr));
3754 if (temp == NULL) {
3755 xmlXPathErrMemory(NULL, "growing nodeset\n");
3756 return(-1);
3757 }
3758 cur->nodeMax *= 2;
3759 cur->nodeTab = temp;
3760 }
3761 if (val->type == XML_NAMESPACE_DECL) {
3762 xmlNsPtr ns = (xmlNsPtr) val;
3763
3764 /* TODO: Check memory error. */
3765 cur->nodeTab[cur->nodeNr++] =
3766 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3767 } else
3768 cur->nodeTab[cur->nodeNr++] = val;
3769 return(0);
3770}
3771
3782int
3783xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3784 if ((cur == NULL) || (val == NULL)) return(-1);
3785
3786 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3787 /*
3788 * grow the nodeTab if needed
3789 */
3790 if (cur->nodeMax == 0) {
3791 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792 sizeof(xmlNodePtr));
3793 if (cur->nodeTab == NULL) {
3794 xmlXPathErrMemory(NULL, "growing nodeset\n");
3795 return(-1);
3796 }
3797 memset(cur->nodeTab, 0 ,
3798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799 cur->nodeMax = XML_NODESET_DEFAULT;
3800 } else if (cur->nodeNr == cur->nodeMax) {
3802
3803 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3804 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3805 return(-1);
3806 }
3807 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3808 sizeof(xmlNodePtr));
3809 if (temp == NULL) {
3810 xmlXPathErrMemory(NULL, "growing nodeset\n");
3811 return(-1);
3812 }
3813 cur->nodeTab = temp;
3814 cur->nodeMax *= 2;
3815 }
3816 if (val->type == XML_NAMESPACE_DECL) {
3817 xmlNsPtr ns = (xmlNsPtr) val;
3818
3819 /* TODO: Check memory error. */
3820 cur->nodeTab[cur->nodeNr++] =
3821 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3822 } else
3823 cur->nodeTab[cur->nodeNr++] = val;
3824 return(0);
3825}
3826
3837xmlNodeSetPtr
3838xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3839 int i, j, initNr, skip;
3840 xmlNodePtr n1, n2;
3841
3842 if (val2 == NULL) return(val1);
3843 if (val1 == NULL) {
3844 val1 = xmlXPathNodeSetCreate(NULL);
3845 if (val1 == NULL)
3846 return (NULL);
3847#if 0
3848 /*
3849 * TODO: The optimization won't work in every case, since
3850 * those nasty namespace nodes need to be added with
3851 * xmlXPathNodeSetDupNs() to the set; thus a pure
3852 * memcpy is not possible.
3853 * If there was a flag on the nodesetval, indicating that
3854 * some temporary nodes are in, that would be helpful.
3855 */
3856 /*
3857 * Optimization: Create an equally sized node-set
3858 * and memcpy the content.
3859 */
3860 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3861 if (val1 == NULL)
3862 return(NULL);
3863 if (val2->nodeNr != 0) {
3864 if (val2->nodeNr == 1)
3865 *(val1->nodeTab) = *(val2->nodeTab);
3866 else {
3867 memcpy(val1->nodeTab, val2->nodeTab,
3868 val2->nodeNr * sizeof(xmlNodePtr));
3869 }
3870 val1->nodeNr = val2->nodeNr;
3871 }
3872 return(val1);
3873#endif
3874 }
3875
3876 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3877 initNr = val1->nodeNr;
3878
3879 for (i = 0;i < val2->nodeNr;i++) {
3880 n2 = val2->nodeTab[i];
3881 /*
3882 * check against duplicates
3883 */
3884 skip = 0;
3885 for (j = 0; j < initNr; j++) {
3886 n1 = val1->nodeTab[j];
3887 if (n1 == n2) {
3888 skip = 1;
3889 break;
3890 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3891 (n2->type == XML_NAMESPACE_DECL)) {
3892 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3893 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3894 ((xmlNsPtr) n2)->prefix)))
3895 {
3896 skip = 1;
3897 break;
3898 }
3899 }
3900 }
3901 if (skip)
3902 continue;
3903
3904 /*
3905 * grow the nodeTab if needed
3906 */
3907 if (val1->nodeMax == 0) {
3908 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3909 sizeof(xmlNodePtr));
3910 if (val1->nodeTab == NULL) {
3911 xmlXPathErrMemory(NULL, "merging nodeset\n");
3912 return(NULL);
3913 }
3914 memset(val1->nodeTab, 0 ,
3915 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3916 val1->nodeMax = XML_NODESET_DEFAULT;
3917 } else if (val1->nodeNr == val1->nodeMax) {
3919
3920 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3921 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3922 return(NULL);
3923 }
3924 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3925 sizeof(xmlNodePtr));
3926 if (temp == NULL) {
3927 xmlXPathErrMemory(NULL, "merging nodeset\n");
3928 return(NULL);
3929 }
3930 val1->nodeTab = temp;
3931 val1->nodeMax *= 2;
3932 }
3933 if (n2->type == XML_NAMESPACE_DECL) {
3934 xmlNsPtr ns = (xmlNsPtr) n2;
3935
3936 /* TODO: Check memory error. */
3937 val1->nodeTab[val1->nodeNr++] =
3938 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3939 } else
3940 val1->nodeTab[val1->nodeNr++] = n2;
3941 }
3942
3943 return(val1);
3944}
3945
3946
3957static xmlNodeSetPtr
3958xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3959{
3960 {
3961 int i, j, initNbSet1;
3962 xmlNodePtr n1, n2;
3963
3964 initNbSet1 = set1->nodeNr;
3965 for (i = 0;i < set2->nodeNr;i++) {
3966 n2 = set2->nodeTab[i];
3967 /*
3968 * Skip duplicates.
3969 */
3970 for (j = 0; j < initNbSet1; j++) {
3971 n1 = set1->nodeTab[j];
3972 if (n1 == n2) {
3973 goto skip_node;
3974 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3975 (n2->type == XML_NAMESPACE_DECL))
3976 {
3977 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3978 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3979 ((xmlNsPtr) n2)->prefix)))
3980 {
3981 /*
3982 * Free the namespace node.
3983 */
3984 set2->nodeTab[i] = NULL;
3985 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3986 goto skip_node;
3987 }
3988 }
3989 }
3990 /*
3991 * grow the nodeTab if needed
3992 */
3993 if (set1->nodeMax == 0) {
3994 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3995 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3996 if (set1->nodeTab == NULL) {
3997 xmlXPathErrMemory(NULL, "merging nodeset\n");
3998 return(NULL);
3999 }
4000 memset(set1->nodeTab, 0,
4001 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4002 set1->nodeMax = XML_NODESET_DEFAULT;
4003 } else if (set1->nodeNr >= set1->nodeMax) {
4005
4006 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4007 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4008 return(NULL);
4009 }
4011 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4012 if (temp == NULL) {
4013 xmlXPathErrMemory(NULL, "merging nodeset\n");
4014 return(NULL);
4015 }
4016 set1->nodeTab = temp;
4017 set1->nodeMax *= 2;
4018 }
4019 set1->nodeTab[set1->nodeNr++] = n2;
4020skip_node:
4021 {}
4022 }
4023 }
4024 set2->nodeNr = 0;
4025 return(set1);
4026}
4027
4038static xmlNodeSetPtr
4039xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4040{
4041 {
4042 int i;
4043 xmlNodePtr n2;
4044
4045 for (i = 0;i < set2->nodeNr;i++) {
4046 n2 = set2->nodeTab[i];
4047 if (set1->nodeMax == 0) {
4048 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4049 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4050 if (set1->nodeTab == NULL) {
4051 xmlXPathErrMemory(NULL, "merging nodeset\n");
4052 return(NULL);
4053 }
4054 memset(set1->nodeTab, 0,
4055 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4056 set1->nodeMax = XML_NODESET_DEFAULT;
4057 } else if (set1->nodeNr >= set1->nodeMax) {
4059
4060 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4061 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4062 return(NULL);
4063 }
4065 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4066 if (temp == NULL) {
4067 xmlXPathErrMemory(NULL, "merging nodeset\n");
4068 return(NULL);
4069 }
4070 set1->nodeTab = temp;
4071 set1->nodeMax *= 2;
4072 }
4073 set1->nodeTab[set1->nodeNr++] = n2;
4074 }
4075 }
4076 set2->nodeNr = 0;
4077 return(set1);
4078}
4079
4087void
4088xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4089 int i;
4090
4091 if (cur == NULL) return;
4092 if (val == NULL) return;
4093
4094 /*
4095 * find node in nodeTab
4096 */
4097 for (i = 0;i < cur->nodeNr;i++)
4098 if (cur->nodeTab[i] == val) break;
4099
4100 if (i >= cur->nodeNr) { /* not found */
4101#ifdef DEBUG
4103 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4104 val->name);
4105#endif
4106 return;
4107 }
4108 if ((cur->nodeTab[i] != NULL) &&
4109 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4110 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4111 cur->nodeNr--;
4112 for (;i < cur->nodeNr;i++)
4113 cur->nodeTab[i] = cur->nodeTab[i + 1];
4114 cur->nodeTab[cur->nodeNr] = NULL;
4115}
4116
4124void
4125xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4126 if (cur == NULL) return;
4127 if (val >= cur->nodeNr) return;
4128 if ((cur->nodeTab[val] != NULL) &&
4129 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4130 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4131 cur->nodeNr--;
4132 for (;val < cur->nodeNr;val++)
4133 cur->nodeTab[val] = cur->nodeTab[val + 1];
4134 cur->nodeTab[cur->nodeNr] = NULL;
4135}
4136
4143void
4144xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4145 if (obj == NULL) return;
4146 if (obj->nodeTab != NULL) {
4147 int i;
4148
4149 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4150 for (i = 0;i < obj->nodeNr;i++)
4151 if ((obj->nodeTab[i] != NULL) &&
4152 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4153 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4154 xmlFree(obj->nodeTab);
4155 }
4156 xmlFree(obj);
4157}
4158
4168static void
4169xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4170{
4171 if ((set == NULL) || (pos >= set->nodeNr))
4172 return;
4173 else if ((hasNsNodes)) {
4174 int i;
4176
4177 for (i = pos; i < set->nodeNr; i++) {
4178 node = set->nodeTab[i];
4179 if ((node != NULL) &&
4180 (node->type == XML_NAMESPACE_DECL))
4181 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4182 }
4183 }
4184 set->nodeNr = pos;
4185}
4186
4195static void
4196xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4197{
4198 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4199}
4200
4209static void
4210xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4211{
4212 int i;
4214
4215 if ((set == NULL) || (set->nodeNr <= 1))
4216 return;
4217 for (i = 0; i < set->nodeNr - 1; i++) {
4218 node = set->nodeTab[i];
4219 if ((node != NULL) &&
4220 (node->type == XML_NAMESPACE_DECL))
4221 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4222 }
4223 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4224 set->nodeNr = 1;
4225}
4226
4234static void
4235xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4236 int i;
4237
4238 if (obj == NULL) return;
4239
4240 if (obj->nodeTab != NULL) {
4241 for (i = 0;i < obj->nodeNr;i++) {
4242 if (obj->nodeTab[i] != NULL) {
4243 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4244 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4245 } else {
4246 xmlFreeNodeList(obj->nodeTab[i]);
4247 }
4248 }
4249 }
4250 xmlFree(obj->nodeTab);
4251 }
4252 xmlFree(obj);
4253}
4254
4255#if defined(DEBUG) || defined(DEBUG_STEP)
4263void
4264xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4265 int i;
4266
4267 if (output == NULL) output = xmlGenericErrorContext;
4268 if (obj == NULL) {
4269 fprintf(output, "NodeSet == NULL !\n");
4270 return;
4271 }
4272 if (obj->nodeNr == 0) {
4273 fprintf(output, "NodeSet is empty\n");
4274 return;
4275 }
4276 if (obj->nodeTab == NULL) {
4277 fprintf(output, " nodeTab == NULL !\n");
4278 return;
4279 }
4280 for (i = 0; i < obj->nodeNr; i++) {
4281 if (obj->nodeTab[i] == NULL) {
4282 fprintf(output, " NULL !\n");
4283 return;
4284 }
4285 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4286 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4287 fprintf(output, " /");
4288 else if (obj->nodeTab[i]->name == NULL)
4289 fprintf(output, " noname!");
4290 else fprintf(output, " %s", obj->nodeTab[i]->name);
4291 }
4292 fprintf(output, "\n");
4293}
4294#endif
4295
4305xmlXPathObjectPtr
4306xmlXPathNewNodeSet(xmlNodePtr val) {
4307 xmlXPathObjectPtr ret;
4308
4309 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4310 if (ret == NULL) {
4311 xmlXPathErrMemory(NULL, "creating nodeset\n");
4312 return(NULL);
4313 }
4314 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4315 ret->type = XPATH_NODESET;
4316 ret->boolval = 0;
4317 /* TODO: Check memory error. */
4318 ret->nodesetval = xmlXPathNodeSetCreate(val);
4319 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4320#ifdef XP_DEBUG_OBJ_USAGE
4321 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4322#endif
4323 return(ret);
4324}
4325
4335xmlXPathObjectPtr
4336xmlXPathNewValueTree(xmlNodePtr val) {
4337 xmlXPathObjectPtr ret;
4338
4339 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4340 if (ret == NULL) {
4341 xmlXPathErrMemory(NULL, "creating result value tree\n");
4342 return(NULL);
4343 }
4344 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4345 ret->type = XPATH_XSLT_TREE;
4346 ret->boolval = 1;
4347 ret->user = (void *) val;
4348 ret->nodesetval = xmlXPathNodeSetCreate(val);
4349#ifdef XP_DEBUG_OBJ_USAGE
4350 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4351#endif
4352 return(ret);
4353}
4354
4364xmlXPathObjectPtr
4365xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4366{
4367 xmlXPathObjectPtr ret;
4368 int i;
4369
4370 if (val == NULL)
4371 ret = NULL;
4372 else if (val->nodeTab == NULL)
4373 ret = xmlXPathNewNodeSet(NULL);
4374 else {
4375 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4376 if (ret) {
4377 for (i = 1; i < val->nodeNr; ++i) {
4378 /* TODO: Propagate memory error. */
4379 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4380 < 0) break;
4381 }
4382 }
4383 }
4384
4385 return (ret);
4386}
4387
4396xmlXPathObjectPtr
4397xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4398 xmlXPathObjectPtr ret;
4399
4400 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4401 if (ret == NULL) {
4402 xmlXPathErrMemory(NULL, "creating node set object\n");
4403 return(NULL);
4404 }
4405 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4406 ret->type = XPATH_NODESET;
4407 ret->nodesetval = val;
4408#ifdef XP_DEBUG_OBJ_USAGE
4409 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4410#endif
4411 return(ret);
4412}
4413
4421void
4422xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4423 if (obj == NULL) return;
4424#ifdef XP_DEBUG_OBJ_USAGE
4425 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4426#endif
4427 xmlFree(obj);
4428}
4429
4441xmlNodeSetPtr
4442xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4443 xmlNodeSetPtr ret;
4444 int i, l1;
4446
4447 if (xmlXPathNodeSetIsEmpty(nodes2))
4448 return(nodes1);
4449
4450 /* TODO: Check memory error. */
4451 ret = xmlXPathNodeSetCreate(NULL);
4452 if (xmlXPathNodeSetIsEmpty(nodes1))
4453 return(ret);
4454
4455 l1 = xmlXPathNodeSetGetLength(nodes1);
4456
4457 for (i = 0; i < l1; i++) {
4458 cur = xmlXPathNodeSetItem(nodes1, i);
4459 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4460 /* TODO: Propagate memory error. */
4461 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4462 break;
4463 }
4464 }
4465 return(ret);
4466}
4467
4479xmlNodeSetPtr
4480xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4481 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4482 int i, l1;
4484
4485 if (ret == NULL)
4486 return(ret);
4487 if (xmlXPathNodeSetIsEmpty(nodes1))
4488 return(ret);
4489 if (xmlXPathNodeSetIsEmpty(nodes2))
4490 return(ret);
4491
4492 l1 = xmlXPathNodeSetGetLength(nodes1);
4493
4494 for (i = 0; i < l1; i++) {
4495 cur = xmlXPathNodeSetItem(nodes1, i);
4496 if (xmlXPathNodeSetContains(nodes2, cur)) {
4497 /* TODO: Propagate memory error. */
4498 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4499 break;
4500 }
4501 }
4502 return(ret);
4503}
4504
4515xmlNodeSetPtr
4516xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4517 xmlNodeSetPtr ret;
4519 int i, l;
4520 xmlChar * strval;
4522
4523 if (xmlXPathNodeSetIsEmpty(nodes))
4524 return(nodes);
4525
4526 ret = xmlXPathNodeSetCreate(NULL);
4527 if (ret == NULL)
4528 return(ret);
4529 l = xmlXPathNodeSetGetLength(nodes);
4530 hash = xmlHashCreate (l);
4531 for (i = 0; i < l; i++) {
4532 cur = xmlXPathNodeSetItem(nodes, i);
4533 strval = xmlXPathCastNodeToString(cur);
4534 if (xmlHashLookup(hash, strval) == NULL) {
4536 /* TODO: Propagate memory error. */
4537 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4538 break;
4539 } else {
4540 xmlFree(strval);
4541 }
4542 }
4544 return(ret);
4545}
4546
4559xmlNodeSetPtr
4560xmlXPathDistinct (xmlNodeSetPtr nodes) {
4561 if (xmlXPathNodeSetIsEmpty(nodes))
4562 return(nodes);
4563
4564 xmlXPathNodeSetSort(nodes);
4565 return(xmlXPathDistinctSorted(nodes));
4566}
4567
4579int
4580xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4581 int i, l;
4583
4584 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4585 xmlXPathNodeSetIsEmpty(nodes2))
4586 return(0);
4587
4588 l = xmlXPathNodeSetGetLength(nodes1);
4589 for (i = 0; i < l; i++) {
4590 cur = xmlXPathNodeSetItem(nodes1, i);
4591 if (xmlXPathNodeSetContains(nodes2, cur))
4592 return(1);
4593 }
4594 return(0);
4595}
4596
4609xmlNodeSetPtr
4610xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4611 int i, l;
4613 xmlNodeSetPtr ret;
4614
4615 if (node == NULL)
4616 return(nodes);
4617
4618 ret = xmlXPathNodeSetCreate(NULL);
4619 if (ret == NULL)
4620 return(ret);
4621 if (xmlXPathNodeSetIsEmpty(nodes) ||
4622 (!xmlXPathNodeSetContains(nodes, node)))
4623 return(ret);
4624
4625 l = xmlXPathNodeSetGetLength(nodes);
4626 for (i = 0; i < l; i++) {
4627 cur = xmlXPathNodeSetItem(nodes, i);
4628 if (cur == node)
4629 break;
4630 /* TODO: Propagate memory error. */
4631 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4632 break;
4633 }
4634 return(ret);
4635}
4636
4651xmlNodeSetPtr
4652xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4653 xmlXPathNodeSetSort(nodes);
4654 return(xmlXPathNodeLeadingSorted(nodes, node));
4655}
4656
4669xmlNodeSetPtr
4670xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4671 if (xmlXPathNodeSetIsEmpty(nodes2))
4672 return(nodes1);
4673 return(xmlXPathNodeLeadingSorted(nodes1,
4674 xmlXPathNodeSetItem(nodes2, 1)));
4675}
4676
4691xmlNodeSetPtr
4692xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4693 if (xmlXPathNodeSetIsEmpty(nodes2))
4694 return(nodes1);
4695 if (xmlXPathNodeSetIsEmpty(nodes1))
4696 return(xmlXPathNodeSetCreate(NULL));
4697 xmlXPathNodeSetSort(nodes1);
4698 xmlXPathNodeSetSort(nodes2);
4699 return(xmlXPathNodeLeadingSorted(nodes1,
4700 xmlXPathNodeSetItem(nodes2, 1)));
4701}
4702
4715xmlNodeSetPtr
4716xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4717 int i, l;
4719 xmlNodeSetPtr ret;
4720
4721 if (node == NULL)
4722 return(nodes);
4723
4724 ret = xmlXPathNodeSetCreate(NULL);
4725 if (ret == NULL)
4726 return(ret);
4727 if (xmlXPathNodeSetIsEmpty(nodes) ||
4728 (!xmlXPathNodeSetContains(nodes, node)))
4729 return(ret);
4730
4731 l = xmlXPathNodeSetGetLength(nodes);
4732 for (i = l - 1; i >= 0; i--) {
4733 cur = xmlXPathNodeSetItem(nodes, i);
4734 if (cur == node)
4735 break;
4736 /* TODO: Propagate memory error. */
4737 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4738 break;
4739 }
4740 xmlXPathNodeSetSort(ret); /* bug 413451 */
4741 return(ret);
4742}
4743
4758xmlNodeSetPtr
4759xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4760 xmlXPathNodeSetSort(nodes);
4761 return(xmlXPathNodeTrailingSorted(nodes, node));
4762}
4763
4776xmlNodeSetPtr
4777xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4778 if (xmlXPathNodeSetIsEmpty(nodes2))
4779 return(nodes1);
4780 return(xmlXPathNodeTrailingSorted(nodes1,
4781 xmlXPathNodeSetItem(nodes2, 0)));
4782}
4783
4798xmlNodeSetPtr
4799xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4800 if (xmlXPathNodeSetIsEmpty(nodes2))
4801 return(nodes1);
4802 if (xmlXPathNodeSetIsEmpty(nodes1))
4803 return(xmlXPathNodeSetCreate(NULL));
4804 xmlXPathNodeSetSort(nodes1);
4805 xmlXPathNodeSetSort(nodes2);
4806 return(xmlXPathNodeTrailingSorted(nodes1,
4807 xmlXPathNodeSetItem(nodes2, 0)));
4808}
4809
4810/************************************************************************
4811 * *
4812 * Routines to handle extra functions *
4813 * *
4814 ************************************************************************/
4815
4826int
4827xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4828 xmlXPathFunction f) {
4829 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4830}
4831
4843int
4844xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4845 const xmlChar *ns_uri, xmlXPathFunction f) {
4846 if (ctxt == NULL)
4847 return(-1);
4848 if (name == NULL)
4849 return(-1);
4850
4851 if (ctxt->funcHash == NULL)
4852 ctxt->funcHash = xmlHashCreate(0);
4853 if (ctxt->funcHash == NULL)
4854 return(-1);
4855 if (f == NULL)
4856 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4858 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4860}
4861
4870void
4871xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4872 xmlXPathFuncLookupFunc f,
4873 void *funcCtxt) {
4874 if (ctxt == NULL)
4875 return;
4876 ctxt->funcLookupFunc = f;
4877 ctxt->funcLookupData = funcCtxt;
4878}
4879
4890xmlXPathFunction
4891xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4892 if (ctxt == NULL)
4893 return (NULL);
4894
4895 if (ctxt->funcLookupFunc != NULL) {
4896 xmlXPathFunction ret;
4897 xmlXPathFuncLookupFunc f;
4898
4899 f = ctxt->funcLookupFunc;
4900 ret = f(ctxt->funcLookupData, name, NULL);
4901 if (ret != NULL)
4902 return(ret);
4903 }
4904 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4905}
4906
4918xmlXPathFunction
4919xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4920 const xmlChar *ns_uri) {
4921 xmlXPathFunction ret;
4922
4923 if (ctxt == NULL)
4924 return(NULL);
4925 if (name == NULL)
4926 return(NULL);
4927
4928 if (ctxt->funcLookupFunc != NULL) {
4929 xmlXPathFuncLookupFunc f;
4930
4931 f = ctxt->funcLookupFunc;
4932 ret = f(ctxt->funcLookupData, name, ns_uri);
4933 if (ret != NULL)
4934 return(ret);
4935 }
4936
4937 if (ctxt->funcHash == NULL)
4938 return(NULL);
4939
4941 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4943 return(ret);
4944}
4945
4952void
4953xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4954 if (ctxt == NULL)
4955 return;
4956
4957 xmlHashFree(ctxt->funcHash, NULL);
4958 ctxt->funcHash = NULL;
4959}
4960
4961/************************************************************************
4962 * *
4963 * Routines to handle Variables *
4964 * *
4965 ************************************************************************/
4966
4978int
4979xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4980 xmlXPathObjectPtr value) {
4981 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4982}
4983
4996int
4997xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4998 const xmlChar *ns_uri,
4999 xmlXPathObjectPtr value) {
5000 if (ctxt == NULL)
5001 return(-1);
5002 if (name == NULL)
5003 return(-1);
5004
5005 if (ctxt->varHash == NULL)
5006 ctxt->varHash = xmlHashCreate(0);
5007 if (ctxt->varHash == NULL)
5008 return(-1);
5009 if (value == NULL)
5010 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5011 xmlXPathFreeObjectEntry));
5012 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5013 (void *) value, xmlXPathFreeObjectEntry));
5014}
5015
5024void
5025xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5026 xmlXPathVariableLookupFunc f, void *data) {
5027 if (ctxt == NULL)
5028 return;
5029 ctxt->varLookupFunc = f;
5030 ctxt->varLookupData = data;
5031}
5032
5043xmlXPathObjectPtr
5044xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5045 if (ctxt == NULL)
5046 return(NULL);
5047
5048 if (ctxt->varLookupFunc != NULL) {
5049 xmlXPathObjectPtr ret;
5050
5051 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5052 (ctxt->varLookupData, name, NULL);
5053 return(ret);
5054 }
5055 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5056}
5057
5069xmlXPathObjectPtr
5070xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5071 const xmlChar *ns_uri) {
5072 if (ctxt == NULL)
5073 return(NULL);
5074
5075 if (ctxt->varLookupFunc != NULL) {
5076 xmlXPathObjectPtr ret;
5077
5078 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5079 (ctxt->varLookupData, name, ns_uri);
5080 if (ret != NULL) return(ret);
5081 }
5082
5083 if (ctxt->varHash == NULL)
5084 return(NULL);
5085 if (name == NULL)
5086 return(NULL);
5087
5088 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5089 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5090}
5091
5098void
5099xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5100 if (ctxt == NULL)
5101 return;
5102
5103 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5104 ctxt->varHash = NULL;
5105}
5106
5118int
5119xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5120 const xmlChar *ns_uri) {
5121 if (ctxt == NULL)
5122 return(-1);
5123 if (prefix == NULL)
5124 return(-1);
5125 if (prefix[0] == 0)
5126 return(-1);
5127
5128 if (ctxt->nsHash == NULL)
5129 ctxt->nsHash = xmlHashCreate(10);
5130 if (ctxt->nsHash == NULL)
5131 return(-1);
5132 if (ns_uri == NULL)
5133 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5135 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5137}
5138
5149const xmlChar *
5150xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5151 if (ctxt == NULL)
5152 return(NULL);
5153 if (prefix == NULL)
5154 return(NULL);
5155
5156#ifdef XML_XML_NAMESPACE
5157 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5158 return(XML_XML_NAMESPACE);
5159#endif
5160
5161 if (ctxt->namespaces != NULL) {
5162 int i;
5163
5164 for (i = 0;i < ctxt->nsNr;i++) {
5165 if ((ctxt->namespaces[i] != NULL) &&
5166 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5167 return(ctxt->namespaces[i]->href);
5168 }
5169 }
5170
5171 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5172}
5173
5180void
5181xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5182 if (ctxt == NULL)
5183 return;
5184
5186 ctxt->nsHash = NULL;
5187}
5188
5189/************************************************************************
5190 * *
5191 * Routines to handle Values *
5192 * *
5193 ************************************************************************/
5194
5195/* Allocations are terrible, one needs to optimize all this !!! */
5196
5205xmlXPathObjectPtr
5206xmlXPathNewFloat(double val) {
5207 xmlXPathObjectPtr ret;
5208
5209 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5210 if (ret == NULL) {
5211 xmlXPathErrMemory(NULL, "creating float object\n");
5212 return(NULL);
5213 }
5214 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5215 ret->type = XPATH_NUMBER;
5216 ret->floatval = val;
5217#ifdef XP_DEBUG_OBJ_USAGE
5218 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5219#endif
5220 return(ret);
5221}
5222
5231xmlXPathObjectPtr
5232xmlXPathNewBoolean(int val) {
5233 xmlXPathObjectPtr ret;
5234
5235 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5236 if (ret == NULL) {
5237 xmlXPathErrMemory(NULL, "creating boolean object\n");
5238 return(NULL);
5239 }
5240 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5241 ret->type = XPATH_BOOLEAN;
5242 ret->boolval = (val != 0);
5243#ifdef XP_DEBUG_OBJ_USAGE
5244 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5245#endif
5246 return(ret);
5247}
5248
5257xmlXPathObjectPtr
5258xmlXPathNewString(const xmlChar *val) {
5259 xmlXPathObjectPtr ret;
5260
5261 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5262 if (ret == NULL) {
5263 xmlXPathErrMemory(NULL, "creating string object\n");
5264 return(NULL);
5265 }
5266 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5267 ret->type = XPATH_STRING;
5268 if (val != NULL)
5269 ret->stringval = xmlStrdup(val);
5270 else
5271 ret->stringval = xmlStrdup((const xmlChar *)"");
5272#ifdef XP_DEBUG_OBJ_USAGE
5273 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5274#endif
5275 return(ret);
5276}
5277
5286xmlXPathObjectPtr
5287xmlXPathWrapString (xmlChar *val) {
5288 xmlXPathObjectPtr ret;
5289
5290 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5291 if (ret == NULL) {
5292 xmlXPathErrMemory(NULL, "creating string object\n");
5293 return(NULL);
5294 }
5295 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5296 ret->type = XPATH_STRING;
5297 ret->stringval = val;
5298#ifdef XP_DEBUG_OBJ_USAGE
5299 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5300#endif
5301 return(ret);
5302}
5303
5312xmlXPathObjectPtr
5313xmlXPathNewCString(const char *val) {
5314 xmlXPathObjectPtr ret;
5315
5316 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5317 if (ret == NULL) {
5318 xmlXPathErrMemory(NULL, "creating string object\n");
5319 return(NULL);
5320 }
5321 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5322 ret->type = XPATH_STRING;
5323 ret->stringval = xmlStrdup(BAD_CAST val);
5324#ifdef XP_DEBUG_OBJ_USAGE
5325 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5326#endif
5327 return(ret);
5328}
5329
5338xmlXPathObjectPtr
5339xmlXPathWrapCString (char * val) {
5340 return(xmlXPathWrapString((xmlChar *)(val)));
5341}
5342
5351xmlXPathObjectPtr
5352xmlXPathWrapExternal (void *val) {
5353 xmlXPathObjectPtr ret;
5354
5355 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5356 if (ret == NULL) {
5357 xmlXPathErrMemory(NULL, "creating user object\n");
5358 return(NULL);
5359 }
5360 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5361 ret->type = XPATH_USERS;
5362 ret->user = val;
5363#ifdef XP_DEBUG_OBJ_USAGE
5364 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5365#endif
5366 return(ret);
5367}
5368
5377xmlXPathObjectPtr
5378xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5379 xmlXPathObjectPtr ret;
5380
5381 if (val == NULL)
5382 return(NULL);
5383
5384 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5385 if (ret == NULL) {
5386 xmlXPathErrMemory(NULL, "copying object\n");
5387 return(NULL);
5388 }
5389 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5390#ifdef XP_DEBUG_OBJ_USAGE
5391 xmlXPathDebugObjUsageRequested(NULL, val->type);
5392#endif
5393 switch (val->type) {
5394 case XPATH_BOOLEAN:
5395 case XPATH_NUMBER:
5396#ifdef LIBXML_XPTR_LOCS_ENABLED
5397 case XPATH_POINT:
5398 case XPATH_RANGE:
5399#endif /* LIBXML_XPTR_LOCS_ENABLED */
5400 break;
5401 case XPATH_STRING:
5402 ret->stringval = xmlStrdup(val->stringval);
5403 break;
5404 case XPATH_XSLT_TREE:
5405#if 0
5406/*
5407 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5408 this previous handling is no longer correct, and can cause some serious
5409 problems (ref. bug 145547)
5410*/
5411 if ((val->nodesetval != NULL) &&
5412 (val->nodesetval->nodeTab != NULL)) {
5413 xmlNodePtr cur, tmp;
5414 xmlDocPtr top;
5415
5416 ret->boolval = 1;
5417 top = xmlNewDoc(NULL);
5418 top->name = (char *)
5419 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5420 ret->user = top;
5421 if (top != NULL) {
5422 top->doc = top;
5423 cur = val->nodesetval->nodeTab[0]->children;
5424 while (cur != NULL) {
5425 tmp = xmlDocCopyNode(cur, top, 1);
5426 xmlAddChild((xmlNodePtr) top, tmp);
5427 cur = cur->next;
5428 }
5429 }
5430
5431 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5432 } else
5433 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5434 /* Deallocate the copied tree value */
5435 break;
5436#endif
5437 case XPATH_NODESET:
5438 /* TODO: Check memory error. */
5439 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5440 /* Do not deallocate the copied tree value */
5441 ret->boolval = 0;
5442 break;
5443#ifdef LIBXML_XPTR_LOCS_ENABLED
5444 case XPATH_LOCATIONSET:
5445 {
5446 xmlLocationSetPtr loc = val->user;
5447 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5448 break;
5449 }
5450#endif
5451 case XPATH_USERS:
5452 ret->user = val->user;
5453 break;
5454 case XPATH_UNDEFINED:
5456 "xmlXPathObjectCopy: unsupported type %d\n",
5457 val->type);
5458 break;
5459 }
5460 return(ret);
5461}
5462
5469void
5470xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5471 if (obj == NULL) return;
5472 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5473 if (obj->boolval) {
5474#if 0
5475 if (obj->user != NULL) {
5476 xmlXPathFreeNodeSet(obj->nodesetval);
5478 } else
5479#endif
5480 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5481 if (obj->nodesetval != NULL)
5482 xmlXPathFreeValueTree(obj->nodesetval);
5483 } else {
5484 if (obj->nodesetval != NULL)
5485 xmlXPathFreeNodeSet(obj->nodesetval);
5486 }
5487#ifdef LIBXML_XPTR_LOCS_ENABLED
5488 } else if (obj->type == XPATH_LOCATIONSET) {
5489 if (obj->user != NULL)
5490 xmlXPtrFreeLocationSet(obj->user);
5491#endif
5492 } else if (obj->type == XPATH_STRING) {
5493 if (obj->stringval != NULL)
5494 xmlFree(obj->stringval);
5495 }
5496#ifdef XP_DEBUG_OBJ_USAGE
5497 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5498#endif
5499 xmlFree(obj);
5500}
5501
5502static void
5503xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5504 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5505}
5506
5514static void
5515xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5516{
5517#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5518 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5519 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5520
5521#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5522
5523 if (obj == NULL)
5524 return;
5525 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5526 xmlXPathFreeObject(obj);
5527 } else {
5528 xmlXPathContextCachePtr cache =
5529 (xmlXPathContextCachePtr) ctxt->cache;
5530
5531 switch (obj->type) {
5532 case XPATH_NODESET:
5533 case XPATH_XSLT_TREE:
5534 if (obj->nodesetval != NULL) {
5535 if (obj->boolval) {
5536 /*
5537 * It looks like the @boolval is used for
5538 * evaluation if this an XSLT Result Tree Fragment.
5539 * TODO: Check if this assumption is correct.
5540 */
5541 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5542 xmlXPathFreeValueTree(obj->nodesetval);
5543 obj->nodesetval = NULL;
5544 } else if ((obj->nodesetval->nodeMax <= 40) &&
5545 (XP_CACHE_WANTS(cache->nodesetObjs,
5546 cache->maxNodeset)))
5547 {
5548 XP_CACHE_ADD(cache->nodesetObjs, obj);
5549 goto obj_cached;
5550 } else {
5551 xmlXPathFreeNodeSet(obj->nodesetval);
5552 obj->nodesetval = NULL;
5553 }
5554 }
5555 break;
5556 case XPATH_STRING:
5557 if (obj->stringval != NULL)
5558 xmlFree(obj->stringval);
5559
5560 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5561 XP_CACHE_ADD(cache->stringObjs, obj);
5562 goto obj_cached;
5563 }
5564 break;
5565 case XPATH_BOOLEAN:
5566 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5567 XP_CACHE_ADD(cache->booleanObjs, obj);
5568 goto obj_cached;
5569 }
5570 break;
5571 case XPATH_NUMBER:
5572 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5573 XP_CACHE_ADD(cache->numberObjs, obj);
5574 goto obj_cached;
5575 }
5576 break;
5577#ifdef LIBXML_XPTR_LOCS_ENABLED
5578 case XPATH_LOCATIONSET:
5579 if (obj->user != NULL) {
5580 xmlXPtrFreeLocationSet(obj->user);
5581 }
5582 goto free_obj;
5583#endif
5584 default:
5585 goto free_obj;
5586 }
5587
5588 /*
5589 * Fallback to adding to the misc-objects slot.
5590 */
5591 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5592 XP_CACHE_ADD(cache->miscObjs, obj);
5593 } else
5594 goto free_obj;
5595
5596obj_cached:
5597
5598#ifdef XP_DEBUG_OBJ_USAGE
5599 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5600#endif
5601
5602 if (obj->nodesetval != NULL) {
5603 xmlNodeSetPtr tmpset = obj->nodesetval;
5604
5605 /*
5606 * TODO: Due to those nasty ns-nodes, we need to traverse
5607 * the list and free the ns-nodes.
5608 * URGENT TODO: Check if it's actually slowing things down.
5609 * Maybe we shouldn't try to preserve the list.
5610 */
5611 if (tmpset->nodeNr > 1) {
5612 int i;
5614
5615 for (i = 0; i < tmpset->nodeNr; i++) {
5616 node = tmpset->nodeTab[i];
5617 if ((node != NULL) &&
5618 (node->type == XML_NAMESPACE_DECL))
5619 {
5620 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5621 }
5622 }
5623 } else if (tmpset->nodeNr == 1) {
5624 if ((tmpset->nodeTab[0] != NULL) &&
5625 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5626 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5627 }
5628 tmpset->nodeNr = 0;
5629 memset(obj, 0, sizeof(xmlXPathObject));
5630 obj->nodesetval = tmpset;
5631 } else
5632 memset(obj, 0, sizeof(xmlXPathObject));
5633
5634 return;
5635
5636free_obj:
5637 /*
5638 * Cache is full; free the object.
5639 */
5640 if (obj->nodesetval != NULL)
5641 xmlXPathFreeNodeSet(obj->nodesetval);
5642#ifdef XP_DEBUG_OBJ_USAGE
5643 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5644#endif
5645 xmlFree(obj);
5646 }
5647 return;
5648}
5649
5650
5651/************************************************************************
5652 * *
5653 * Type Casting Routines *
5654 * *
5655 ************************************************************************/
5656
5665xmlChar *
5666xmlXPathCastBooleanToString (int val) {
5667 xmlChar *ret;
5668 if (val)
5669 ret = xmlStrdup((const xmlChar *) "true");
5670 else
5671 ret = xmlStrdup((const xmlChar *) "false");
5672 return(ret);
5673}
5674
5683xmlChar *
5684xmlXPathCastNumberToString (double val) {
5685 xmlChar *ret;
5686 switch (xmlXPathIsInf(val)) {
5687 case 1:
5688 ret = xmlStrdup((const xmlChar *) "Infinity");
5689 break;
5690 case -1:
5691 ret = xmlStrdup((const xmlChar *) "-Infinity");
5692 break;
5693 default:
5694 if (xmlXPathIsNaN(val)) {
5695 ret = xmlStrdup((const xmlChar *) "NaN");
5696 } else if (val == 0) {
5697 /* Omit sign for negative zero. */
5698 ret = xmlStrdup((const xmlChar *) "0");
5699 } else {
5700 /* could be improved */
5701 char buf[100];
5702 xmlXPathFormatNumber(val, buf, 99);
5703 buf[99] = 0;
5704 ret = xmlStrdup((const xmlChar *) buf);
5705 }
5706 }
5707 return(ret);
5708}
5709
5718xmlChar *
5719xmlXPathCastNodeToString (xmlNodePtr node) {
5720xmlChar *ret;
5721 if ((ret = xmlNodeGetContent(node)) == NULL)
5722 ret = xmlStrdup((const xmlChar *) "");
5723 return(ret);
5724}
5725
5734xmlChar *
5735xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5736 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5737 return(xmlStrdup((const xmlChar *) ""));
5738
5739 if (ns->nodeNr > 1)
5740 xmlXPathNodeSetSort(ns);
5741 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5742}
5743
5753xmlChar *
5754xmlXPathCastToString(xmlXPathObjectPtr val) {
5755 xmlChar *ret = NULL;
5756
5757 if (val == NULL)
5758 return(xmlStrdup((const xmlChar *) ""));
5759 switch (val->type) {
5760 case XPATH_UNDEFINED:
5761#ifdef DEBUG_EXPR
5762 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5763#endif
5764 ret = xmlStrdup((const xmlChar *) "");
5765 break;
5766 case XPATH_NODESET:
5767 case XPATH_XSLT_TREE:
5768 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5769 break;
5770 case XPATH_STRING:
5771 return(xmlStrdup(val->stringval));
5772 case XPATH_BOOLEAN:
5773 ret = xmlXPathCastBooleanToString(val->boolval);
5774 break;
5775 case XPATH_NUMBER: {
5776 ret = xmlXPathCastNumberToString(val->floatval);
5777 break;
5778 }
5779 case XPATH_USERS:
5780#ifdef LIBXML_XPTR_LOCS_ENABLED
5781 case XPATH_POINT:
5782 case XPATH_RANGE:
5783 case XPATH_LOCATIONSET:
5784#endif /* LIBXML_XPTR_LOCS_ENABLED */
5785 TODO
5786 ret = xmlStrdup((const xmlChar *) "");
5787 break;
5788 }
5789 return(ret);
5790}
5791
5801xmlXPathObjectPtr
5802xmlXPathConvertString(xmlXPathObjectPtr val) {
5803 xmlChar *res = NULL;
5804
5805 if (val == NULL)
5806 return(xmlXPathNewCString(""));
5807
5808 switch (val->type) {
5809 case XPATH_UNDEFINED:
5810#ifdef DEBUG_EXPR
5811 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5812#endif
5813 break;
5814 case XPATH_NODESET:
5815 case XPATH_XSLT_TREE:
5816 res = xmlXPathCastNodeSetToString(val->nodesetval);
5817 break;
5818 case XPATH_STRING:
5819 return(val);
5820 case XPATH_BOOLEAN:
5821 res = xmlXPathCastBooleanToString(val->boolval);
5822 break;
5823 case XPATH_NUMBER:
5824 res = xmlXPathCastNumberToString(val->floatval);
5825 break;
5826 case XPATH_USERS:
5827#ifdef LIBXML_XPTR_LOCS_ENABLED
5828 case XPATH_POINT:
5829 case XPATH_RANGE:
5830 case XPATH_LOCATIONSET:
5831#endif /* LIBXML_XPTR_LOCS_ENABLED */
5832 TODO;
5833 break;
5834 }
5835 xmlXPathFreeObject(val);
5836 if (res == NULL)
5837 return(xmlXPathNewCString(""));
5838 return(xmlXPathWrapString(res));
5839}
5840
5849double
5850xmlXPathCastBooleanToNumber(int val) {
5851 if (val)
5852 return(1.0);
5853 return(0.0);
5854}
5855
5864double
5865xmlXPathCastStringToNumber(const xmlChar * val) {
5867}
5868
5877double
5878xmlXPathCastNodeToNumber (xmlNodePtr node) {
5879 xmlChar *strval;
5880 double ret;
5881
5882 if (node == NULL)
5883 return(xmlXPathNAN);
5884 strval = xmlXPathCastNodeToString(node);
5885 if (strval == NULL)
5886 return(xmlXPathNAN);
5887 ret = xmlXPathCastStringToNumber(strval);
5888 xmlFree(strval);
5889
5890 return(ret);
5891}
5892
5901double
5902xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5903 xmlChar *str;
5904 double ret;
5905
5906 if (ns == NULL)
5907 return(xmlXPathNAN);
5908 str = xmlXPathCastNodeSetToString(ns);
5909 ret = xmlXPathCastStringToNumber(str);
5910 xmlFree(str);
5911 return(ret);
5912}
5913
5922double
5923xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5924 double ret = 0.0;
5925
5926 if (val == NULL)
5927 return(xmlXPathNAN);
5928 switch (val->type) {
5929 case XPATH_UNDEFINED:
5930#ifdef DEBUG_EXPR
5931 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5932#endif
5933 ret = xmlXPathNAN;
5934 break;
5935 case XPATH_NODESET:
5936 case XPATH_XSLT_TREE:
5937 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5938 break;
5939 case XPATH_STRING:
5940 ret = xmlXPathCastStringToNumber(val->stringval);
5941 break;
5942 case XPATH_NUMBER:
5943 ret = val->floatval;
5944 break;
5945 case XPATH_BOOLEAN:
5946 ret = xmlXPathCastBooleanToNumber(val->boolval);
5947 break;
5948 case XPATH_USERS:
5949#ifdef LIBXML_XPTR_LOCS_ENABLED
5950 case XPATH_POINT:
5951 case XPATH_RANGE:
5952 case XPATH_LOCATIONSET:
5953#endif /* LIBXML_XPTR_LOCS_ENABLED */
5954 TODO;
5955 ret = xmlXPathNAN;
5956 break;
5957 }
5958 return(ret);
5959}
5960
5970xmlXPathObjectPtr
5971xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5972 xmlXPathObjectPtr ret;
5973
5974 if (val == NULL)
5975 return(xmlXPathNewFloat(0.0));
5976 if (val->type == XPATH_NUMBER)
5977 return(val);
5978 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5979 xmlXPathFreeObject(val);
5980 return(ret);
5981}
5982
5991int
5992xmlXPathCastNumberToBoolean (double val) {
5993 if (xmlXPathIsNaN(val) || (val == 0.0))
5994 return(0);
5995 return(1);
5996}
5997
6006int
6007xmlXPathCastStringToBoolean (const xmlChar *val) {
6008 if ((val == NULL) || (xmlStrlen(val) == 0))
6009 return(0);
6010 return(1);
6011}
6012
6021int
6022xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6023 if ((ns == NULL) || (ns->nodeNr == 0))
6024 return(0);
6025 return(1);
6026}
6027
6036int
6037xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6038 int ret = 0;
6039
6040 if (val == NULL)
6041 return(0);
6042 switch (val->type) {
6043 case XPATH_UNDE