352747313f0b62b2acad6650ac384988802fce70
[reactos.git] / sdk / lib / 3rdparty / libxml2 / xpath.c
1 /*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *f
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See Copyright for the status of this software
12 *
13 * Author: daniel@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
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_MATH_H
33 #include <math.h>
34 #endif
35 #ifdef HAVE_FLOAT_H
36 #include <float.h>
37 #endif
38 #ifdef HAVE_CTYPE_H
39 #include <ctype.h>
40 #endif
41 #ifdef HAVE_SIGNAL_H
42 #include <signal.h>
43 #endif
44
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
54 #endif
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
57 #endif
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
63 #endif
64
65 #include "buf.h"
66
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
69 #endif
70
71 #define TODO \
72 xmlGenericError(xmlGenericErrorContext, \
73 "Unimplemented block at %s:%d\n", \
74 __FILE__, __LINE__);
75
76 /**
77 * WITH_TIM_SORT:
78 *
79 * Use the Timsort algorithm provided in timsort.h to sort
80 * nodeset as this is a great improvement over the old Shell sort
81 * used in xmlXPathNodeSetSort()
82 */
83 #define WITH_TIM_SORT
84
85 /*
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
93 */
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
95
96 /*
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
100 */
101 #define XP_OPTIMIZED_FILTER_FIRST
102
103 /*
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
106 * created.
107 */
108 /* #define XP_DEBUG_OBJ_USAGE */
109
110 /*
111 * XPATH_MAX_STEPS:
112 * when compiling an XPath expression we arbitrary limit the maximum
113 * number of step operation in the compiled expression. 1000000 is
114 * an insanely large value which should never be reached under normal
115 * circumstances
116 */
117 #define XPATH_MAX_STEPS 1000000
118
119 /*
120 * XPATH_MAX_STACK_DEPTH:
121 * when evaluating an XPath expression we arbitrary limit the maximum
122 * number of object allowed to be pushed on the stack. 1000000 is
123 * an insanely large value which should never be reached under normal
124 * circumstances
125 */
126 #define XPATH_MAX_STACK_DEPTH 1000000
127
128 /*
129 * XPATH_MAX_NODESET_LENGTH:
130 * when evaluating an XPath expression nodesets are created and we
131 * arbitrary limit the maximum length of those node set. 10000000 is
132 * an insanely large value which should never be reached under normal
133 * circumstances, one would first need to construct an in memory tree
134 * with more than 10 millions nodes.
135 */
136 #define XPATH_MAX_NODESET_LENGTH 10000000
137
138 /*
139 * TODO:
140 * There are a few spots where some tests are done which depend upon ascii
141 * data. These should be enhanced for full UTF8 support (see particularly
142 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
143 */
144
145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
146 /**
147 * xmlXPathCmpNodesExt:
148 * @node1: the first node
149 * @node2: the second node
150 *
151 * Compare two nodes w.r.t document order.
152 * This one is optimized for handling of non-element nodes.
153 *
154 * Returns -2 in case of error 1 if first point < second point, 0 if
155 * it's the same node, -1 otherwise
156 */
157 static int
158 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
159 int depth1, depth2;
160 int misc = 0, precedence1 = 0, precedence2 = 0;
161 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
162 xmlNodePtr cur, root;
163 ptrdiff_t l1, l2;
164
165 if ((node1 == NULL) || (node2 == NULL))
166 return(-2);
167
168 if (node1 == node2)
169 return(0);
170
171 /*
172 * a couple of optimizations which will avoid computations in most cases
173 */
174 switch (node1->type) {
175 case XML_ELEMENT_NODE:
176 if (node2->type == XML_ELEMENT_NODE) {
177 if ((0 > (ptrdiff_t) node1->content) &&
178 (0 > (ptrdiff_t) node2->content) &&
179 (node1->doc == node2->doc))
180 {
181 l1 = -((ptrdiff_t) node1->content);
182 l2 = -((ptrdiff_t) node2->content);
183 if (l1 < l2)
184 return(1);
185 if (l1 > l2)
186 return(-1);
187 } else
188 goto turtle_comparison;
189 }
190 break;
191 case XML_ATTRIBUTE_NODE:
192 precedence1 = 1; /* element is owner */
193 miscNode1 = node1;
194 node1 = node1->parent;
195 misc = 1;
196 break;
197 case XML_TEXT_NODE:
198 case XML_CDATA_SECTION_NODE:
199 case XML_COMMENT_NODE:
200 case XML_PI_NODE: {
201 miscNode1 = node1;
202 /*
203 * Find nearest element node.
204 */
205 if (node1->prev != NULL) {
206 do {
207 node1 = node1->prev;
208 if (node1->type == XML_ELEMENT_NODE) {
209 precedence1 = 3; /* element in prev-sibl axis */
210 break;
211 }
212 if (node1->prev == NULL) {
213 precedence1 = 2; /* element is parent */
214 /*
215 * URGENT TODO: Are there any cases, where the
216 * parent of such a node is not an element node?
217 */
218 node1 = node1->parent;
219 break;
220 }
221 } while (1);
222 } else {
223 precedence1 = 2; /* element is parent */
224 node1 = node1->parent;
225 }
226 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
227 (0 <= (ptrdiff_t) node1->content)) {
228 /*
229 * Fallback for whatever case.
230 */
231 node1 = miscNode1;
232 precedence1 = 0;
233 } else
234 misc = 1;
235 }
236 break;
237 case XML_NAMESPACE_DECL:
238 /*
239 * TODO: why do we return 1 for namespace nodes?
240 */
241 return(1);
242 default:
243 break;
244 }
245 switch (node2->type) {
246 case XML_ELEMENT_NODE:
247 break;
248 case XML_ATTRIBUTE_NODE:
249 precedence2 = 1; /* element is owner */
250 miscNode2 = node2;
251 node2 = node2->parent;
252 misc = 1;
253 break;
254 case XML_TEXT_NODE:
255 case XML_CDATA_SECTION_NODE:
256 case XML_COMMENT_NODE:
257 case XML_PI_NODE: {
258 miscNode2 = node2;
259 if (node2->prev != NULL) {
260 do {
261 node2 = node2->prev;
262 if (node2->type == XML_ELEMENT_NODE) {
263 precedence2 = 3; /* element in prev-sibl axis */
264 break;
265 }
266 if (node2->prev == NULL) {
267 precedence2 = 2; /* element is parent */
268 node2 = node2->parent;
269 break;
270 }
271 } while (1);
272 } else {
273 precedence2 = 2; /* element is parent */
274 node2 = node2->parent;
275 }
276 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
277 (0 <= (ptrdiff_t) node2->content))
278 {
279 node2 = miscNode2;
280 precedence2 = 0;
281 } else
282 misc = 1;
283 }
284 break;
285 case XML_NAMESPACE_DECL:
286 return(1);
287 default:
288 break;
289 }
290 if (misc) {
291 if (node1 == node2) {
292 if (precedence1 == precedence2) {
293 /*
294 * The ugly case; but normally there aren't many
295 * adjacent non-element nodes around.
296 */
297 cur = miscNode2->prev;
298 while (cur != NULL) {
299 if (cur == miscNode1)
300 return(1);
301 if (cur->type == XML_ELEMENT_NODE)
302 return(-1);
303 cur = cur->prev;
304 }
305 return (-1);
306 } else {
307 /*
308 * Evaluate based on higher precedence wrt to the element.
309 * TODO: This assumes attributes are sorted before content.
310 * Is this 100% correct?
311 */
312 if (precedence1 < precedence2)
313 return(1);
314 else
315 return(-1);
316 }
317 }
318 /*
319 * Special case: One of the helper-elements is contained by the other.
320 * <foo>
321 * <node2>
322 * <node1>Text-1(precedence1 == 2)</node1>
323 * </node2>
324 * Text-6(precedence2 == 3)
325 * </foo>
326 */
327 if ((precedence2 == 3) && (precedence1 > 1)) {
328 cur = node1->parent;
329 while (cur) {
330 if (cur == node2)
331 return(1);
332 cur = cur->parent;
333 }
334 }
335 if ((precedence1 == 3) && (precedence2 > 1)) {
336 cur = node2->parent;
337 while (cur) {
338 if (cur == node1)
339 return(-1);
340 cur = cur->parent;
341 }
342 }
343 }
344
345 /*
346 * Speedup using document order if availble.
347 */
348 if ((node1->type == XML_ELEMENT_NODE) &&
349 (node2->type == XML_ELEMENT_NODE) &&
350 (0 > (ptrdiff_t) node1->content) &&
351 (0 > (ptrdiff_t) node2->content) &&
352 (node1->doc == node2->doc)) {
353
354 l1 = -((ptrdiff_t) node1->content);
355 l2 = -((ptrdiff_t) node2->content);
356 if (l1 < l2)
357 return(1);
358 if (l1 > l2)
359 return(-1);
360 }
361
362 turtle_comparison:
363
364 if (node1 == node2->prev)
365 return(1);
366 if (node1 == node2->next)
367 return(-1);
368 /*
369 * compute depth to root
370 */
371 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
372 if (cur->parent == node1)
373 return(1);
374 depth2++;
375 }
376 root = cur;
377 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
378 if (cur->parent == node2)
379 return(-1);
380 depth1++;
381 }
382 /*
383 * Distinct document (or distinct entities :-( ) case.
384 */
385 if (root != cur) {
386 return(-2);
387 }
388 /*
389 * get the nearest common ancestor.
390 */
391 while (depth1 > depth2) {
392 depth1--;
393 node1 = node1->parent;
394 }
395 while (depth2 > depth1) {
396 depth2--;
397 node2 = node2->parent;
398 }
399 while (node1->parent != node2->parent) {
400 node1 = node1->parent;
401 node2 = node2->parent;
402 /* should not happen but just in case ... */
403 if ((node1 == NULL) || (node2 == NULL))
404 return(-2);
405 }
406 /*
407 * Find who's first.
408 */
409 if (node1 == node2->prev)
410 return(1);
411 if (node1 == node2->next)
412 return(-1);
413 /*
414 * Speedup using document order if availble.
415 */
416 if ((node1->type == XML_ELEMENT_NODE) &&
417 (node2->type == XML_ELEMENT_NODE) &&
418 (0 > (ptrdiff_t) node1->content) &&
419 (0 > (ptrdiff_t) node2->content) &&
420 (node1->doc == node2->doc)) {
421
422 l1 = -((ptrdiff_t) node1->content);
423 l2 = -((ptrdiff_t) node2->content);
424 if (l1 < l2)
425 return(1);
426 if (l1 > l2)
427 return(-1);
428 }
429
430 for (cur = node1->next;cur != NULL;cur = cur->next)
431 if (cur == node2)
432 return(1);
433 return(-1); /* assume there is no sibling list corruption */
434 }
435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
436
437 /*
438 * Wrapper for the Timsort argorithm from timsort.h
439 */
440 #ifdef WITH_TIM_SORT
441 #define SORT_NAME libxml_domnode
442 #define SORT_TYPE xmlNodePtr
443 /**
444 * wrap_cmp:
445 * @x: a node
446 * @y: another node
447 *
448 * Comparison function for the Timsort implementation
449 *
450 * Returns -2 in case of error -1 if first point < second point, 0 if
451 * it's the same node, +1 otherwise
452 */
453 static
454 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
456 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
457 {
458 int res = xmlXPathCmpNodesExt(x, y);
459 return res == -2 ? res : -res;
460 }
461 #else
462 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463 {
464 int res = xmlXPathCmpNodes(x, y);
465 return res == -2 ? res : -res;
466 }
467 #endif
468 #define SORT_CMP(x, y) (wrap_cmp(x, y))
469 #include "timsort.h"
470 #endif /* WITH_TIM_SORT */
471
472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
473
474 /************************************************************************
475 * *
476 * Floating point stuff *
477 * *
478 ************************************************************************/
479
480 #ifndef TRIO_REPLACE_STDIO
481 #define TRIO_PUBLIC static
482 #endif
483 #include "trionan.c"
484
485 /*
486 * The lack of portability of this section of the libc is annoying !
487 */
488 double xmlXPathNAN = 0;
489 double xmlXPathPINF = 1;
490 double xmlXPathNINF = -1;
491 static double xmlXPathNZERO = 0; /* not exported from headers */
492 static int xmlXPathInitialized = 0;
493
494 /**
495 * xmlXPathInit:
496 *
497 * Initialize the XPath environment
498 */
499 void
500 xmlXPathInit(void) {
501 if (xmlXPathInitialized) return;
502
503 xmlXPathPINF = trio_pinf();
504 xmlXPathNINF = trio_ninf();
505 xmlXPathNAN = trio_nan();
506 xmlXPathNZERO = trio_nzero();
507
508 xmlXPathInitialized = 1;
509 }
510
511 /**
512 * xmlXPathIsNaN:
513 * @val: a double value
514 *
515 * Provides a portable isnan() function to detect whether a double
516 * is a NotaNumber. Based on trio code
517 * http://sourceforge.net/projects/ctrio/
518 *
519 * Returns 1 if the value is a NaN, 0 otherwise
520 */
521 int
522 xmlXPathIsNaN(double val) {
523 return(trio_isnan(val));
524 }
525
526 /**
527 * xmlXPathIsInf:
528 * @val: a double value
529 *
530 * Provides a portable isinf() function to detect whether a double
531 * is a +Infinite or -Infinite. Based on trio code
532 * http://sourceforge.net/projects/ctrio/
533 *
534 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
535 */
536 int
537 xmlXPathIsInf(double val) {
538 return(trio_isinf(val));
539 }
540
541 #endif /* SCHEMAS or XPATH */
542 #ifdef LIBXML_XPATH_ENABLED
543 /**
544 * xmlXPathGetSign:
545 * @val: a double value
546 *
547 * Provides a portable function to detect the sign of a double
548 * Modified from trio code
549 * http://sourceforge.net/projects/ctrio/
550 *
551 * Returns 1 if the value is Negative, 0 if positive
552 */
553 static int
554 xmlXPathGetSign(double val) {
555 return(trio_signbit(val));
556 }
557
558
559 /*
560 * TODO: when compatibility allows remove all "fake node libxslt" strings
561 * the test should just be name[0] = ' '
562 */
563 #ifdef DEBUG_XPATH_EXPRESSION
564 #define DEBUG_STEP
565 #define DEBUG_EXPR
566 #define DEBUG_EVAL_COUNTS
567 #endif
568
569 static xmlNs xmlXPathXMLNamespaceStruct = {
570 NULL,
571 XML_NAMESPACE_DECL,
572 XML_XML_NAMESPACE,
573 BAD_CAST "xml",
574 NULL,
575 NULL
576 };
577 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
578 #ifndef LIBXML_THREAD_ENABLED
579 /*
580 * Optimizer is disabled only when threaded apps are detected while
581 * the library ain't compiled for thread safety.
582 */
583 static int xmlXPathDisableOptimizer = 0;
584 #endif
585
586 /************************************************************************
587 * *
588 * Error handling routines *
589 * *
590 ************************************************************************/
591
592 /**
593 * XP_ERRORNULL:
594 * @X: the error code
595 *
596 * Macro to raise an XPath error and return NULL.
597 */
598 #define XP_ERRORNULL(X) \
599 { xmlXPathErr(ctxt, X); return(NULL); }
600
601 /*
602 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603 */
604 static const char *xmlXPathErrorMessages[] = {
605 "Ok\n",
606 "Number encoding\n",
607 "Unfinished literal\n",
608 "Start of literal\n",
609 "Expected $ for variable reference\n",
610 "Undefined variable\n",
611 "Invalid predicate\n",
612 "Invalid expression\n",
613 "Missing closing curly brace\n",
614 "Unregistered function\n",
615 "Invalid operand\n",
616 "Invalid type\n",
617 "Invalid number of arguments\n",
618 "Invalid context size\n",
619 "Invalid context position\n",
620 "Memory allocation error\n",
621 "Syntax error\n",
622 "Resource error\n",
623 "Sub resource error\n",
624 "Undefined namespace prefix\n",
625 "Encoding error\n",
626 "Char out of XML range\n",
627 "Invalid or incomplete context\n",
628 "Stack usage error\n",
629 "Forbidden variable\n",
630 "?? Unknown error ??\n" /* Must be last in the list! */
631 };
632 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
633 sizeof(xmlXPathErrorMessages[0])) - 1)
634 /**
635 * xmlXPathErrMemory:
636 * @ctxt: an XPath context
637 * @extra: extra informations
638 *
639 * Handle a redefinition of attribute error
640 */
641 static void
642 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
643 {
644 if (ctxt != NULL) {
645 if (extra) {
646 xmlChar buf[200];
647
648 xmlStrPrintf(buf, 200,
649 "Memory allocation failed : %s\n",
650 extra);
651 ctxt->lastError.message = (char *) xmlStrdup(buf);
652 } else {
653 ctxt->lastError.message = (char *)
654 xmlStrdup(BAD_CAST "Memory allocation failed\n");
655 }
656 ctxt->lastError.domain = XML_FROM_XPATH;
657 ctxt->lastError.code = XML_ERR_NO_MEMORY;
658 if (ctxt->error != NULL)
659 ctxt->error(ctxt->userData, &ctxt->lastError);
660 } else {
661 if (extra)
662 __xmlRaiseError(NULL, NULL, NULL,
663 NULL, NULL, XML_FROM_XPATH,
664 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
665 extra, NULL, NULL, 0, 0,
666 "Memory allocation failed : %s\n", extra);
667 else
668 __xmlRaiseError(NULL, NULL, NULL,
669 NULL, NULL, XML_FROM_XPATH,
670 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
671 NULL, NULL, NULL, 0, 0,
672 "Memory allocation failed\n");
673 }
674 }
675
676 /**
677 * xmlXPathPErrMemory:
678 * @ctxt: an XPath parser context
679 * @extra: extra informations
680 *
681 * Handle a redefinition of attribute error
682 */
683 static void
684 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
685 {
686 if (ctxt == NULL)
687 xmlXPathErrMemory(NULL, extra);
688 else {
689 ctxt->error = XPATH_MEMORY_ERROR;
690 xmlXPathErrMemory(ctxt->context, extra);
691 }
692 }
693
694 /**
695 * xmlXPathErr:
696 * @ctxt: a XPath parser context
697 * @error: the error code
698 *
699 * Handle an XPath error
700 */
701 void
702 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
703 {
704 if ((error < 0) || (error > MAXERRNO))
705 error = MAXERRNO;
706 if (ctxt == NULL) {
707 __xmlRaiseError(NULL, NULL, NULL,
708 NULL, NULL, XML_FROM_XPATH,
709 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
710 XML_ERR_ERROR, NULL, 0,
711 NULL, NULL, NULL, 0, 0,
712 "%s", xmlXPathErrorMessages[error]);
713 return;
714 }
715 ctxt->error = error;
716 if (ctxt->context == NULL) {
717 __xmlRaiseError(NULL, NULL, NULL,
718 NULL, NULL, XML_FROM_XPATH,
719 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
720 XML_ERR_ERROR, NULL, 0,
721 (const char *) ctxt->base, NULL, NULL,
722 ctxt->cur - ctxt->base, 0,
723 "%s", xmlXPathErrorMessages[error]);
724 return;
725 }
726
727 /* cleanup current last error */
728 xmlResetError(&ctxt->context->lastError);
729
730 ctxt->context->lastError.domain = XML_FROM_XPATH;
731 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732 XPATH_EXPRESSION_OK;
733 ctxt->context->lastError.level = XML_ERR_ERROR;
734 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736 ctxt->context->lastError.node = ctxt->context->debugNode;
737 if (ctxt->context->error != NULL) {
738 ctxt->context->error(ctxt->context->userData,
739 &ctxt->context->lastError);
740 } else {
741 __xmlRaiseError(NULL, NULL, NULL,
742 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744 XML_ERR_ERROR, NULL, 0,
745 (const char *) ctxt->base, NULL, NULL,
746 ctxt->cur - ctxt->base, 0,
747 "%s", xmlXPathErrorMessages[error]);
748 }
749
750 }
751
752 /**
753 * xmlXPatherror:
754 * @ctxt: the XPath Parser context
755 * @file: the file name
756 * @line: the line number
757 * @no: the error number
758 *
759 * Formats an error message.
760 */
761 void
762 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
763 int line ATTRIBUTE_UNUSED, int no) {
764 xmlXPathErr(ctxt, no);
765 }
766
767 /************************************************************************
768 * *
769 * Utilities *
770 * *
771 ************************************************************************/
772
773 /**
774 * xsltPointerList:
775 *
776 * Pointer-list for various purposes.
777 */
778 typedef struct _xmlPointerList xmlPointerList;
779 typedef xmlPointerList *xmlPointerListPtr;
780 struct _xmlPointerList {
781 void **items;
782 int number;
783 int size;
784 };
785 /*
786 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
787 * and here, we should make the functions public.
788 */
789 static int
790 xmlPointerListAddSize(xmlPointerListPtr list,
791 void *item,
792 int initialSize)
793 {
794 if (list->items == NULL) {
795 if (initialSize <= 0)
796 initialSize = 1;
797 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
798 if (list->items == NULL) {
799 xmlXPathErrMemory(NULL,
800 "xmlPointerListCreate: allocating item\n");
801 return(-1);
802 }
803 list->number = 0;
804 list->size = initialSize;
805 } else if (list->size <= list->number) {
806 if (list->size > 50000000) {
807 xmlXPathErrMemory(NULL,
808 "xmlPointerListAddSize: re-allocating item\n");
809 return(-1);
810 }
811 list->size *= 2;
812 list->items = (void **) xmlRealloc(list->items,
813 list->size * sizeof(void *));
814 if (list->items == NULL) {
815 xmlXPathErrMemory(NULL,
816 "xmlPointerListAddSize: re-allocating item\n");
817 list->size = 0;
818 return(-1);
819 }
820 }
821 list->items[list->number++] = item;
822 return(0);
823 }
824
825 /**
826 * xsltPointerListCreate:
827 *
828 * Creates an xsltPointerList structure.
829 *
830 * Returns a xsltPointerList structure or NULL in case of an error.
831 */
832 static xmlPointerListPtr
833 xmlPointerListCreate(int initialSize)
834 {
835 xmlPointerListPtr ret;
836
837 ret = xmlMalloc(sizeof(xmlPointerList));
838 if (ret == NULL) {
839 xmlXPathErrMemory(NULL,
840 "xmlPointerListCreate: allocating item\n");
841 return (NULL);
842 }
843 memset(ret, 0, sizeof(xmlPointerList));
844 if (initialSize > 0) {
845 xmlPointerListAddSize(ret, NULL, initialSize);
846 ret->number = 0;
847 }
848 return (ret);
849 }
850
851 /**
852 * xsltPointerListFree:
853 *
854 * Frees the xsltPointerList structure. This does not free
855 * the content of the list.
856 */
857 static void
858 xmlPointerListFree(xmlPointerListPtr list)
859 {
860 if (list == NULL)
861 return;
862 if (list->items != NULL)
863 xmlFree(list->items);
864 xmlFree(list);
865 }
866
867 /************************************************************************
868 * *
869 * Parser Types *
870 * *
871 ************************************************************************/
872
873 /*
874 * Types are private:
875 */
876
877 typedef enum {
878 XPATH_OP_END=0,
879 XPATH_OP_AND,
880 XPATH_OP_OR,
881 XPATH_OP_EQUAL,
882 XPATH_OP_CMP,
883 XPATH_OP_PLUS,
884 XPATH_OP_MULT,
885 XPATH_OP_UNION,
886 XPATH_OP_ROOT,
887 XPATH_OP_NODE,
888 XPATH_OP_RESET, /* 10 */
889 XPATH_OP_COLLECT,
890 XPATH_OP_VALUE, /* 12 */
891 XPATH_OP_VARIABLE,
892 XPATH_OP_FUNCTION,
893 XPATH_OP_ARG,
894 XPATH_OP_PREDICATE,
895 XPATH_OP_FILTER, /* 17 */
896 XPATH_OP_SORT /* 18 */
897 #ifdef LIBXML_XPTR_ENABLED
898 ,XPATH_OP_RANGETO
899 #endif
900 } xmlXPathOp;
901
902 typedef enum {
903 AXIS_ANCESTOR = 1,
904 AXIS_ANCESTOR_OR_SELF,
905 AXIS_ATTRIBUTE,
906 AXIS_CHILD,
907 AXIS_DESCENDANT,
908 AXIS_DESCENDANT_OR_SELF,
909 AXIS_FOLLOWING,
910 AXIS_FOLLOWING_SIBLING,
911 AXIS_NAMESPACE,
912 AXIS_PARENT,
913 AXIS_PRECEDING,
914 AXIS_PRECEDING_SIBLING,
915 AXIS_SELF
916 } xmlXPathAxisVal;
917
918 typedef enum {
919 NODE_TEST_NONE = 0,
920 NODE_TEST_TYPE = 1,
921 NODE_TEST_PI = 2,
922 NODE_TEST_ALL = 3,
923 NODE_TEST_NS = 4,
924 NODE_TEST_NAME = 5
925 } xmlXPathTestVal;
926
927 typedef enum {
928 NODE_TYPE_NODE = 0,
929 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
930 NODE_TYPE_TEXT = XML_TEXT_NODE,
931 NODE_TYPE_PI = XML_PI_NODE
932 } xmlXPathTypeVal;
933
934 typedef struct _xmlXPathStepOp xmlXPathStepOp;
935 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
936 struct _xmlXPathStepOp {
937 xmlXPathOp op; /* The identifier of the operation */
938 int ch1; /* First child */
939 int ch2; /* Second child */
940 int value;
941 int value2;
942 int value3;
943 void *value4;
944 void *value5;
945 xmlXPathFunction cache;
946 void *cacheURI;
947 };
948
949 struct _xmlXPathCompExpr {
950 int nbStep; /* Number of steps in this expression */
951 int maxStep; /* Maximum number of steps allocated */
952 xmlXPathStepOp *steps; /* ops for computation of this expression */
953 int last; /* index of last step in expression */
954 xmlChar *expr; /* the expression being computed */
955 xmlDictPtr dict; /* the dictionary to use if any */
956 #ifdef DEBUG_EVAL_COUNTS
957 int nb;
958 xmlChar *string;
959 #endif
960 #ifdef XPATH_STREAMING
961 xmlPatternPtr stream;
962 #endif
963 };
964
965 /************************************************************************
966 * *
967 * Forward declarations *
968 * *
969 ************************************************************************/
970 static void
971 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
972 static void
973 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
974 static int
975 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
976 xmlXPathStepOpPtr op, xmlNodePtr *first);
977 static int
978 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
979 xmlXPathStepOpPtr op,
980 int isPredicate);
981
982 /************************************************************************
983 * *
984 * Parser Type functions *
985 * *
986 ************************************************************************/
987
988 /**
989 * xmlXPathNewCompExpr:
990 *
991 * Create a new Xpath component
992 *
993 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
994 */
995 static xmlXPathCompExprPtr
996 xmlXPathNewCompExpr(void) {
997 xmlXPathCompExprPtr cur;
998
999 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1000 if (cur == NULL) {
1001 xmlXPathErrMemory(NULL, "allocating component\n");
1002 return(NULL);
1003 }
1004 memset(cur, 0, sizeof(xmlXPathCompExpr));
1005 cur->maxStep = 10;
1006 cur->nbStep = 0;
1007 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1008 sizeof(xmlXPathStepOp));
1009 if (cur->steps == NULL) {
1010 xmlXPathErrMemory(NULL, "allocating steps\n");
1011 xmlFree(cur);
1012 return(NULL);
1013 }
1014 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1015 cur->last = -1;
1016 #ifdef DEBUG_EVAL_COUNTS
1017 cur->nb = 0;
1018 #endif
1019 return(cur);
1020 }
1021
1022 /**
1023 * xmlXPathFreeCompExpr:
1024 * @comp: an XPATH comp
1025 *
1026 * Free up the memory allocated by @comp
1027 */
1028 void
1029 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1030 {
1031 xmlXPathStepOpPtr op;
1032 int i;
1033
1034 if (comp == NULL)
1035 return;
1036 if (comp->dict == NULL) {
1037 for (i = 0; i < comp->nbStep; i++) {
1038 op = &comp->steps[i];
1039 if (op->value4 != NULL) {
1040 if (op->op == XPATH_OP_VALUE)
1041 xmlXPathFreeObject(op->value4);
1042 else
1043 xmlFree(op->value4);
1044 }
1045 if (op->value5 != NULL)
1046 xmlFree(op->value5);
1047 }
1048 } else {
1049 for (i = 0; i < comp->nbStep; i++) {
1050 op = &comp->steps[i];
1051 if (op->value4 != NULL) {
1052 if (op->op == XPATH_OP_VALUE)
1053 xmlXPathFreeObject(op->value4);
1054 }
1055 }
1056 xmlDictFree(comp->dict);
1057 }
1058 if (comp->steps != NULL) {
1059 xmlFree(comp->steps);
1060 }
1061 #ifdef DEBUG_EVAL_COUNTS
1062 if (comp->string != NULL) {
1063 xmlFree(comp->string);
1064 }
1065 #endif
1066 #ifdef XPATH_STREAMING
1067 if (comp->stream != NULL) {
1068 xmlFreePatternList(comp->stream);
1069 }
1070 #endif
1071 if (comp->expr != NULL) {
1072 xmlFree(comp->expr);
1073 }
1074
1075 xmlFree(comp);
1076 }
1077
1078 /**
1079 * xmlXPathCompExprAdd:
1080 * @comp: the compiled expression
1081 * @ch1: first child index
1082 * @ch2: second child index
1083 * @op: an op
1084 * @value: the first int value
1085 * @value2: the second int value
1086 * @value3: the third int value
1087 * @value4: the first string value
1088 * @value5: the second string value
1089 *
1090 * Add a step to an XPath Compiled Expression
1091 *
1092 * Returns -1 in case of failure, the index otherwise
1093 */
1094 static int
1095 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1096 xmlXPathOp op, int value,
1097 int value2, int value3, void *value4, void *value5) {
1098 if (comp->nbStep >= comp->maxStep) {
1099 xmlXPathStepOp *real;
1100
1101 if (comp->maxStep >= XPATH_MAX_STEPS) {
1102 xmlXPathErrMemory(NULL, "adding step\n");
1103 return(-1);
1104 }
1105 comp->maxStep *= 2;
1106 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1107 comp->maxStep * sizeof(xmlXPathStepOp));
1108 if (real == NULL) {
1109 comp->maxStep /= 2;
1110 xmlXPathErrMemory(NULL, "adding step\n");
1111 return(-1);
1112 }
1113 comp->steps = real;
1114 }
1115 comp->last = comp->nbStep;
1116 comp->steps[comp->nbStep].ch1 = ch1;
1117 comp->steps[comp->nbStep].ch2 = ch2;
1118 comp->steps[comp->nbStep].op = op;
1119 comp->steps[comp->nbStep].value = value;
1120 comp->steps[comp->nbStep].value2 = value2;
1121 comp->steps[comp->nbStep].value3 = value3;
1122 if ((comp->dict != NULL) &&
1123 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1124 (op == XPATH_OP_COLLECT))) {
1125 if (value4 != NULL) {
1126 comp->steps[comp->nbStep].value4 = (xmlChar *)
1127 (void *)xmlDictLookup(comp->dict, value4, -1);
1128 xmlFree(value4);
1129 } else
1130 comp->steps[comp->nbStep].value4 = NULL;
1131 if (value5 != NULL) {
1132 comp->steps[comp->nbStep].value5 = (xmlChar *)
1133 (void *)xmlDictLookup(comp->dict, value5, -1);
1134 xmlFree(value5);
1135 } else
1136 comp->steps[comp->nbStep].value5 = NULL;
1137 } else {
1138 comp->steps[comp->nbStep].value4 = value4;
1139 comp->steps[comp->nbStep].value5 = value5;
1140 }
1141 comp->steps[comp->nbStep].cache = NULL;
1142 return(comp->nbStep++);
1143 }
1144
1145 /**
1146 * xmlXPathCompSwap:
1147 * @comp: the compiled expression
1148 * @op: operation index
1149 *
1150 * Swaps 2 operations in the compiled expression
1151 */
1152 static void
1153 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1154 int tmp;
1155
1156 #ifndef LIBXML_THREAD_ENABLED
1157 /*
1158 * Since this manipulates possibly shared variables, this is
1159 * disabled if one detects that the library is used in a multithreaded
1160 * application
1161 */
1162 if (xmlXPathDisableOptimizer)
1163 return;
1164 #endif
1165
1166 tmp = op->ch1;
1167 op->ch1 = op->ch2;
1168 op->ch2 = tmp;
1169 }
1170
1171 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1172 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1173 (op), (val), (val2), (val3), (val4), (val5))
1174 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1175 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1176 (op), (val), (val2), (val3), (val4), (val5))
1177
1178 #define PUSH_LEAVE_EXPR(op, val, val2) \
1179 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1180
1181 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1182 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1183
1184 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1185 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1186 (val), (val2), 0 ,NULL ,NULL)
1187
1188 /************************************************************************
1189 * *
1190 * XPath object cache structures *
1191 * *
1192 ************************************************************************/
1193
1194 /* #define XP_DEFAULT_CACHE_ON */
1195
1196 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1197
1198 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1199 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1200 struct _xmlXPathContextCache {
1201 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1202 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1203 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1204 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1205 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1206 int maxNodeset;
1207 int maxString;
1208 int maxBoolean;
1209 int maxNumber;
1210 int maxMisc;
1211 #ifdef XP_DEBUG_OBJ_USAGE
1212 int dbgCachedAll;
1213 int dbgCachedNodeset;
1214 int dbgCachedString;
1215 int dbgCachedBool;
1216 int dbgCachedNumber;
1217 int dbgCachedPoint;
1218 int dbgCachedRange;
1219 int dbgCachedLocset;
1220 int dbgCachedUsers;
1221 int dbgCachedXSLTTree;
1222 int dbgCachedUndefined;
1223
1224
1225 int dbgReusedAll;
1226 int dbgReusedNodeset;
1227 int dbgReusedString;
1228 int dbgReusedBool;
1229 int dbgReusedNumber;
1230 int dbgReusedPoint;
1231 int dbgReusedRange;
1232 int dbgReusedLocset;
1233 int dbgReusedUsers;
1234 int dbgReusedXSLTTree;
1235 int dbgReusedUndefined;
1236
1237 #endif
1238 };
1239
1240 /************************************************************************
1241 * *
1242 * Debugging related functions *
1243 * *
1244 ************************************************************************/
1245
1246 #define STRANGE \
1247 xmlGenericError(xmlGenericErrorContext, \
1248 "Internal error at %s:%d\n", \
1249 __FILE__, __LINE__);
1250
1251 #ifdef LIBXML_DEBUG_ENABLED
1252 static void
1253 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1254 int i;
1255 char shift[100];
1256
1257 for (i = 0;((i < depth) && (i < 25));i++)
1258 shift[2 * i] = shift[2 * i + 1] = ' ';
1259 shift[2 * i] = shift[2 * i + 1] = 0;
1260 if (cur == NULL) {
1261 fprintf(output, "%s", shift);
1262 fprintf(output, "Node is NULL !\n");
1263 return;
1264
1265 }
1266
1267 if ((cur->type == XML_DOCUMENT_NODE) ||
1268 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1269 fprintf(output, "%s", shift);
1270 fprintf(output, " /\n");
1271 } else if (cur->type == XML_ATTRIBUTE_NODE)
1272 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1273 else
1274 xmlDebugDumpOneNode(output, cur, depth);
1275 }
1276 static void
1277 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1278 xmlNodePtr tmp;
1279 int i;
1280 char shift[100];
1281
1282 for (i = 0;((i < depth) && (i < 25));i++)
1283 shift[2 * i] = shift[2 * i + 1] = ' ';
1284 shift[2 * i] = shift[2 * i + 1] = 0;
1285 if (cur == NULL) {
1286 fprintf(output, "%s", shift);
1287 fprintf(output, "Node is NULL !\n");
1288 return;
1289
1290 }
1291
1292 while (cur != NULL) {
1293 tmp = cur;
1294 cur = cur->next;
1295 xmlDebugDumpOneNode(output, tmp, depth);
1296 }
1297 }
1298
1299 static void
1300 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1301 int i;
1302 char shift[100];
1303
1304 for (i = 0;((i < depth) && (i < 25));i++)
1305 shift[2 * i] = shift[2 * i + 1] = ' ';
1306 shift[2 * i] = shift[2 * i + 1] = 0;
1307
1308 if (cur == NULL) {
1309 fprintf(output, "%s", shift);
1310 fprintf(output, "NodeSet is NULL !\n");
1311 return;
1312
1313 }
1314
1315 if (cur != NULL) {
1316 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1317 for (i = 0;i < cur->nodeNr;i++) {
1318 fprintf(output, "%s", shift);
1319 fprintf(output, "%d", i + 1);
1320 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1321 }
1322 }
1323 }
1324
1325 static void
1326 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1327 int i;
1328 char shift[100];
1329
1330 for (i = 0;((i < depth) && (i < 25));i++)
1331 shift[2 * i] = shift[2 * i + 1] = ' ';
1332 shift[2 * i] = shift[2 * i + 1] = 0;
1333
1334 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1335 fprintf(output, "%s", shift);
1336 fprintf(output, "Value Tree is NULL !\n");
1337 return;
1338
1339 }
1340
1341 fprintf(output, "%s", shift);
1342 fprintf(output, "%d", i + 1);
1343 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1344 }
1345 #if defined(LIBXML_XPTR_ENABLED)
1346 static void
1347 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1348 int i;
1349 char shift[100];
1350
1351 for (i = 0;((i < depth) && (i < 25));i++)
1352 shift[2 * i] = shift[2 * i + 1] = ' ';
1353 shift[2 * i] = shift[2 * i + 1] = 0;
1354
1355 if (cur == NULL) {
1356 fprintf(output, "%s", shift);
1357 fprintf(output, "LocationSet is NULL !\n");
1358 return;
1359
1360 }
1361
1362 for (i = 0;i < cur->locNr;i++) {
1363 fprintf(output, "%s", shift);
1364 fprintf(output, "%d : ", i + 1);
1365 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1366 }
1367 }
1368 #endif /* LIBXML_XPTR_ENABLED */
1369
1370 /**
1371 * xmlXPathDebugDumpObject:
1372 * @output: the FILE * to dump the output
1373 * @cur: the object to inspect
1374 * @depth: indentation level
1375 *
1376 * Dump the content of the object for debugging purposes
1377 */
1378 void
1379 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1380 int i;
1381 char shift[100];
1382
1383 if (output == NULL) return;
1384
1385 for (i = 0;((i < depth) && (i < 25));i++)
1386 shift[2 * i] = shift[2 * i + 1] = ' ';
1387 shift[2 * i] = shift[2 * i + 1] = 0;
1388
1389
1390 fprintf(output, "%s", shift);
1391
1392 if (cur == NULL) {
1393 fprintf(output, "Object is empty (NULL)\n");
1394 return;
1395 }
1396 switch(cur->type) {
1397 case XPATH_UNDEFINED:
1398 fprintf(output, "Object is uninitialized\n");
1399 break;
1400 case XPATH_NODESET:
1401 fprintf(output, "Object is a Node Set :\n");
1402 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1403 break;
1404 case XPATH_XSLT_TREE:
1405 fprintf(output, "Object is an XSLT value tree :\n");
1406 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1407 break;
1408 case XPATH_BOOLEAN:
1409 fprintf(output, "Object is a Boolean : ");
1410 if (cur->boolval) fprintf(output, "true\n");
1411 else fprintf(output, "false\n");
1412 break;
1413 case XPATH_NUMBER:
1414 switch (xmlXPathIsInf(cur->floatval)) {
1415 case 1:
1416 fprintf(output, "Object is a number : Infinity\n");
1417 break;
1418 case -1:
1419 fprintf(output, "Object is a number : -Infinity\n");
1420 break;
1421 default:
1422 if (xmlXPathIsNaN(cur->floatval)) {
1423 fprintf(output, "Object is a number : NaN\n");
1424 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1425 fprintf(output, "Object is a number : 0\n");
1426 } else {
1427 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1428 }
1429 }
1430 break;
1431 case XPATH_STRING:
1432 fprintf(output, "Object is a string : ");
1433 xmlDebugDumpString(output, cur->stringval);
1434 fprintf(output, "\n");
1435 break;
1436 case XPATH_POINT:
1437 fprintf(output, "Object is a point : index %d in node", cur->index);
1438 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1439 fprintf(output, "\n");
1440 break;
1441 case XPATH_RANGE:
1442 if ((cur->user2 == NULL) ||
1443 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1444 fprintf(output, "Object is a collapsed range :\n");
1445 fprintf(output, "%s", shift);
1446 if (cur->index >= 0)
1447 fprintf(output, "index %d in ", cur->index);
1448 fprintf(output, "node\n");
1449 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1450 depth + 1);
1451 } else {
1452 fprintf(output, "Object is a range :\n");
1453 fprintf(output, "%s", shift);
1454 fprintf(output, "From ");
1455 if (cur->index >= 0)
1456 fprintf(output, "index %d in ", cur->index);
1457 fprintf(output, "node\n");
1458 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1459 depth + 1);
1460 fprintf(output, "%s", shift);
1461 fprintf(output, "To ");
1462 if (cur->index2 >= 0)
1463 fprintf(output, "index %d in ", cur->index2);
1464 fprintf(output, "node\n");
1465 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1466 depth + 1);
1467 fprintf(output, "\n");
1468 }
1469 break;
1470 case XPATH_LOCATIONSET:
1471 #if defined(LIBXML_XPTR_ENABLED)
1472 fprintf(output, "Object is a Location Set:\n");
1473 xmlXPathDebugDumpLocationSet(output,
1474 (xmlLocationSetPtr) cur->user, depth);
1475 #endif
1476 break;
1477 case XPATH_USERS:
1478 fprintf(output, "Object is user defined\n");
1479 break;
1480 }
1481 }
1482
1483 static void
1484 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1485 xmlXPathStepOpPtr op, int depth) {
1486 int i;
1487 char shift[100];
1488
1489 for (i = 0;((i < depth) && (i < 25));i++)
1490 shift[2 * i] = shift[2 * i + 1] = ' ';
1491 shift[2 * i] = shift[2 * i + 1] = 0;
1492
1493 fprintf(output, "%s", shift);
1494 if (op == NULL) {
1495 fprintf(output, "Step is NULL\n");
1496 return;
1497 }
1498 switch (op->op) {
1499 case XPATH_OP_END:
1500 fprintf(output, "END"); break;
1501 case XPATH_OP_AND:
1502 fprintf(output, "AND"); break;
1503 case XPATH_OP_OR:
1504 fprintf(output, "OR"); break;
1505 case XPATH_OP_EQUAL:
1506 if (op->value)
1507 fprintf(output, "EQUAL =");
1508 else
1509 fprintf(output, "EQUAL !=");
1510 break;
1511 case XPATH_OP_CMP:
1512 if (op->value)
1513 fprintf(output, "CMP <");
1514 else
1515 fprintf(output, "CMP >");
1516 if (!op->value2)
1517 fprintf(output, "=");
1518 break;
1519 case XPATH_OP_PLUS:
1520 if (op->value == 0)
1521 fprintf(output, "PLUS -");
1522 else if (op->value == 1)
1523 fprintf(output, "PLUS +");
1524 else if (op->value == 2)
1525 fprintf(output, "PLUS unary -");
1526 else if (op->value == 3)
1527 fprintf(output, "PLUS unary - -");
1528 break;
1529 case XPATH_OP_MULT:
1530 if (op->value == 0)
1531 fprintf(output, "MULT *");
1532 else if (op->value == 1)
1533 fprintf(output, "MULT div");
1534 else
1535 fprintf(output, "MULT mod");
1536 break;
1537 case XPATH_OP_UNION:
1538 fprintf(output, "UNION"); break;
1539 case XPATH_OP_ROOT:
1540 fprintf(output, "ROOT"); break;
1541 case XPATH_OP_NODE:
1542 fprintf(output, "NODE"); break;
1543 case XPATH_OP_RESET:
1544 fprintf(output, "RESET"); break;
1545 case XPATH_OP_SORT:
1546 fprintf(output, "SORT"); break;
1547 case XPATH_OP_COLLECT: {
1548 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1549 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1550 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1551 const xmlChar *prefix = op->value4;
1552 const xmlChar *name = op->value5;
1553
1554 fprintf(output, "COLLECT ");
1555 switch (axis) {
1556 case AXIS_ANCESTOR:
1557 fprintf(output, " 'ancestors' "); break;
1558 case AXIS_ANCESTOR_OR_SELF:
1559 fprintf(output, " 'ancestors-or-self' "); break;
1560 case AXIS_ATTRIBUTE:
1561 fprintf(output, " 'attributes' "); break;
1562 case AXIS_CHILD:
1563 fprintf(output, " 'child' "); break;
1564 case AXIS_DESCENDANT:
1565 fprintf(output, " 'descendant' "); break;
1566 case AXIS_DESCENDANT_OR_SELF:
1567 fprintf(output, " 'descendant-or-self' "); break;
1568 case AXIS_FOLLOWING:
1569 fprintf(output, " 'following' "); break;
1570 case AXIS_FOLLOWING_SIBLING:
1571 fprintf(output, " 'following-siblings' "); break;
1572 case AXIS_NAMESPACE:
1573 fprintf(output, " 'namespace' "); break;
1574 case AXIS_PARENT:
1575 fprintf(output, " 'parent' "); break;
1576 case AXIS_PRECEDING:
1577 fprintf(output, " 'preceding' "); break;
1578 case AXIS_PRECEDING_SIBLING:
1579 fprintf(output, " 'preceding-sibling' "); break;
1580 case AXIS_SELF:
1581 fprintf(output, " 'self' "); break;
1582 }
1583 switch (test) {
1584 case NODE_TEST_NONE:
1585 fprintf(output, "'none' "); break;
1586 case NODE_TEST_TYPE:
1587 fprintf(output, "'type' "); break;
1588 case NODE_TEST_PI:
1589 fprintf(output, "'PI' "); break;
1590 case NODE_TEST_ALL:
1591 fprintf(output, "'all' "); break;
1592 case NODE_TEST_NS:
1593 fprintf(output, "'namespace' "); break;
1594 case NODE_TEST_NAME:
1595 fprintf(output, "'name' "); break;
1596 }
1597 switch (type) {
1598 case NODE_TYPE_NODE:
1599 fprintf(output, "'node' "); break;
1600 case NODE_TYPE_COMMENT:
1601 fprintf(output, "'comment' "); break;
1602 case NODE_TYPE_TEXT:
1603 fprintf(output, "'text' "); break;
1604 case NODE_TYPE_PI:
1605 fprintf(output, "'PI' "); break;
1606 }
1607 if (prefix != NULL)
1608 fprintf(output, "%s:", prefix);
1609 if (name != NULL)
1610 fprintf(output, "%s", (const char *) name);
1611 break;
1612
1613 }
1614 case XPATH_OP_VALUE: {
1615 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1616
1617 fprintf(output, "ELEM ");
1618 xmlXPathDebugDumpObject(output, object, 0);
1619 goto finish;
1620 }
1621 case XPATH_OP_VARIABLE: {
1622 const xmlChar *prefix = op->value5;
1623 const xmlChar *name = op->value4;
1624
1625 if (prefix != NULL)
1626 fprintf(output, "VARIABLE %s:%s", prefix, name);
1627 else
1628 fprintf(output, "VARIABLE %s", name);
1629 break;
1630 }
1631 case XPATH_OP_FUNCTION: {
1632 int nbargs = op->value;
1633 const xmlChar *prefix = op->value5;
1634 const xmlChar *name = op->value4;
1635
1636 if (prefix != NULL)
1637 fprintf(output, "FUNCTION %s:%s(%d args)",
1638 prefix, name, nbargs);
1639 else
1640 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1641 break;
1642 }
1643 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1644 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1645 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1646 #ifdef LIBXML_XPTR_ENABLED
1647 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1648 #endif
1649 default:
1650 fprintf(output, "UNKNOWN %d\n", op->op); return;
1651 }
1652 fprintf(output, "\n");
1653 finish:
1654 if (op->ch1 >= 0)
1655 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1656 if (op->ch2 >= 0)
1657 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1658 }
1659
1660 /**
1661 * xmlXPathDebugDumpCompExpr:
1662 * @output: the FILE * for the output
1663 * @comp: the precompiled XPath expression
1664 * @depth: the indentation level.
1665 *
1666 * Dumps the tree of the compiled XPath expression.
1667 */
1668 void
1669 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1670 int depth) {
1671 int i;
1672 char shift[100];
1673
1674 if ((output == NULL) || (comp == NULL)) return;
1675
1676 for (i = 0;((i < depth) && (i < 25));i++)
1677 shift[2 * i] = shift[2 * i + 1] = ' ';
1678 shift[2 * i] = shift[2 * i + 1] = 0;
1679
1680 fprintf(output, "%s", shift);
1681
1682 #ifdef XPATH_STREAMING
1683 if (comp->stream) {
1684 fprintf(output, "Streaming Expression\n");
1685 } else
1686 #endif
1687 {
1688 fprintf(output, "Compiled Expression : %d elements\n",
1689 comp->nbStep);
1690 i = comp->last;
1691 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1692 }
1693 }
1694
1695 #ifdef XP_DEBUG_OBJ_USAGE
1696
1697 /*
1698 * XPath object usage related debugging variables.
1699 */
1700 static int xmlXPathDebugObjCounterUndefined = 0;
1701 static int xmlXPathDebugObjCounterNodeset = 0;
1702 static int xmlXPathDebugObjCounterBool = 0;
1703 static int xmlXPathDebugObjCounterNumber = 0;
1704 static int xmlXPathDebugObjCounterString = 0;
1705 static int xmlXPathDebugObjCounterPoint = 0;
1706 static int xmlXPathDebugObjCounterRange = 0;
1707 static int xmlXPathDebugObjCounterLocset = 0;
1708 static int xmlXPathDebugObjCounterUsers = 0;
1709 static int xmlXPathDebugObjCounterXSLTTree = 0;
1710 static int xmlXPathDebugObjCounterAll = 0;
1711
1712 static int xmlXPathDebugObjTotalUndefined = 0;
1713 static int xmlXPathDebugObjTotalNodeset = 0;
1714 static int xmlXPathDebugObjTotalBool = 0;
1715 static int xmlXPathDebugObjTotalNumber = 0;
1716 static int xmlXPathDebugObjTotalString = 0;
1717 static int xmlXPathDebugObjTotalPoint = 0;
1718 static int xmlXPathDebugObjTotalRange = 0;
1719 static int xmlXPathDebugObjTotalLocset = 0;
1720 static int xmlXPathDebugObjTotalUsers = 0;
1721 static int xmlXPathDebugObjTotalXSLTTree = 0;
1722 static int xmlXPathDebugObjTotalAll = 0;
1723
1724 static int xmlXPathDebugObjMaxUndefined = 0;
1725 static int xmlXPathDebugObjMaxNodeset = 0;
1726 static int xmlXPathDebugObjMaxBool = 0;
1727 static int xmlXPathDebugObjMaxNumber = 0;
1728 static int xmlXPathDebugObjMaxString = 0;
1729 static int xmlXPathDebugObjMaxPoint = 0;
1730 static int xmlXPathDebugObjMaxRange = 0;
1731 static int xmlXPathDebugObjMaxLocset = 0;
1732 static int xmlXPathDebugObjMaxUsers = 0;
1733 static int xmlXPathDebugObjMaxXSLTTree = 0;
1734 static int xmlXPathDebugObjMaxAll = 0;
1735
1736 /* REVISIT TODO: Make this static when committing */
1737 static void
1738 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1739 {
1740 if (ctxt != NULL) {
1741 if (ctxt->cache != NULL) {
1742 xmlXPathContextCachePtr cache =
1743 (xmlXPathContextCachePtr) ctxt->cache;
1744
1745 cache->dbgCachedAll = 0;
1746 cache->dbgCachedNodeset = 0;
1747 cache->dbgCachedString = 0;
1748 cache->dbgCachedBool = 0;
1749 cache->dbgCachedNumber = 0;
1750 cache->dbgCachedPoint = 0;
1751 cache->dbgCachedRange = 0;
1752 cache->dbgCachedLocset = 0;
1753 cache->dbgCachedUsers = 0;
1754 cache->dbgCachedXSLTTree = 0;
1755 cache->dbgCachedUndefined = 0;
1756
1757 cache->dbgReusedAll = 0;
1758 cache->dbgReusedNodeset = 0;
1759 cache->dbgReusedString = 0;
1760 cache->dbgReusedBool = 0;
1761 cache->dbgReusedNumber = 0;
1762 cache->dbgReusedPoint = 0;
1763 cache->dbgReusedRange = 0;
1764 cache->dbgReusedLocset = 0;
1765 cache->dbgReusedUsers = 0;
1766 cache->dbgReusedXSLTTree = 0;
1767 cache->dbgReusedUndefined = 0;
1768 }
1769 }
1770
1771 xmlXPathDebugObjCounterUndefined = 0;
1772 xmlXPathDebugObjCounterNodeset = 0;
1773 xmlXPathDebugObjCounterBool = 0;
1774 xmlXPathDebugObjCounterNumber = 0;
1775 xmlXPathDebugObjCounterString = 0;
1776 xmlXPathDebugObjCounterPoint = 0;
1777 xmlXPathDebugObjCounterRange = 0;
1778 xmlXPathDebugObjCounterLocset = 0;
1779 xmlXPathDebugObjCounterUsers = 0;
1780 xmlXPathDebugObjCounterXSLTTree = 0;
1781 xmlXPathDebugObjCounterAll = 0;
1782
1783 xmlXPathDebugObjTotalUndefined = 0;
1784 xmlXPathDebugObjTotalNodeset = 0;
1785 xmlXPathDebugObjTotalBool = 0;
1786 xmlXPathDebugObjTotalNumber = 0;
1787 xmlXPathDebugObjTotalString = 0;
1788 xmlXPathDebugObjTotalPoint = 0;
1789 xmlXPathDebugObjTotalRange = 0;
1790 xmlXPathDebugObjTotalLocset = 0;
1791 xmlXPathDebugObjTotalUsers = 0;
1792 xmlXPathDebugObjTotalXSLTTree = 0;
1793 xmlXPathDebugObjTotalAll = 0;
1794
1795 xmlXPathDebugObjMaxUndefined = 0;
1796 xmlXPathDebugObjMaxNodeset = 0;
1797 xmlXPathDebugObjMaxBool = 0;
1798 xmlXPathDebugObjMaxNumber = 0;
1799 xmlXPathDebugObjMaxString = 0;
1800 xmlXPathDebugObjMaxPoint = 0;
1801 xmlXPathDebugObjMaxRange = 0;
1802 xmlXPathDebugObjMaxLocset = 0;
1803 xmlXPathDebugObjMaxUsers = 0;
1804 xmlXPathDebugObjMaxXSLTTree = 0;
1805 xmlXPathDebugObjMaxAll = 0;
1806
1807 }
1808
1809 static void
1810 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1811 xmlXPathObjectType objType)
1812 {
1813 int isCached = 0;
1814
1815 if (ctxt != NULL) {
1816 if (ctxt->cache != NULL) {
1817 xmlXPathContextCachePtr cache =
1818 (xmlXPathContextCachePtr) ctxt->cache;
1819
1820 isCached = 1;
1821
1822 cache->dbgReusedAll++;
1823 switch (objType) {
1824 case XPATH_UNDEFINED:
1825 cache->dbgReusedUndefined++;
1826 break;
1827 case XPATH_NODESET:
1828 cache->dbgReusedNodeset++;
1829 break;
1830 case XPATH_BOOLEAN:
1831 cache->dbgReusedBool++;
1832 break;
1833 case XPATH_NUMBER:
1834 cache->dbgReusedNumber++;
1835 break;
1836 case XPATH_STRING:
1837 cache->dbgReusedString++;
1838 break;
1839 case XPATH_POINT:
1840 cache->dbgReusedPoint++;
1841 break;
1842 case XPATH_RANGE:
1843 cache->dbgReusedRange++;
1844 break;
1845 case XPATH_LOCATIONSET:
1846 cache->dbgReusedLocset++;
1847 break;
1848 case XPATH_USERS:
1849 cache->dbgReusedUsers++;
1850 break;
1851 case XPATH_XSLT_TREE:
1852 cache->dbgReusedXSLTTree++;
1853 break;
1854 default:
1855 break;
1856 }
1857 }
1858 }
1859
1860 switch (objType) {
1861 case XPATH_UNDEFINED:
1862 if (! isCached)
1863 xmlXPathDebugObjTotalUndefined++;
1864 xmlXPathDebugObjCounterUndefined++;
1865 if (xmlXPathDebugObjCounterUndefined >
1866 xmlXPathDebugObjMaxUndefined)
1867 xmlXPathDebugObjMaxUndefined =
1868 xmlXPathDebugObjCounterUndefined;
1869 break;
1870 case XPATH_NODESET:
1871 if (! isCached)
1872 xmlXPathDebugObjTotalNodeset++;
1873 xmlXPathDebugObjCounterNodeset++;
1874 if (xmlXPathDebugObjCounterNodeset >
1875 xmlXPathDebugObjMaxNodeset)
1876 xmlXPathDebugObjMaxNodeset =
1877 xmlXPathDebugObjCounterNodeset;
1878 break;
1879 case XPATH_BOOLEAN:
1880 if (! isCached)
1881 xmlXPathDebugObjTotalBool++;
1882 xmlXPathDebugObjCounterBool++;
1883 if (xmlXPathDebugObjCounterBool >
1884 xmlXPathDebugObjMaxBool)
1885 xmlXPathDebugObjMaxBool =
1886 xmlXPathDebugObjCounterBool;
1887 break;
1888 case XPATH_NUMBER:
1889 if (! isCached)
1890 xmlXPathDebugObjTotalNumber++;
1891 xmlXPathDebugObjCounterNumber++;
1892 if (xmlXPathDebugObjCounterNumber >
1893 xmlXPathDebugObjMaxNumber)
1894 xmlXPathDebugObjMaxNumber =
1895 xmlXPathDebugObjCounterNumber;
1896 break;
1897 case XPATH_STRING:
1898 if (! isCached)
1899 xmlXPathDebugObjTotalString++;
1900 xmlXPathDebugObjCounterString++;
1901 if (xmlXPathDebugObjCounterString >
1902 xmlXPathDebugObjMaxString)
1903 xmlXPathDebugObjMaxString =
1904 xmlXPathDebugObjCounterString;
1905 break;
1906 case XPATH_POINT:
1907 if (! isCached)
1908 xmlXPathDebugObjTotalPoint++;
1909 xmlXPathDebugObjCounterPoint++;
1910 if (xmlXPathDebugObjCounterPoint >
1911 xmlXPathDebugObjMaxPoint)
1912 xmlXPathDebugObjMaxPoint =
1913 xmlXPathDebugObjCounterPoint;
1914 break;
1915 case XPATH_RANGE:
1916 if (! isCached)
1917 xmlXPathDebugObjTotalRange++;
1918 xmlXPathDebugObjCounterRange++;
1919 if (xmlXPathDebugObjCounterRange >
1920 xmlXPathDebugObjMaxRange)
1921 xmlXPathDebugObjMaxRange =
1922 xmlXPathDebugObjCounterRange;
1923 break;
1924 case XPATH_LOCATIONSET:
1925 if (! isCached)
1926 xmlXPathDebugObjTotalLocset++;
1927 xmlXPathDebugObjCounterLocset++;
1928 if (xmlXPathDebugObjCounterLocset >
1929 xmlXPathDebugObjMaxLocset)
1930 xmlXPathDebugObjMaxLocset =
1931 xmlXPathDebugObjCounterLocset;
1932 break;
1933 case XPATH_USERS:
1934 if (! isCached)
1935 xmlXPathDebugObjTotalUsers++;
1936 xmlXPathDebugObjCounterUsers++;
1937 if (xmlXPathDebugObjCounterUsers >
1938 xmlXPathDebugObjMaxUsers)
1939 xmlXPathDebugObjMaxUsers =
1940 xmlXPathDebugObjCounterUsers;
1941 break;
1942 case XPATH_XSLT_TREE:
1943 if (! isCached)
1944 xmlXPathDebugObjTotalXSLTTree++;
1945 xmlXPathDebugObjCounterXSLTTree++;
1946 if (xmlXPathDebugObjCounterXSLTTree >
1947 xmlXPathDebugObjMaxXSLTTree)
1948 xmlXPathDebugObjMaxXSLTTree =
1949 xmlXPathDebugObjCounterXSLTTree;
1950 break;
1951 default:
1952 break;
1953 }
1954 if (! isCached)
1955 xmlXPathDebugObjTotalAll++;
1956 xmlXPathDebugObjCounterAll++;
1957 if (xmlXPathDebugObjCounterAll >
1958 xmlXPathDebugObjMaxAll)
1959 xmlXPathDebugObjMaxAll =
1960 xmlXPathDebugObjCounterAll;
1961 }
1962
1963 static void
1964 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1965 xmlXPathObjectType objType)
1966 {
1967 int isCached = 0;
1968
1969 if (ctxt != NULL) {
1970 if (ctxt->cache != NULL) {
1971 xmlXPathContextCachePtr cache =
1972 (xmlXPathContextCachePtr) ctxt->cache;
1973
1974 isCached = 1;
1975
1976 cache->dbgCachedAll++;
1977 switch (objType) {
1978 case XPATH_UNDEFINED:
1979 cache->dbgCachedUndefined++;
1980 break;
1981 case XPATH_NODESET:
1982 cache->dbgCachedNodeset++;
1983 break;
1984 case XPATH_BOOLEAN:
1985 cache->dbgCachedBool++;
1986 break;
1987 case XPATH_NUMBER:
1988 cache->dbgCachedNumber++;
1989 break;
1990 case XPATH_STRING:
1991 cache->dbgCachedString++;
1992 break;
1993 case XPATH_POINT:
1994 cache->dbgCachedPoint++;
1995 break;
1996 case XPATH_RANGE:
1997 cache->dbgCachedRange++;
1998 break;
1999 case XPATH_LOCATIONSET:
2000 cache->dbgCachedLocset++;
2001 break;
2002 case XPATH_USERS:
2003 cache->dbgCachedUsers++;
2004 break;
2005 case XPATH_XSLT_TREE:
2006 cache->dbgCachedXSLTTree++;
2007 break;
2008 default:
2009 break;
2010 }
2011
2012 }
2013 }
2014 switch (objType) {
2015 case XPATH_UNDEFINED:
2016 xmlXPathDebugObjCounterUndefined--;
2017 break;
2018 case XPATH_NODESET:
2019 xmlXPathDebugObjCounterNodeset--;
2020 break;
2021 case XPATH_BOOLEAN:
2022 xmlXPathDebugObjCounterBool--;
2023 break;
2024 case XPATH_NUMBER:
2025 xmlXPathDebugObjCounterNumber--;
2026 break;
2027 case XPATH_STRING:
2028 xmlXPathDebugObjCounterString--;
2029 break;
2030 case XPATH_POINT:
2031 xmlXPathDebugObjCounterPoint--;
2032 break;
2033 case XPATH_RANGE:
2034 xmlXPathDebugObjCounterRange--;
2035 break;
2036 case XPATH_LOCATIONSET:
2037 xmlXPathDebugObjCounterLocset--;
2038 break;
2039 case XPATH_USERS:
2040 xmlXPathDebugObjCounterUsers--;
2041 break;
2042 case XPATH_XSLT_TREE:
2043 xmlXPathDebugObjCounterXSLTTree--;
2044 break;
2045 default:
2046 break;
2047 }
2048 xmlXPathDebugObjCounterAll--;
2049 }
2050
2051 /* REVISIT TODO: Make this static when committing */
2052 static void
2053 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2054 {
2055 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2056 reqXSLTTree, reqUndefined;
2057 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2058 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2059 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2060 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2061 int leftObjs = xmlXPathDebugObjCounterAll;
2062
2063 reqAll = xmlXPathDebugObjTotalAll;
2064 reqNodeset = xmlXPathDebugObjTotalNodeset;
2065 reqString = xmlXPathDebugObjTotalString;
2066 reqBool = xmlXPathDebugObjTotalBool;
2067 reqNumber = xmlXPathDebugObjTotalNumber;
2068 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2069 reqUndefined = xmlXPathDebugObjTotalUndefined;
2070
2071 printf("# XPath object usage:\n");
2072
2073 if (ctxt != NULL) {
2074 if (ctxt->cache != NULL) {
2075 xmlXPathContextCachePtr cache =
2076 (xmlXPathContextCachePtr) ctxt->cache;
2077
2078 reAll = cache->dbgReusedAll;
2079 reqAll += reAll;
2080 reNodeset = cache->dbgReusedNodeset;
2081 reqNodeset += reNodeset;
2082 reString = cache->dbgReusedString;
2083 reqString += reString;
2084 reBool = cache->dbgReusedBool;
2085 reqBool += reBool;
2086 reNumber = cache->dbgReusedNumber;
2087 reqNumber += reNumber;
2088 reXSLTTree = cache->dbgReusedXSLTTree;
2089 reqXSLTTree += reXSLTTree;
2090 reUndefined = cache->dbgReusedUndefined;
2091 reqUndefined += reUndefined;
2092
2093 caAll = cache->dbgCachedAll;
2094 caBool = cache->dbgCachedBool;
2095 caNodeset = cache->dbgCachedNodeset;
2096 caString = cache->dbgCachedString;
2097 caNumber = cache->dbgCachedNumber;
2098 caXSLTTree = cache->dbgCachedXSLTTree;
2099 caUndefined = cache->dbgCachedUndefined;
2100
2101 if (cache->nodesetObjs)
2102 leftObjs -= cache->nodesetObjs->number;
2103 if (cache->stringObjs)
2104 leftObjs -= cache->stringObjs->number;
2105 if (cache->booleanObjs)
2106 leftObjs -= cache->booleanObjs->number;
2107 if (cache->numberObjs)
2108 leftObjs -= cache->numberObjs->number;
2109 if (cache->miscObjs)
2110 leftObjs -= cache->miscObjs->number;
2111 }
2112 }
2113
2114 printf("# all\n");
2115 printf("# total : %d\n", reqAll);
2116 printf("# left : %d\n", leftObjs);
2117 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2118 printf("# reused : %d\n", reAll);
2119 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2120
2121 printf("# node-sets\n");
2122 printf("# total : %d\n", reqNodeset);
2123 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2124 printf("# reused : %d\n", reNodeset);
2125 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2126
2127 printf("# strings\n");
2128 printf("# total : %d\n", reqString);
2129 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2130 printf("# reused : %d\n", reString);
2131 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2132
2133 printf("# booleans\n");
2134 printf("# total : %d\n", reqBool);
2135 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2136 printf("# reused : %d\n", reBool);
2137 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2138
2139 printf("# numbers\n");
2140 printf("# total : %d\n", reqNumber);
2141 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2142 printf("# reused : %d\n", reNumber);
2143 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2144
2145 printf("# XSLT result tree fragments\n");
2146 printf("# total : %d\n", reqXSLTTree);
2147 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2148 printf("# reused : %d\n", reXSLTTree);
2149 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2150
2151 printf("# undefined\n");
2152 printf("# total : %d\n", reqUndefined);
2153 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2154 printf("# reused : %d\n", reUndefined);
2155 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2156
2157 }
2158
2159 #endif /* XP_DEBUG_OBJ_USAGE */
2160
2161 #endif /* LIBXML_DEBUG_ENABLED */
2162
2163 /************************************************************************
2164 * *
2165 * XPath object caching *
2166 * *
2167 ************************************************************************/
2168
2169 /**
2170 * xmlXPathNewCache:
2171 *
2172 * Create a new object cache
2173 *
2174 * Returns the xmlXPathCache just allocated.
2175 */
2176 static xmlXPathContextCachePtr
2177 xmlXPathNewCache(void)
2178 {
2179 xmlXPathContextCachePtr ret;
2180
2181 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2182 if (ret == NULL) {
2183 xmlXPathErrMemory(NULL, "creating object cache\n");
2184 return(NULL);
2185 }
2186 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2187 ret->maxNodeset = 100;
2188 ret->maxString = 100;
2189 ret->maxBoolean = 100;
2190 ret->maxNumber = 100;
2191 ret->maxMisc = 100;
2192 return(ret);
2193 }
2194
2195 static void
2196 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2197 {
2198 int i;
2199 xmlXPathObjectPtr obj;
2200
2201 if (list == NULL)
2202 return;
2203
2204 for (i = 0; i < list->number; i++) {
2205 obj = list->items[i];
2206 /*
2207 * Note that it is already assured that we don't need to
2208 * look out for namespace nodes in the node-set.
2209 */
2210 if (obj->nodesetval != NULL) {
2211 if (obj->nodesetval->nodeTab != NULL)
2212 xmlFree(obj->nodesetval->nodeTab);
2213 xmlFree(obj->nodesetval);
2214 }
2215 xmlFree(obj);
2216 #ifdef XP_DEBUG_OBJ_USAGE
2217 xmlXPathDebugObjCounterAll--;
2218 #endif
2219 }
2220 xmlPointerListFree(list);
2221 }
2222
2223 static void
2224 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2225 {
2226 if (cache == NULL)
2227 return;
2228 if (cache->nodesetObjs)
2229 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2230 if (cache->stringObjs)
2231 xmlXPathCacheFreeObjectList(cache->stringObjs);
2232 if (cache->booleanObjs)
2233 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2234 if (cache->numberObjs)
2235 xmlXPathCacheFreeObjectList(cache->numberObjs);
2236 if (cache->miscObjs)
2237 xmlXPathCacheFreeObjectList(cache->miscObjs);
2238 xmlFree(cache);
2239 }
2240
2241 /**
2242 * xmlXPathContextSetCache:
2243 *
2244 * @ctxt: the XPath context
2245 * @active: enables/disables (creates/frees) the cache
2246 * @value: a value with semantics dependant on @options
2247 * @options: options (currently only the value 0 is used)
2248 *
2249 * Creates/frees an object cache on the XPath context.
2250 * If activates XPath objects (xmlXPathObject) will be cached internally
2251 * to be reused.
2252 * @options:
2253 * 0: This will set the XPath object caching:
2254 * @value:
2255 * This will set the maximum number of XPath objects
2256 * to be cached per slot
2257 * There are 5 slots for: node-set, string, number, boolean, and
2258 * misc objects. Use <0 for the default number (100).
2259 * Other values for @options have currently no effect.
2260 *
2261 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2262 */
2263 int
2264 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2265 int active,
2266 int value,
2267 int options)
2268 {
2269 if (ctxt == NULL)
2270 return(-1);
2271 if (active) {
2272 xmlXPathContextCachePtr cache;
2273
2274 if (ctxt->cache == NULL) {
2275 ctxt->cache = xmlXPathNewCache();
2276 if (ctxt->cache == NULL)
2277 return(-1);
2278 }
2279 cache = (xmlXPathContextCachePtr) ctxt->cache;
2280 if (options == 0) {
2281 if (value < 0)
2282 value = 100;
2283 cache->maxNodeset = value;
2284 cache->maxString = value;
2285 cache->maxNumber = value;
2286 cache->maxBoolean = value;
2287 cache->maxMisc = value;
2288 }
2289 } else if (ctxt->cache != NULL) {
2290 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2291 ctxt->cache = NULL;
2292 }
2293 return(0);
2294 }
2295
2296 /**
2297 * xmlXPathCacheWrapNodeSet:
2298 * @ctxt: the XPath context
2299 * @val: the NodePtr value
2300 *
2301 * This is the cached version of xmlXPathWrapNodeSet().
2302 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2303 *
2304 * Returns the created or reused object.
2305 */
2306 static xmlXPathObjectPtr
2307 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2308 {
2309 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2310 xmlXPathContextCachePtr cache =
2311 (xmlXPathContextCachePtr) ctxt->cache;
2312
2313 if ((cache->miscObjs != NULL) &&
2314 (cache->miscObjs->number != 0))
2315 {
2316 xmlXPathObjectPtr ret;
2317
2318 ret = (xmlXPathObjectPtr)
2319 cache->miscObjs->items[--cache->miscObjs->number];
2320 ret->type = XPATH_NODESET;
2321 ret->nodesetval = val;
2322 #ifdef XP_DEBUG_OBJ_USAGE
2323 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2324 #endif
2325 return(ret);
2326 }
2327 }
2328
2329 return(xmlXPathWrapNodeSet(val));
2330
2331 }
2332
2333 /**
2334 * xmlXPathCacheWrapString:
2335 * @ctxt: the XPath context
2336 * @val: the xmlChar * value
2337 *
2338 * This is the cached version of xmlXPathWrapString().
2339 * Wraps the @val string into an XPath object.
2340 *
2341 * Returns the created or reused object.
2342 */
2343 static xmlXPathObjectPtr
2344 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2345 {
2346 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2347 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2348
2349 if ((cache->stringObjs != NULL) &&
2350 (cache->stringObjs->number != 0))
2351 {
2352
2353 xmlXPathObjectPtr ret;
2354
2355 ret = (xmlXPathObjectPtr)
2356 cache->stringObjs->items[--cache->stringObjs->number];
2357 ret->type = XPATH_STRING;
2358 ret->stringval = val;
2359 #ifdef XP_DEBUG_OBJ_USAGE
2360 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2361 #endif
2362 return(ret);
2363 } else if ((cache->miscObjs != NULL) &&
2364 (cache->miscObjs->number != 0))
2365 {
2366 xmlXPathObjectPtr ret;
2367 /*
2368 * Fallback to misc-cache.
2369 */
2370 ret = (xmlXPathObjectPtr)
2371 cache->miscObjs->items[--cache->miscObjs->number];
2372
2373 ret->type = XPATH_STRING;
2374 ret->stringval = val;
2375 #ifdef XP_DEBUG_OBJ_USAGE
2376 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2377 #endif
2378 return(ret);
2379 }
2380 }
2381 return(xmlXPathWrapString(val));
2382 }
2383
2384 /**
2385 * xmlXPathCacheNewNodeSet:
2386 * @ctxt: the XPath context
2387 * @val: the NodePtr value
2388 *
2389 * This is the cached version of xmlXPathNewNodeSet().
2390 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2391 * it with the single Node @val
2392 *
2393 * Returns the created or reused object.
2394 */
2395 static xmlXPathObjectPtr
2396 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2397 {
2398 if ((ctxt != NULL) && (ctxt->cache)) {
2399 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2400
2401 if ((cache->nodesetObjs != NULL) &&
2402 (cache->nodesetObjs->number != 0))
2403 {
2404 xmlXPathObjectPtr ret;
2405 /*
2406 * Use the nodset-cache.
2407 */
2408 ret = (xmlXPathObjectPtr)
2409 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2410 ret->type = XPATH_NODESET;
2411 ret->boolval = 0;
2412 if (val) {
2413 if ((ret->nodesetval->nodeMax == 0) ||
2414 (val->type == XML_NAMESPACE_DECL))
2415 {
2416 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2417 } else {
2418 ret->nodesetval->nodeTab[0] = val;
2419 ret->nodesetval->nodeNr = 1;
2420 }
2421 }
2422 #ifdef XP_DEBUG_OBJ_USAGE
2423 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2424 #endif
2425 return(ret);
2426 } else if ((cache->miscObjs != NULL) &&
2427 (cache->miscObjs->number != 0))
2428 {
2429 xmlXPathObjectPtr ret;
2430 /*
2431 * Fallback to misc-cache.
2432 */
2433
2434 ret = (xmlXPathObjectPtr)
2435 cache->miscObjs->items[--cache->miscObjs->number];
2436
2437 ret->type = XPATH_NODESET;
2438 ret->boolval = 0;
2439 ret->nodesetval = xmlXPathNodeSetCreate(val);
2440 if (ret->nodesetval == NULL) {
2441 ctxt->lastError.domain = XML_FROM_XPATH;
2442 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2443 return(NULL);
2444 }
2445 #ifdef XP_DEBUG_OBJ_USAGE
2446 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2447 #endif
2448 return(ret);
2449 }
2450 }
2451 return(xmlXPathNewNodeSet(val));
2452 }
2453
2454 /**
2455 * xmlXPathCacheNewCString:
2456 * @ctxt: the XPath context
2457 * @val: the char * value
2458 *
2459 * This is the cached version of xmlXPathNewCString().
2460 * Acquire an xmlXPathObjectPtr of type string and of value @val
2461 *
2462 * Returns the created or reused object.
2463 */
2464 static xmlXPathObjectPtr
2465 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2466 {
2467 if ((ctxt != NULL) && (ctxt->cache)) {
2468 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2469
2470 if ((cache->stringObjs != NULL) &&
2471 (cache->stringObjs->number != 0))
2472 {
2473 xmlXPathObjectPtr ret;
2474
2475 ret = (xmlXPathObjectPtr)
2476 cache->stringObjs->items[--cache->stringObjs->number];
2477
2478 ret->type = XPATH_STRING;
2479 ret->stringval = xmlStrdup(BAD_CAST val);
2480 #ifdef XP_DEBUG_OBJ_USAGE
2481 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2482 #endif
2483 return(ret);
2484 } else if ((cache->miscObjs != NULL) &&
2485 (cache->miscObjs->number != 0))
2486 {
2487 xmlXPathObjectPtr ret;
2488
2489 ret = (xmlXPathObjectPtr)
2490 cache->miscObjs->items[--cache->miscObjs->number];
2491
2492 ret->type = XPATH_STRING;
2493 ret->stringval = xmlStrdup(BAD_CAST val);
2494 #ifdef XP_DEBUG_OBJ_USAGE
2495 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2496 #endif
2497 return(ret);
2498 }
2499 }
2500 return(xmlXPathNewCString(val));
2501 }
2502
2503 /**
2504 * xmlXPathCacheNewString:
2505 * @ctxt: the XPath context
2506 * @val: the xmlChar * value
2507 *
2508 * This is the cached version of xmlXPathNewString().
2509 * Acquire an xmlXPathObjectPtr of type string and of value @val
2510 *
2511 * Returns the created or reused object.
2512 */
2513 static xmlXPathObjectPtr
2514 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2515 {
2516 if ((ctxt != NULL) && (ctxt->cache)) {
2517 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2518
2519 if ((cache->stringObjs != NULL) &&
2520 (cache->stringObjs->number != 0))
2521 {
2522 xmlXPathObjectPtr ret;
2523
2524 ret = (xmlXPathObjectPtr)
2525 cache->stringObjs->items[--cache->stringObjs->number];
2526 ret->type = XPATH_STRING;
2527 if (val != NULL)
2528 ret->stringval = xmlStrdup(val);
2529 else
2530 ret->stringval = xmlStrdup((const xmlChar *)"");
2531 #ifdef XP_DEBUG_OBJ_USAGE
2532 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533 #endif
2534 return(ret);
2535 } else if ((cache->miscObjs != NULL) &&
2536 (cache->miscObjs->number != 0))
2537 {
2538 xmlXPathObjectPtr ret;
2539
2540 ret = (xmlXPathObjectPtr)
2541 cache->miscObjs->items[--cache->miscObjs->number];
2542
2543 ret->type = XPATH_STRING;
2544 if (val != NULL)
2545 ret->stringval = xmlStrdup(val);
2546 else
2547 ret->stringval = xmlStrdup((const xmlChar *)"");
2548 #ifdef XP_DEBUG_OBJ_USAGE
2549 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2550 #endif
2551 return(ret);
2552 }
2553 }
2554 return(xmlXPathNewString(val));
2555 }
2556
2557 /**
2558 * xmlXPathCacheNewBoolean:
2559 * @ctxt: the XPath context
2560 * @val: the boolean value
2561 *
2562 * This is the cached version of xmlXPathNewBoolean().
2563 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2564 *
2565 * Returns the created or reused object.
2566 */
2567 static xmlXPathObjectPtr
2568 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2569 {
2570 if ((ctxt != NULL) && (ctxt->cache)) {
2571 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2572
2573 if ((cache->booleanObjs != NULL) &&
2574 (cache->booleanObjs->number != 0))
2575 {
2576 xmlXPathObjectPtr ret;
2577
2578 ret = (xmlXPathObjectPtr)
2579 cache->booleanObjs->items[--cache->booleanObjs->number];
2580 ret->type = XPATH_BOOLEAN;
2581 ret->boolval = (val != 0);
2582 #ifdef XP_DEBUG_OBJ_USAGE
2583 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2584 #endif
2585 return(ret);
2586 } else if ((cache->miscObjs != NULL) &&
2587 (cache->miscObjs->number != 0))
2588 {
2589 xmlXPathObjectPtr ret;
2590
2591 ret = (xmlXPathObjectPtr)
2592 cache->miscObjs->items[--cache->miscObjs->number];
2593
2594 ret->type = XPATH_BOOLEAN;
2595 ret->boolval = (val != 0);
2596 #ifdef XP_DEBUG_OBJ_USAGE
2597 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2598 #endif
2599 return(ret);
2600 }
2601 }
2602 return(xmlXPathNewBoolean(val));
2603 }
2604
2605 /**
2606 * xmlXPathCacheNewFloat:
2607 * @ctxt: the XPath context
2608 * @val: the double value
2609 *
2610 * This is the cached version of xmlXPathNewFloat().
2611 * Acquires an xmlXPathObjectPtr of type double and of value @val
2612 *
2613 * Returns the created or reused object.
2614 */
2615 static xmlXPathObjectPtr
2616 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2617 {
2618 if ((ctxt != NULL) && (ctxt->cache)) {
2619 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2620
2621 if ((cache->numberObjs != NULL) &&
2622 (cache->numberObjs->number != 0))
2623 {
2624 xmlXPathObjectPtr ret;
2625
2626 ret = (xmlXPathObjectPtr)
2627 cache->numberObjs->items[--cache->numberObjs->number];
2628 ret->type = XPATH_NUMBER;
2629 ret->floatval = val;
2630 #ifdef XP_DEBUG_OBJ_USAGE
2631 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2632 #endif
2633 return(ret);
2634 } else if ((cache->miscObjs != NULL) &&
2635 (cache->miscObjs->number != 0))
2636 {
2637 xmlXPathObjectPtr ret;
2638
2639 ret = (xmlXPathObjectPtr)
2640 cache->miscObjs->items[--cache->miscObjs->number];
2641
2642 ret->type = XPATH_NUMBER;
2643 ret->floatval = val;
2644 #ifdef XP_DEBUG_OBJ_USAGE
2645 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2646 #endif
2647 return(ret);
2648 }
2649 }
2650 return(xmlXPathNewFloat(val));
2651 }
2652
2653 /**
2654 * xmlXPathCacheConvertString:
2655 * @ctxt: the XPath context
2656 * @val: an XPath object
2657 *
2658 * This is the cached version of xmlXPathConvertString().
2659 * Converts an existing object to its string() equivalent
2660 *
2661 * Returns a created or reused object, the old one is freed (cached)
2662 * (or the operation is done directly on @val)
2663 */
2664
2665 static xmlXPathObjectPtr
2666 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2667 xmlChar *res = NULL;
2668
2669 if (val == NULL)
2670 return(xmlXPathCacheNewCString(ctxt, ""));
2671
2672 switch (val->type) {
2673 case XPATH_UNDEFINED:
2674 #ifdef DEBUG_EXPR
2675 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2676 #endif
2677 break;
2678 case XPATH_NODESET:
2679 case XPATH_XSLT_TREE:
2680 res = xmlXPathCastNodeSetToString(val->nodesetval);
2681 break;
2682 case XPATH_STRING:
2683 return(val);
2684 case XPATH_BOOLEAN:
2685 res = xmlXPathCastBooleanToString(val->boolval);
2686 break;
2687 case XPATH_NUMBER:
2688 res = xmlXPathCastNumberToString(val->floatval);
2689 break;
2690 case XPATH_USERS:
2691 case XPATH_POINT:
2692 case XPATH_RANGE:
2693 case XPATH_LOCATIONSET:
2694 TODO;
2695 break;
2696 }
2697 xmlXPathReleaseObject(ctxt, val);
2698 if (res == NULL)
2699 return(xmlXPathCacheNewCString(ctxt, ""));
2700 return(xmlXPathCacheWrapString(ctxt, res));
2701 }
2702
2703 /**
2704 * xmlXPathCacheObjectCopy:
2705 * @ctxt: the XPath context
2706 * @val: the original object
2707 *
2708 * This is the cached version of xmlXPathObjectCopy().
2709 * Acquire a copy of a given object
2710 *
2711 * Returns a created or reused created object.
2712 */
2713 static xmlXPathObjectPtr
2714 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2715 {
2716 if (val == NULL)
2717 return(NULL);
2718
2719 if (XP_HAS_CACHE(ctxt)) {
2720 switch (val->type) {
2721 case XPATH_NODESET:
2722 return(xmlXPathCacheWrapNodeSet(ctxt,
2723 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2724 case XPATH_STRING:
2725 return(xmlXPathCacheNewString(ctxt, val->stringval));
2726 case XPATH_BOOLEAN:
2727 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2728 case XPATH_NUMBER:
2729 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2730 default:
2731 break;
2732 }
2733 }
2734 return(xmlXPathObjectCopy(val));
2735 }
2736
2737 /**
2738 * xmlXPathCacheConvertBoolean:
2739 * @ctxt: the XPath context
2740 * @val: an XPath object
2741 *
2742 * This is the cached version of xmlXPathConvertBoolean().
2743 * Converts an existing object to its boolean() equivalent
2744 *
2745 * Returns a created or reused object, the old one is freed (or the operation
2746 * is done directly on @val)
2747 */
2748 static xmlXPathObjectPtr
2749 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2750 xmlXPathObjectPtr ret;
2751
2752 if (val == NULL)
2753 return(xmlXPathCacheNewBoolean(ctxt, 0));
2754 if (val->type == XPATH_BOOLEAN)
2755 return(val);
2756 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2757 xmlXPathReleaseObject(ctxt, val);
2758 return(ret);
2759 }
2760
2761 /**
2762 * xmlXPathCacheConvertNumber:
2763 * @ctxt: the XPath context
2764 * @val: an XPath object
2765 *
2766 * This is the cached version of xmlXPathConvertNumber().
2767 * Converts an existing object to its number() equivalent
2768 *
2769 * Returns a created or reused object, the old one is freed (or the operation
2770 * is done directly on @val)
2771 */
2772 static xmlXPathObjectPtr
2773 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774 xmlXPathObjectPtr ret;
2775
2776 if (val == NULL)
2777 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2778 if (val->type == XPATH_NUMBER)
2779 return(val);
2780 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2781 xmlXPathReleaseObject(ctxt, val);
2782 return(ret);
2783 }
2784
2785 /************************************************************************
2786 * *
2787 * Parser stacks related functions and macros *
2788 * *
2789 ************************************************************************/
2790
2791 /**
2792 * xmlXPathSetFrame:
2793 * @ctxt: an XPath parser context
2794 *
2795 * Set the callee evaluation frame
2796 *
2797 * Returns the previous frame value to be restored once done
2798 */
2799 static int
2800 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2801 int ret;
2802
2803 if (ctxt == NULL)
2804 return(0);
2805 ret = ctxt->valueFrame;
2806 ctxt->valueFrame = ctxt->valueNr;
2807 return(ret);
2808 }
2809
2810 /**
2811 * xmlXPathPopFrame:
2812 * @ctxt: an XPath parser context
2813 * @frame: the previous frame value
2814 *
2815 * Remove the callee evaluation frame
2816 */
2817 static void
2818 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2819 if (ctxt == NULL)
2820 return;
2821 if (ctxt->valueNr < ctxt->valueFrame) {
2822 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2823 }
2824 ctxt->valueFrame = frame;
2825 }
2826
2827 /**
2828 * valuePop:
2829 * @ctxt: an XPath evaluation context
2830 *
2831 * Pops the top XPath object from the value stack
2832 *
2833 * Returns the XPath object just removed
2834 */
2835 xmlXPathObjectPtr
2836 valuePop(xmlXPathParserContextPtr ctxt)
2837 {
2838 xmlXPathObjectPtr ret;
2839
2840 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2841 return (NULL);
2842
2843 if (ctxt->valueNr <= ctxt->valueFrame) {
2844 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2845 return (NULL);
2846 }
2847
2848 ctxt->valueNr--;
2849 if (ctxt->valueNr > 0)
2850 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2851 else
2852 ctxt->value = NULL;
2853 ret = ctxt->valueTab[ctxt->valueNr];
2854 ctxt->valueTab[ctxt->valueNr] = NULL;
2855 return (ret);
2856 }
2857 /**
2858 * valuePush:
2859 * @ctxt: an XPath evaluation context
2860 * @value: the XPath object
2861 *
2862 * Pushes a new XPath object on top of the value stack
2863 *
2864 * returns the number of items on the value stack
2865 */
2866 int
2867 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2868 {
2869 if ((ctxt == NULL) || (value == NULL)) return(-1);
2870 if (ctxt->valueNr >= ctxt->valueMax) {
2871 xmlXPathObjectPtr *tmp;
2872
2873 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2874 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2875 ctxt->error = XPATH_MEMORY_ERROR;
2876 return (0);
2877 }
2878 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2879 2 * ctxt->valueMax *
2880 sizeof(ctxt->valueTab[0]));
2881 if (tmp == NULL) {
2882 xmlXPathErrMemory(NULL, "pushing value\n");
2883 ctxt->error = XPATH_MEMORY_ERROR;
2884 return (0);
2885 }
2886 ctxt->valueMax *= 2;
2887 ctxt->valueTab = tmp;
2888 }
2889 ctxt->valueTab[ctxt->valueNr] = value;
2890 ctxt->value = value;
2891 return (ctxt->valueNr++);
2892 }
2893
2894 /**
2895 * xmlXPathPopBoolean:
2896 * @ctxt: an XPath parser context
2897 *
2898 * Pops a boolean from the stack, handling conversion if needed.
2899 * Check error with #xmlXPathCheckError.
2900 *
2901 * Returns the boolean
2902 */
2903 int
2904 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2905 xmlXPathObjectPtr obj;
2906 int ret;
2907
2908 obj = valuePop(ctxt);
2909 if (obj == NULL) {
2910 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2911 return(0);
2912 }
2913 if (obj->type != XPATH_BOOLEAN)
2914 ret = xmlXPathCastToBoolean(obj);
2915 else
2916 ret = obj->boolval;
2917 xmlXPathReleaseObject(ctxt->context, obj);
2918 return(ret);
2919 }
2920
2921 /**
2922 * xmlXPathPopNumber:
2923 * @ctxt: an XPath parser context
2924 *
2925 * Pops a number from the stack, handling conversion if needed.
2926 * Check error with #xmlXPathCheckError.
2927 *
2928 * Returns the number
2929 */
2930 double
2931 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2932 xmlXPathObjectPtr obj;
2933 double ret;
2934
2935 obj = valuePop(ctxt);
2936 if (obj == NULL) {
2937 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2938 return(0);
2939 }
2940 if (obj->type != XPATH_NUMBER)
2941 ret = xmlXPathCastToNumber(obj);
2942 else
2943 ret = obj->floatval;
2944 xmlXPathReleaseObject(ctxt->context, obj);
2945 return(ret);
2946 }
2947
2948 /**
2949 * xmlXPathPopString:
2950 * @ctxt: an XPath parser context
2951 *
2952 * Pops a string from the stack, handling conversion if needed.
2953 * Check error with #xmlXPathCheckError.
2954 *
2955 * Returns the string
2956 */
2957 xmlChar *
2958 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2959 xmlXPathObjectPtr obj;
2960 xmlChar * ret;
2961
2962 obj = valuePop(ctxt);
2963 if (obj == NULL) {
2964 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2965 return(NULL);
2966 }
2967 ret = xmlXPathCastToString(obj); /* this does required strdup */
2968 /* TODO: needs refactoring somewhere else */
2969 if (obj->stringval == ret)
2970 obj->stringval = NULL;
2971 xmlXPathReleaseObject(ctxt->context, obj);
2972 return(ret);
2973 }
2974
2975 /**
2976 * xmlXPathPopNodeSet:
2977 * @ctxt: an XPath parser context
2978 *
2979 * Pops a node-set from the stack, handling conversion if needed.
2980 * Check error with #xmlXPathCheckError.
2981 *
2982 * Returns the node-set
2983 */
2984 xmlNodeSetPtr
2985 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2986 xmlXPathObjectPtr obj;
2987 xmlNodeSetPtr ret;
2988
2989 if (ctxt == NULL) return(NULL);
2990 if (ctxt->value == NULL) {
2991 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2992 return(NULL);
2993 }
2994 if (!xmlXPathStackIsNodeSet(ctxt)) {
2995 xmlXPathSetTypeError(ctxt);
2996 return(NULL);
2997 }
2998 obj = valuePop(ctxt);
2999 ret = obj->nodesetval;
3000 #if 0
3001 /* to fix memory leak of not clearing obj->user */
3002 if (obj->boolval && obj->user != NULL)
3003 xmlFreeNodeList((xmlNodePtr) obj->user);
3004 #endif
3005 obj->nodesetval = NULL;
3006 xmlXPathReleaseObject(ctxt->context, obj);
3007 return(ret);
3008 }
3009
3010 /**
3011 * xmlXPathPopExternal:
3012 * @ctxt: an XPath parser context
3013 *
3014 * Pops an external object from the stack, handling conversion if needed.
3015 * Check error with #xmlXPathCheckError.
3016 *
3017 * Returns the object
3018 */
3019 void *
3020 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3021 xmlXPathObjectPtr obj;
3022 void * ret;
3023
3024 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3025 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3026 return(NULL);
3027 }
3028 if (ctxt->value->type != XPATH_USERS) {
3029 xmlXPathSetTypeError(ctxt);
3030 return(NULL);
3031 }
3032 obj = valuePop(ctxt);
3033 ret = obj->user;
3034 obj->user = NULL;
3035 xmlXPathReleaseObject(ctxt->context, obj);
3036 return(ret);
3037 }
3038
3039 /*
3040 * Macros for accessing the content. Those should be used only by the parser,
3041 * and not exported.
3042 *
3043 * Dirty macros, i.e. one need to make assumption on the context to use them
3044 *
3045 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3046 * CUR returns the current xmlChar value, i.e. a 8 bit value
3047 * in ISO-Latin or UTF-8.
3048 * This should be used internally by the parser
3049 * only to compare to ASCII values otherwise it would break when
3050 * running with UTF-8 encoding.
3051 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3052 * to compare on ASCII based substring.
3053 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3054 * strings within the parser.
3055 * CURRENT Returns the current char value, with the full decoding of
3056 * UTF-8 if we are using this mode. It returns an int.
3057 * NEXT Skip to the next character, this does the proper decoding
3058 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3059 * It returns the pointer to the current xmlChar.
3060 */
3061
3062 #define CUR (*ctxt->cur)
3063 #define SKIP(val) ctxt->cur += (val)
3064 #define NXT(val) ctxt->cur[(val)]
3065 #define CUR_PTR ctxt->cur
3066 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3067
3068 #define COPY_BUF(l,b,i,v) \
3069 if (l == 1) b[i++] = (xmlChar) v; \
3070 else i += xmlCopyChar(l,&b[i],v)
3071
3072 #define NEXTL(l) ctxt->cur += l
3073
3074 #define SKIP_BLANKS \
3075 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3076
3077 #define CURRENT (*ctxt->cur)
3078 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3079
3080
3081 #ifndef DBL_DIG
3082 #define DBL_DIG 16
3083 #endif
3084 #ifndef DBL_EPSILON
3085 #define DBL_EPSILON 1E-9
3086 #endif
3087
3088 #define UPPER_DOUBLE 1E9
3089 #define LOWER_DOUBLE 1E-5
3090 #define LOWER_DOUBLE_EXP 5
3091
3092 #define INTEGER_DIGITS DBL_DIG
3093 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3094 #define EXPONENT_DIGITS (3 + 2)
3095
3096 /**
3097 * xmlXPathFormatNumber:
3098 * @number: number to format
3099 * @buffer: output buffer
3100 * @buffersize: size of output buffer
3101 *
3102 * Convert the number into a string representation.
3103 */
3104 static void
3105 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3106 {
3107 switch (xmlXPathIsInf(number)) {
3108 case 1:
3109 if (buffersize > (int)sizeof("Infinity"))
3110 snprintf(buffer, buffersize, "Infinity");
3111 break;
3112 case -1:
3113 if (buffersize > (int)sizeof("-Infinity"))
3114 snprintf(buffer, buffersize, "-Infinity");
3115 break;
3116 default:
3117 if (xmlXPathIsNaN(number)) {
3118 if (buffersize > (int)sizeof("NaN"))
3119 snprintf(buffer, buffersize, "NaN");
3120 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
3121 snprintf(buffer, buffersize, "0");
3122 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3123 (number == (int) number)) {
3124 char work[30];
3125 char *ptr, *cur;
3126 int value = (int) number;
3127
3128 ptr = &buffer[0];
3129 if (value == 0) {
3130 *ptr++ = '0';
3131 } else {
3132 snprintf(work, 29, "%d", value);
3133 cur = &work[0];
3134 while ((*cur) && (ptr - buffer < buffersize)) {
3135 *ptr++ = *cur++;
3136 }
3137 }
3138 if (ptr - buffer < buffersize) {
3139 *ptr = 0;
3140 } else if (buffersize > 0) {
3141 ptr--;
3142 *ptr = 0;
3143 }
3144 } else {
3145 /*
3146 For the dimension of work,
3147 DBL_DIG is number of significant digits
3148 EXPONENT is only needed for "scientific notation"
3149 3 is sign, decimal point, and terminating zero
3150 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3151 Note that this dimension is slightly (a few characters)
3152 larger than actually necessary.
3153 */
3154 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3155 int integer_place, fraction_place;
3156 char *ptr;
3157 char *after_fraction;
3158 double absolute_value;
3159 int size;
3160
3161 absolute_value = fabs(number);
3162
3163 /*
3164 * First choose format - scientific or regular floating point.
3165 * In either case, result is in work, and after_fraction points
3166 * just past the fractional part.
3167 */
3168 if ( ((absolute_value > UPPER_DOUBLE) ||
3169 (absolute_value < LOWER_DOUBLE)) &&
3170 (absolute_value != 0.0) ) {
3171 /* Use scientific notation */
3172 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3173 fraction_place = DBL_DIG - 1;
3174 size = snprintf(work, sizeof(work),"%*.*e",
3175 integer_place, fraction_place, number);
3176 while ((size > 0) && (work[size] != 'e')) size--;
3177
3178 }
3179 else {
3180 /* Use regular notation */
3181 if (absolute_value > 0.0) {
3182 integer_place = (int)log10(absolute_value);
3183 if (integer_place > 0)
3184 fraction_place = DBL_DIG - integer_place - 1;
3185 else
3186 fraction_place = DBL_DIG - integer_place;
3187 } else {
3188 fraction_place = 1;
3189 }
3190 size = snprintf(work, sizeof(work), "%0.*f",
3191 fraction_place, number);
3192 }
3193
3194 /* Remove leading spaces sometimes inserted by snprintf */
3195 while (work[0] == ' ') {
3196 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3197 size--;
3198 }
3199
3200 /* Remove fractional trailing zeroes */
3201 after_fraction = work + size;
3202 ptr = after_fraction;
3203 while (*(--ptr) == '0')
3204 ;
3205 if (*ptr != '.')
3206 ptr++;
3207 while ((*ptr++ = *after_fraction++) != 0);
3208
3209 /* Finally copy result back to caller */
3210 size = strlen(work) + 1;
3211 if (size > buffersize) {
3212 work[buffersize - 1] = 0;
3213 size = buffersize;
3214 }
3215 memmove(buffer, work, size);
3216 }
3217 break;
3218 }
3219 }
3220
3221
3222 /************************************************************************
3223 * *
3224 * Routines to handle NodeSets *
3225 * *
3226 ************************************************************************/
3227
3228 /**
3229 * xmlXPathOrderDocElems:
3230 * @doc: an input document
3231 *
3232 * Call this routine to speed up XPath computation on static documents.
3233 * This stamps all the element nodes with the document order
3234 * Like for line information, the order is kept in the element->content
3235 * field, the value stored is actually - the node number (starting at -1)
3236 * to be able to differentiate from line numbers.
3237 *
3238 * Returns the number of elements found in the document or -1 in case
3239 * of error.
3240 */
3241 long
3242 xmlXPathOrderDocElems(xmlDocPtr doc) {
3243 ptrdiff_t count = 0;
3244 xmlNodePtr cur;
3245
3246 if (doc == NULL)
3247 return(-1);
3248 cur = doc->children;
3249 while (cur != NULL) {
3250 if (cur->type == XML_ELEMENT_NODE) {
3251 cur->content = (void *) (-(++count));
3252 if (cur->children != NULL) {
3253 cur = cur->children;
3254 continue;
3255 }
3256 }
3257 if (cur->next != NULL) {
3258 cur = cur->next;
3259 continue;
3260 }
3261 do {
3262 cur = cur->parent;
3263 if (cur == NULL)
3264 break;
3265 if (cur == (xmlNodePtr) doc) {
3266 cur = NULL;
3267 break;
3268 }
3269 if (cur->next != NULL) {
3270 cur = cur->next;
3271 break;
3272 }
3273 } while (cur != NULL);
3274 }
3275 return((long) count);
3276 }
3277
3278 /**
3279 * xmlXPathCmpNodes:
3280 * @node1: the first node
3281 * @node2: the second node
3282 *
3283 * Compare two nodes w.r.t document order
3284 *
3285 * Returns -2 in case of error 1 if first point < second point, 0 if
3286 * it's the same node, -1 otherwise
3287 */
3288 int
3289 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3290 int depth1, depth2;
3291 int attr1 = 0, attr2 = 0;
3292 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3293 xmlNodePtr cur, root;
3294
3295 if ((node1 == NULL) || (node2 == NULL))
3296 return(-2);
3297 /*
3298 * a couple of optimizations which will avoid computations in most cases
3299 */
3300 if (node1 == node2) /* trivial case */
3301 return(0);
3302 if (node1->type == XML_ATTRIBUTE_NODE) {
3303 attr1 = 1;
3304 attrNode1 = node1;
3305 node1 = node1->parent;
3306 }
3307 if (node2->type == XML_ATTRIBUTE_NODE) {
3308 attr2 = 1;
3309 attrNode2 = node2;
3310 node2 = node2->parent;
3311 }
3312 if (node1 == node2) {
3313 if (attr1 == attr2) {
3314 /* not required, but we keep attributes in order */
3315 if (attr1 != 0) {
3316 cur = attrNode2->prev;
3317 while (cur != NULL) {
3318 if (cur == attrNode1)
3319 return (1);
3320 cur = cur->prev;
3321 }
3322 return (-1);
3323 }
3324 return(0);
3325 }
3326 if (attr2 == 1)
3327 return(1);
3328 return(-1);
3329 }
3330 if ((node1->type == XML_NAMESPACE_DECL) ||
3331 (node2->type == XML_NAMESPACE_DECL))
3332 return(1);
3333 if (node1 == node2->prev)
3334 return(1);
3335 if (node1 == node2->next)
3336 return(-1);
3337
3338 /*
3339 * Speedup using document order if availble.
3340 */
3341 if ((node1->type == XML_ELEMENT_NODE) &&
3342 (node2->type == XML_ELEMENT_NODE) &&
3343 (0 > (ptrdiff_t) node1->content) &&
3344 (0 > (ptrdiff_t) node2->content) &&
3345 (node1->doc == node2->doc)) {
3346 ptrdiff_t l1, l2;
3347
3348 l1 = -((ptrdiff_t) node1->content);
3349 l2 = -((ptrdiff_t) node2->content);
3350 if (l1 < l2)
3351 return(1);
3352 if (l1 > l2)
3353 return(-1);
3354 }
3355
3356 /*
3357 * compute depth to root
3358 */
3359 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3360 if (cur->parent == node1)
3361 return(1);
3362 depth2++;
3363 }
3364 root = cur;
3365 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3366 if (cur->parent == node2)
3367 return(-1);
3368 depth1++;
3369 }
3370 /*
3371 * Distinct document (or distinct entities :-( ) case.
3372 */
3373 if (root != cur) {
3374 return(-2);
3375 }
3376 /*
3377 * get the nearest common ancestor.
3378 */
3379 while (depth1 > depth2) {
3380 depth1--;
3381 node1 = node1->parent;
3382 }
3383 while (depth2 > depth1) {
3384 depth2--;
3385 node2 = node2->parent;
3386 }
3387 while (node1->parent != node2->parent) {
3388 node1 = node1->parent;
3389 node2 = node2->parent;
3390 /* should not happen but just in case ... */
3391 if ((node1 == NULL) || (node2 == NULL))
3392 return(-2);
3393 }
3394 /*
3395 * Find who's first.
3396 */
3397 if (node1 == node2->prev)
3398 return(1);
3399 if (node1 == node2->next)
3400 return(-1);
3401 /*
3402 * Speedup using document order if availble.
3403 */
3404 if ((node1->type == XML_ELEMENT_NODE) &&
3405 (node2->type == XML_ELEMENT_NODE) &&
3406 (0 > (ptrdiff_t) node1->content) &&
3407 (0 > (ptrdiff_t) node2->content) &&
3408 (node1->doc == node2->doc)) {
3409 ptrdiff_t l1, l2;
3410
3411 l1 = -((ptrdiff_t) node1->content);
3412 l2 = -((ptrdiff_t) node2->content);
3413 if (l1 < l2)
3414 return(1);
3415 if (l1 > l2)
3416 return(-1);
3417 }
3418
3419 for (cur = node1->next;cur != NULL;cur = cur->next)
3420 if (cur == node2)
3421 return(1);
3422 return(-1); /* assume there is no sibling list corruption */
3423 }
3424
3425 /**
3426 * xmlXPathNodeSetSort:
3427 * @set: the node set
3428 *
3429 * Sort the node set in document order
3430 */
3431 void
3432 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3433 #ifndef WITH_TIM_SORT
3434 int i, j, incr, len;
3435 xmlNodePtr tmp;
3436 #endif
3437
3438 if (set == NULL)
3439 return;
3440
3441 #ifndef WITH_TIM_SORT
3442 /*
3443 * Use the old Shell's sort implementation to sort the node-set
3444 * Timsort ought to be quite faster
3445 */
3446 len = set->nodeNr;
3447 for (incr = len / 2; incr > 0; incr /= 2) {
3448 for (i = incr; i < len; i++) {
3449 j = i - incr;
3450 while (j >= 0) {
3451 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3452 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3453 set->nodeTab[j + incr]) == -1)
3454 #else
3455 if (xmlXPathCmpNodes(set->nodeTab[j],
3456 set->nodeTab[j + incr]) == -1)
3457 #endif
3458 {
3459 tmp = set->nodeTab[j];
3460 set->nodeTab[j] = set->nodeTab[j + incr];
3461 set->nodeTab[j + incr] = tmp;
3462 j -= incr;
3463 } else
3464 break;
3465 }
3466 }
3467 }
3468 #else /* WITH_TIM_SORT */
3469 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3470 #endif /* WITH_TIM_SORT */
3471 }
3472
3473 #define XML_NODESET_DEFAULT 10
3474 /**
3475 * xmlXPathNodeSetDupNs:
3476 * @node: the parent node of the namespace XPath node
3477 * @ns: the libxml namespace declaration node.
3478 *
3479 * Namespace node in libxml don't match the XPath semantic. In a node set
3480 * the namespace nodes are duplicated and the next pointer is set to the
3481 * parent node in the XPath semantic.
3482 *
3483 * Returns the newly created object.
3484 */
3485 static xmlNodePtr
3486 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3487 xmlNsPtr cur;
3488
3489 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3490 return(NULL);
3491 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3492 return((xmlNodePtr) ns);
3493
3494 /*
3495 * Allocate a new Namespace and fill the fields.
3496 */
3497 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3498 if (cur == NULL) {
3499 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3500 return(NULL);
3501 }
3502 memset(cur, 0, sizeof(xmlNs));
3503 cur->type = XML_NAMESPACE_DECL;
3504 if (ns->href != NULL)
3505 cur->href = xmlStrdup(ns->href);
3506 if (ns->prefix != NULL)
3507 cur->prefix = xmlStrdup(ns->prefix);
3508 cur->next = (xmlNsPtr) node;
3509 return((xmlNodePtr) cur);
3510 }
3511
3512 /**
3513 * xmlXPathNodeSetFreeNs:
3514 * @ns: the XPath namespace node found in a nodeset.
3515 *
3516 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3517 * the namespace nodes are duplicated and the next pointer is set to the
3518 * parent node in the XPath semantic. Check if such a node needs to be freed
3519 */
3520 void
3521 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3522 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3523 return;
3524
3525 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3526 if (ns->href != NULL)
3527 xmlFree((xmlChar *)ns->href);
3528 if (ns->prefix != NULL)
3529 xmlFree((xmlChar *)ns->prefix);
3530 xmlFree(ns);
3531 }
3532 }
3533
3534 /**
3535 * xmlXPathNodeSetCreate:
3536 * @val: an initial xmlNodePtr, or NULL
3537 *
3538 * Create a new xmlNodeSetPtr of type double and of value @val
3539 *
3540 * Returns the newly created object.
3541 */
3542 xmlNodeSetPtr
3543 xmlXPathNodeSetCreate(xmlNodePtr val) {
3544 xmlNodeSetPtr ret;
3545
3546 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3547 if (ret == NULL) {
3548 xmlXPathErrMemory(NULL, "creating nodeset\n");
3549 return(NULL);
3550 }
3551 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3552 if (val != NULL) {
3553 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3554 sizeof(xmlNodePtr));
3555 if (ret->nodeTab == NULL) {
3556 xmlXPathErrMemory(NULL, "creating nodeset\n");
3557 xmlFree(ret);
3558 return(NULL);
3559 }
3560 memset(ret->nodeTab, 0 ,
3561 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3562 ret->nodeMax = XML_NODESET_DEFAULT;
3563 if (val->type == XML_NAMESPACE_DECL) {
3564 xmlNsPtr ns = (xmlNsPtr) val;
3565
3566 ret->nodeTab[ret->nodeNr++] =
3567 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3568 } else
3569 ret->nodeTab[ret->nodeNr++] = val;
3570 }
3571 return(ret);
3572 }
3573
3574 /**
3575 * xmlXPathNodeSetCreateSize:
3576 * @size: the initial size of the set
3577 *
3578 * Create a new xmlNodeSetPtr of type double and of value @val
3579 *
3580 * Returns the newly created object.
3581 */
3582 static xmlNodeSetPtr
3583 xmlXPathNodeSetCreateSize(int size) {
3584 xmlNodeSetPtr ret;
3585
3586 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3587 if (ret == NULL) {
3588 xmlXPathErrMemory(NULL, "creating nodeset\n");
3589 return(NULL);
3590 }
3591 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3592 if (size < XML_NODESET_DEFAULT)
3593 size = XML_NODESET_DEFAULT;
3594 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3595 if (ret->nodeTab == NULL) {
3596 xmlXPathErrMemory(NULL, "creating nodeset\n");
3597 xmlFree(ret);
3598 return(NULL);
3599 }
3600 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3601 ret->nodeMax = size;
3602 return(ret);
3603 }
3604
3605 /**
3606 * xmlXPathNodeSetContains:
3607 * @cur: the node-set
3608 * @val: the node
3609 *
3610 * checks whether @cur contains @val
3611 *
3612 * Returns true (1) if @cur contains @val, false (0) otherwise
3613 */
3614 int
3615 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3616 int i;
3617
3618 if ((cur == NULL) || (val == NULL)) return(0);
3619 if (val->type == XML_NAMESPACE_DECL) {
3620 for (i = 0; i < cur->nodeNr; i++) {
3621 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3622 xmlNsPtr ns1, ns2;
3623
3624 ns1 = (xmlNsPtr) val;
3625 ns2 = (xmlNsPtr) cur->nodeTab[i];
3626 if (ns1 == ns2)
3627 return(1);
3628 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3629 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3630 return(1);
3631 }
3632 }
3633 } else {
3634 for (i = 0; i < cur->nodeNr; i++) {
3635 if (cur->nodeTab[i] == val)
3636 return(1);
3637 }
3638 }
3639 return(0);
3640 }
3641
3642 /**
3643 * xmlXPathNodeSetAddNs:
3644 * @cur: the initial node set
3645 * @node: the hosting node
3646 * @ns: a the namespace node
3647 *
3648 * add a new namespace node to an existing NodeSet
3649 *
3650 * Returns 0 in case of success and -1 in case of error
3651 */
3652 int
3653 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3654 int i;
3655
3656
3657 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3658 (ns->type != XML_NAMESPACE_DECL) ||
3659 (node->type != XML_ELEMENT_NODE))
3660 return(-1);
3661
3662 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3663 /*
3664 * prevent duplicates
3665 */
3666 for (i = 0;i < cur->nodeNr;i++) {
3667 if ((cur->nodeTab[i] != NULL) &&
3668 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3669 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3670 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3671 return(0);
3672 }
3673
3674 /*
3675 * grow the nodeTab if needed
3676 */
3677 if (cur->nodeMax == 0) {
3678 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3679 sizeof(xmlNodePtr));
3680 if (cur->nodeTab == NULL) {
3681 xmlXPathErrMemory(NULL, "growing nodeset\n");
3682 return(-1);
3683 }
3684 memset(cur->nodeTab, 0 ,
3685 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3686 cur->nodeMax = XML_NODESET_DEFAULT;
3687 } else if (cur->nodeNr == cur->nodeMax) {
3688 xmlNodePtr *temp;
3689
3690 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3691 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3692 return(-1);
3693 }
3694 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3695 sizeof(xmlNodePtr));
3696 if (temp == NULL) {
3697 xmlXPathErrMemory(NULL, "growing nodeset\n");
3698 return(-1);
3699 }
3700 cur->nodeMax *= 2;
3701 cur->nodeTab = temp;
3702 }
3703 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3704 return(0);
3705 }
3706
3707 /**
3708 * xmlXPathNodeSetAdd:
3709 * @cur: the initial node set
3710 * @val: a new xmlNodePtr
3711 *
3712 * add a new xmlNodePtr to an existing NodeSet
3713 *
3714 * Returns 0 in case of success, and -1 in case of error
3715 */
3716 int
3717 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3718 int i;
3719
3720 if ((cur == NULL) || (val == NULL)) return(-1);
3721
3722 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3723 /*
3724 * prevent duplicates
3725 */
3726 for (i = 0;i < cur->nodeNr;i++)
3727 if (cur->nodeTab[i] == val) return(0);
3728
3729 /*
3730 * grow the nodeTab if needed
3731 */
3732 if (cur->nodeMax == 0) {