[LIBXML2] Update to version 2.9.8. CORE-15280
[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 NAN
481 #define NAN (0.0 / 0.0)
482 #endif
483
484 #ifndef INFINITY
485 #define INFINITY HUGE_VAL
486 #endif
487
488 double xmlXPathNAN = NAN;
489 double xmlXPathPINF = INFINITY;
490 double xmlXPathNINF = -INFINITY;
491
492 /**
493 * xmlXPathInit:
494 *
495 * Initialize the XPath environment
496 *
497 * Does nothing but must be kept as public function.
498 */
499 void
500 xmlXPathInit(void) {
501 }
502
503 /**
504 * xmlXPathIsNaN:
505 * @val: a double value
506 *
507 * Returns 1 if the value is a NaN, 0 otherwise
508 */
509 int
510 xmlXPathIsNaN(double val) {
511 #ifdef isnan
512 return isnan(val);
513 #else
514 return !(val == val);
515 #endif
516 }
517
518 /**
519 * xmlXPathIsInf:
520 * @val: a double value
521 *
522 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
523 */
524 int
525 xmlXPathIsInf(double val) {
526 #ifdef isinf
527 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
528 #else
529 if (val >= HUGE_VAL)
530 return 1;
531 if (val <= -HUGE_VAL)
532 return -1;
533 return 0;
534 #endif
535 }
536
537 #endif /* SCHEMAS or XPATH */
538
539 #ifdef LIBXML_XPATH_ENABLED
540
541 /*
542 * TODO: when compatibility allows remove all "fake node libxslt" strings
543 * the test should just be name[0] = ' '
544 */
545 #ifdef DEBUG_XPATH_EXPRESSION
546 #define DEBUG_STEP
547 #define DEBUG_EXPR
548 #define DEBUG_EVAL_COUNTS
549 #endif
550
551 static xmlNs xmlXPathXMLNamespaceStruct = {
552 NULL,
553 XML_NAMESPACE_DECL,
554 XML_XML_NAMESPACE,
555 BAD_CAST "xml",
556 NULL,
557 NULL
558 };
559 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
560 #ifndef LIBXML_THREAD_ENABLED
561 /*
562 * Optimizer is disabled only when threaded apps are detected while
563 * the library ain't compiled for thread safety.
564 */
565 static int xmlXPathDisableOptimizer = 0;
566 #endif
567
568 /************************************************************************
569 * *
570 * Error handling routines *
571 * *
572 ************************************************************************/
573
574 /**
575 * XP_ERRORNULL:
576 * @X: the error code
577 *
578 * Macro to raise an XPath error and return NULL.
579 */
580 #define XP_ERRORNULL(X) \
581 { xmlXPathErr(ctxt, X); return(NULL); }
582
583 /*
584 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
585 */
586 static const char *xmlXPathErrorMessages[] = {
587 "Ok\n",
588 "Number encoding\n",
589 "Unfinished literal\n",
590 "Start of literal\n",
591 "Expected $ for variable reference\n",
592 "Undefined variable\n",
593 "Invalid predicate\n",
594 "Invalid expression\n",
595 "Missing closing curly brace\n",
596 "Unregistered function\n",
597 "Invalid operand\n",
598 "Invalid type\n",
599 "Invalid number of arguments\n",
600 "Invalid context size\n",
601 "Invalid context position\n",
602 "Memory allocation error\n",
603 "Syntax error\n",
604 "Resource error\n",
605 "Sub resource error\n",
606 "Undefined namespace prefix\n",
607 "Encoding error\n",
608 "Char out of XML range\n",
609 "Invalid or incomplete context\n",
610 "Stack usage error\n",
611 "Forbidden variable\n",
612 "?? Unknown error ??\n" /* Must be last in the list! */
613 };
614 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
615 sizeof(xmlXPathErrorMessages[0])) - 1)
616 /**
617 * xmlXPathErrMemory:
618 * @ctxt: an XPath context
619 * @extra: extra informations
620 *
621 * Handle a redefinition of attribute error
622 */
623 static void
624 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
625 {
626 if (ctxt != NULL) {
627 if (extra) {
628 xmlChar buf[200];
629
630 xmlStrPrintf(buf, 200,
631 "Memory allocation failed : %s\n",
632 extra);
633 ctxt->lastError.message = (char *) xmlStrdup(buf);
634 } else {
635 ctxt->lastError.message = (char *)
636 xmlStrdup(BAD_CAST "Memory allocation failed\n");
637 }
638 ctxt->lastError.domain = XML_FROM_XPATH;
639 ctxt->lastError.code = XML_ERR_NO_MEMORY;
640 if (ctxt->error != NULL)
641 ctxt->error(ctxt->userData, &ctxt->lastError);
642 } else {
643 if (extra)
644 __xmlRaiseError(NULL, NULL, NULL,
645 NULL, NULL, XML_FROM_XPATH,
646 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
647 extra, NULL, NULL, 0, 0,
648 "Memory allocation failed : %s\n", extra);
649 else
650 __xmlRaiseError(NULL, NULL, NULL,
651 NULL, NULL, XML_FROM_XPATH,
652 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
653 NULL, NULL, NULL, 0, 0,
654 "Memory allocation failed\n");
655 }
656 }
657
658 /**
659 * xmlXPathPErrMemory:
660 * @ctxt: an XPath parser context
661 * @extra: extra informations
662 *
663 * Handle a redefinition of attribute error
664 */
665 static void
666 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
667 {
668 if (ctxt == NULL)
669 xmlXPathErrMemory(NULL, extra);
670 else {
671 ctxt->error = XPATH_MEMORY_ERROR;
672 xmlXPathErrMemory(ctxt->context, extra);
673 }
674 }
675
676 /**
677 * xmlXPathErr:
678 * @ctxt: a XPath parser context
679 * @error: the error code
680 *
681 * Handle an XPath error
682 */
683 void
684 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
685 {
686 if ((error < 0) || (error > MAXERRNO))
687 error = MAXERRNO;
688 if (ctxt == NULL) {
689 __xmlRaiseError(NULL, NULL, NULL,
690 NULL, NULL, XML_FROM_XPATH,
691 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
692 XML_ERR_ERROR, NULL, 0,
693 NULL, NULL, NULL, 0, 0,
694 "%s", xmlXPathErrorMessages[error]);
695 return;
696 }
697 ctxt->error = error;
698 if (ctxt->context == NULL) {
699 __xmlRaiseError(NULL, NULL, NULL,
700 NULL, NULL, XML_FROM_XPATH,
701 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
702 XML_ERR_ERROR, NULL, 0,
703 (const char *) ctxt->base, NULL, NULL,
704 ctxt->cur - ctxt->base, 0,
705 "%s", xmlXPathErrorMessages[error]);
706 return;
707 }
708
709 /* cleanup current last error */
710 xmlResetError(&ctxt->context->lastError);
711
712 ctxt->context->lastError.domain = XML_FROM_XPATH;
713 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
714 XPATH_EXPRESSION_OK;
715 ctxt->context->lastError.level = XML_ERR_ERROR;
716 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
717 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
718 ctxt->context->lastError.node = ctxt->context->debugNode;
719 if (ctxt->context->error != NULL) {
720 ctxt->context->error(ctxt->context->userData,
721 &ctxt->context->lastError);
722 } else {
723 __xmlRaiseError(NULL, NULL, NULL,
724 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
725 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
726 XML_ERR_ERROR, NULL, 0,
727 (const char *) ctxt->base, NULL, NULL,
728 ctxt->cur - ctxt->base, 0,
729 "%s", xmlXPathErrorMessages[error]);
730 }
731
732 }
733
734 /**
735 * xmlXPatherror:
736 * @ctxt: the XPath Parser context
737 * @file: the file name
738 * @line: the line number
739 * @no: the error number
740 *
741 * Formats an error message.
742 */
743 void
744 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
745 int line ATTRIBUTE_UNUSED, int no) {
746 xmlXPathErr(ctxt, no);
747 }
748
749 /************************************************************************
750 * *
751 * Utilities *
752 * *
753 ************************************************************************/
754
755 /**
756 * xsltPointerList:
757 *
758 * Pointer-list for various purposes.
759 */
760 typedef struct _xmlPointerList xmlPointerList;
761 typedef xmlPointerList *xmlPointerListPtr;
762 struct _xmlPointerList {
763 void **items;
764 int number;
765 int size;
766 };
767 /*
768 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
769 * and here, we should make the functions public.
770 */
771 static int
772 xmlPointerListAddSize(xmlPointerListPtr list,
773 void *item,
774 int initialSize)
775 {
776 if (list->items == NULL) {
777 if (initialSize <= 0)
778 initialSize = 1;
779 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
780 if (list->items == NULL) {
781 xmlXPathErrMemory(NULL,
782 "xmlPointerListCreate: allocating item\n");
783 return(-1);
784 }
785 list->number = 0;
786 list->size = initialSize;
787 } else if (list->size <= list->number) {
788 if (list->size > 50000000) {
789 xmlXPathErrMemory(NULL,
790 "xmlPointerListAddSize: re-allocating item\n");
791 return(-1);
792 }
793 list->size *= 2;
794 list->items = (void **) xmlRealloc(list->items,
795 list->size * sizeof(void *));
796 if (list->items == NULL) {
797 xmlXPathErrMemory(NULL,
798 "xmlPointerListAddSize: re-allocating item\n");
799 list->size = 0;
800 return(-1);
801 }
802 }
803 list->items[list->number++] = item;
804 return(0);
805 }
806
807 /**
808 * xsltPointerListCreate:
809 *
810 * Creates an xsltPointerList structure.
811 *
812 * Returns a xsltPointerList structure or NULL in case of an error.
813 */
814 static xmlPointerListPtr
815 xmlPointerListCreate(int initialSize)
816 {
817 xmlPointerListPtr ret;
818
819 ret = xmlMalloc(sizeof(xmlPointerList));
820 if (ret == NULL) {
821 xmlXPathErrMemory(NULL,
822 "xmlPointerListCreate: allocating item\n");
823 return (NULL);
824 }
825 memset(ret, 0, sizeof(xmlPointerList));
826 if (initialSize > 0) {
827 xmlPointerListAddSize(ret, NULL, initialSize);
828 ret->number = 0;
829 }
830 return (ret);
831 }
832
833 /**
834 * xsltPointerListFree:
835 *
836 * Frees the xsltPointerList structure. This does not free
837 * the content of the list.
838 */
839 static void
840 xmlPointerListFree(xmlPointerListPtr list)
841 {
842 if (list == NULL)
843 return;
844 if (list->items != NULL)
845 xmlFree(list->items);
846 xmlFree(list);
847 }
848
849 /************************************************************************
850 * *
851 * Parser Types *
852 * *
853 ************************************************************************/
854
855 /*
856 * Types are private:
857 */
858
859 typedef enum {
860 XPATH_OP_END=0,
861 XPATH_OP_AND,
862 XPATH_OP_OR,
863 XPATH_OP_EQUAL,
864 XPATH_OP_CMP,
865 XPATH_OP_PLUS,
866 XPATH_OP_MULT,
867 XPATH_OP_UNION,
868 XPATH_OP_ROOT,
869 XPATH_OP_NODE,
870 XPATH_OP_RESET, /* 10 */
871 XPATH_OP_COLLECT,
872 XPATH_OP_VALUE, /* 12 */
873 XPATH_OP_VARIABLE,
874 XPATH_OP_FUNCTION,
875 XPATH_OP_ARG,
876 XPATH_OP_PREDICATE,
877 XPATH_OP_FILTER, /* 17 */
878 XPATH_OP_SORT /* 18 */
879 #ifdef LIBXML_XPTR_ENABLED
880 ,XPATH_OP_RANGETO
881 #endif
882 } xmlXPathOp;
883
884 typedef enum {
885 AXIS_ANCESTOR = 1,
886 AXIS_ANCESTOR_OR_SELF,
887 AXIS_ATTRIBUTE,
888 AXIS_CHILD,
889 AXIS_DESCENDANT,
890 AXIS_DESCENDANT_OR_SELF,
891 AXIS_FOLLOWING,
892 AXIS_FOLLOWING_SIBLING,
893 AXIS_NAMESPACE,
894 AXIS_PARENT,
895 AXIS_PRECEDING,
896 AXIS_PRECEDING_SIBLING,
897 AXIS_SELF
898 } xmlXPathAxisVal;
899
900 typedef enum {
901 NODE_TEST_NONE = 0,
902 NODE_TEST_TYPE = 1,
903 NODE_TEST_PI = 2,
904 NODE_TEST_ALL = 3,
905 NODE_TEST_NS = 4,
906 NODE_TEST_NAME = 5
907 } xmlXPathTestVal;
908
909 typedef enum {
910 NODE_TYPE_NODE = 0,
911 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
912 NODE_TYPE_TEXT = XML_TEXT_NODE,
913 NODE_TYPE_PI = XML_PI_NODE
914 } xmlXPathTypeVal;
915
916 typedef struct _xmlXPathStepOp xmlXPathStepOp;
917 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
918 struct _xmlXPathStepOp {
919 xmlXPathOp op; /* The identifier of the operation */
920 int ch1; /* First child */
921 int ch2; /* Second child */
922 int value;
923 int value2;
924 int value3;
925 void *value4;
926 void *value5;
927 xmlXPathFunction cache;
928 void *cacheURI;
929 };
930
931 struct _xmlXPathCompExpr {
932 int nbStep; /* Number of steps in this expression */
933 int maxStep; /* Maximum number of steps allocated */
934 xmlXPathStepOp *steps; /* ops for computation of this expression */
935 int last; /* index of last step in expression */
936 xmlChar *expr; /* the expression being computed */
937 xmlDictPtr dict; /* the dictionary to use if any */
938 #ifdef DEBUG_EVAL_COUNTS
939 int nb;
940 xmlChar *string;
941 #endif
942 #ifdef XPATH_STREAMING
943 xmlPatternPtr stream;
944 #endif
945 };
946
947 /************************************************************************
948 * *
949 * Forward declarations *
950 * *
951 ************************************************************************/
952 static void
953 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
954 static void
955 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
956 static int
957 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
958 xmlXPathStepOpPtr op, xmlNodePtr *first);
959 static int
960 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
961 xmlXPathStepOpPtr op,
962 int isPredicate);
963 static void
964 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
965
966 /************************************************************************
967 * *
968 * Parser Type functions *
969 * *
970 ************************************************************************/
971
972 /**
973 * xmlXPathNewCompExpr:
974 *
975 * Create a new Xpath component
976 *
977 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
978 */
979 static xmlXPathCompExprPtr
980 xmlXPathNewCompExpr(void) {
981 xmlXPathCompExprPtr cur;
982
983 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
984 if (cur == NULL) {
985 xmlXPathErrMemory(NULL, "allocating component\n");
986 return(NULL);
987 }
988 memset(cur, 0, sizeof(xmlXPathCompExpr));
989 cur->maxStep = 10;
990 cur->nbStep = 0;
991 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
992 sizeof(xmlXPathStepOp));
993 if (cur->steps == NULL) {
994 xmlXPathErrMemory(NULL, "allocating steps\n");
995 xmlFree(cur);
996 return(NULL);
997 }
998 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
999 cur->last = -1;
1000 #ifdef DEBUG_EVAL_COUNTS
1001 cur->nb = 0;
1002 #endif
1003 return(cur);
1004 }
1005
1006 /**
1007 * xmlXPathFreeCompExpr:
1008 * @comp: an XPATH comp
1009 *
1010 * Free up the memory allocated by @comp
1011 */
1012 void
1013 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1014 {
1015 xmlXPathStepOpPtr op;
1016 int i;
1017
1018 if (comp == NULL)
1019 return;
1020 if (comp->dict == NULL) {
1021 for (i = 0; i < comp->nbStep; i++) {
1022 op = &comp->steps[i];
1023 if (op->value4 != NULL) {
1024 if (op->op == XPATH_OP_VALUE)
1025 xmlXPathFreeObject(op->value4);
1026 else
1027 xmlFree(op->value4);
1028 }
1029 if (op->value5 != NULL)
1030 xmlFree(op->value5);
1031 }
1032 } else {
1033 for (i = 0; i < comp->nbStep; i++) {
1034 op = &comp->steps[i];
1035 if (op->value4 != NULL) {
1036 if (op->op == XPATH_OP_VALUE)
1037 xmlXPathFreeObject(op->value4);
1038 }
1039 }
1040 xmlDictFree(comp->dict);
1041 }
1042 if (comp->steps != NULL) {
1043 xmlFree(comp->steps);
1044 }
1045 #ifdef DEBUG_EVAL_COUNTS
1046 if (comp->string != NULL) {
1047 xmlFree(comp->string);
1048 }
1049 #endif
1050 #ifdef XPATH_STREAMING
1051 if (comp->stream != NULL) {
1052 xmlFreePatternList(comp->stream);
1053 }
1054 #endif
1055 if (comp->expr != NULL) {
1056 xmlFree(comp->expr);
1057 }
1058
1059 xmlFree(comp);
1060 }
1061
1062 /**
1063 * xmlXPathCompExprAdd:
1064 * @comp: the compiled expression
1065 * @ch1: first child index
1066 * @ch2: second child index
1067 * @op: an op
1068 * @value: the first int value
1069 * @value2: the second int value
1070 * @value3: the third int value
1071 * @value4: the first string value
1072 * @value5: the second string value
1073 *
1074 * Add a step to an XPath Compiled Expression
1075 *
1076 * Returns -1 in case of failure, the index otherwise
1077 */
1078 static int
1079 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1080 xmlXPathOp op, int value,
1081 int value2, int value3, void *value4, void *value5) {
1082 if (comp->nbStep >= comp->maxStep) {
1083 xmlXPathStepOp *real;
1084
1085 if (comp->maxStep >= XPATH_MAX_STEPS) {
1086 xmlXPathErrMemory(NULL, "adding step\n");
1087 return(-1);
1088 }
1089 comp->maxStep *= 2;
1090 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1091 comp->maxStep * sizeof(xmlXPathStepOp));
1092 if (real == NULL) {
1093 comp->maxStep /= 2;
1094 xmlXPathErrMemory(NULL, "adding step\n");
1095 return(-1);
1096 }
1097 comp->steps = real;
1098 }
1099 comp->last = comp->nbStep;
1100 comp->steps[comp->nbStep].ch1 = ch1;
1101 comp->steps[comp->nbStep].ch2 = ch2;
1102 comp->steps[comp->nbStep].op = op;
1103 comp->steps[comp->nbStep].value = value;
1104 comp->steps[comp->nbStep].value2 = value2;
1105 comp->steps[comp->nbStep].value3 = value3;
1106 if ((comp->dict != NULL) &&
1107 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1108 (op == XPATH_OP_COLLECT))) {
1109 if (value4 != NULL) {
1110 comp->steps[comp->nbStep].value4 = (xmlChar *)
1111 (void *)xmlDictLookup(comp->dict, value4, -1);
1112 xmlFree(value4);
1113 } else
1114 comp->steps[comp->nbStep].value4 = NULL;
1115 if (value5 != NULL) {
1116 comp->steps[comp->nbStep].value5 = (xmlChar *)
1117 (void *)xmlDictLookup(comp->dict, value5, -1);
1118 xmlFree(value5);
1119 } else
1120 comp->steps[comp->nbStep].value5 = NULL;
1121 } else {
1122 comp->steps[comp->nbStep].value4 = value4;
1123 comp->steps[comp->nbStep].value5 = value5;
1124 }
1125 comp->steps[comp->nbStep].cache = NULL;
1126 return(comp->nbStep++);
1127 }
1128
1129 /**
1130 * xmlXPathCompSwap:
1131 * @comp: the compiled expression
1132 * @op: operation index
1133 *
1134 * Swaps 2 operations in the compiled expression
1135 */
1136 static void
1137 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1138 int tmp;
1139
1140 #ifndef LIBXML_THREAD_ENABLED
1141 /*
1142 * Since this manipulates possibly shared variables, this is
1143 * disabled if one detects that the library is used in a multithreaded
1144 * application
1145 */
1146 if (xmlXPathDisableOptimizer)
1147 return;
1148 #endif
1149
1150 tmp = op->ch1;
1151 op->ch1 = op->ch2;
1152 op->ch2 = tmp;
1153 }
1154
1155 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1156 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1157 (op), (val), (val2), (val3), (val4), (val5))
1158 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1159 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1160 (op), (val), (val2), (val3), (val4), (val5))
1161
1162 #define PUSH_LEAVE_EXPR(op, val, val2) \
1163 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1164
1165 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1166 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1167
1168 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1169 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1170 (val), (val2), 0 ,NULL ,NULL)
1171
1172 /************************************************************************
1173 * *
1174 * XPath object cache structures *
1175 * *
1176 ************************************************************************/
1177
1178 /* #define XP_DEFAULT_CACHE_ON */
1179
1180 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1181
1182 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1183 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1184 struct _xmlXPathContextCache {
1185 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1186 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1187 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1188 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1189 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1190 int maxNodeset;
1191 int maxString;
1192 int maxBoolean;
1193 int maxNumber;
1194 int maxMisc;
1195 #ifdef XP_DEBUG_OBJ_USAGE
1196 int dbgCachedAll;
1197 int dbgCachedNodeset;
1198 int dbgCachedString;
1199 int dbgCachedBool;
1200 int dbgCachedNumber;
1201 int dbgCachedPoint;
1202 int dbgCachedRange;
1203 int dbgCachedLocset;
1204 int dbgCachedUsers;
1205 int dbgCachedXSLTTree;
1206 int dbgCachedUndefined;
1207
1208
1209 int dbgReusedAll;
1210 int dbgReusedNodeset;
1211 int dbgReusedString;
1212 int dbgReusedBool;
1213 int dbgReusedNumber;
1214 int dbgReusedPoint;
1215 int dbgReusedRange;
1216 int dbgReusedLocset;
1217 int dbgReusedUsers;
1218 int dbgReusedXSLTTree;
1219 int dbgReusedUndefined;
1220
1221 #endif
1222 };
1223
1224 /************************************************************************
1225 * *
1226 * Debugging related functions *
1227 * *
1228 ************************************************************************/
1229
1230 #define STRANGE \
1231 xmlGenericError(xmlGenericErrorContext, \
1232 "Internal error at %s:%d\n", \
1233 __FILE__, __LINE__);
1234
1235 #ifdef LIBXML_DEBUG_ENABLED
1236 static void
1237 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1238 int i;
1239 char shift[100];
1240
1241 for (i = 0;((i < depth) && (i < 25));i++)
1242 shift[2 * i] = shift[2 * i + 1] = ' ';
1243 shift[2 * i] = shift[2 * i + 1] = 0;
1244 if (cur == NULL) {
1245 fprintf(output, "%s", shift);
1246 fprintf(output, "Node is NULL !\n");
1247 return;
1248
1249 }
1250
1251 if ((cur->type == XML_DOCUMENT_NODE) ||
1252 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1253 fprintf(output, "%s", shift);
1254 fprintf(output, " /\n");
1255 } else if (cur->type == XML_ATTRIBUTE_NODE)
1256 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1257 else
1258 xmlDebugDumpOneNode(output, cur, depth);
1259 }
1260 static void
1261 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1262 xmlNodePtr tmp;
1263 int i;
1264 char shift[100];
1265
1266 for (i = 0;((i < depth) && (i < 25));i++)
1267 shift[2 * i] = shift[2 * i + 1] = ' ';
1268 shift[2 * i] = shift[2 * i + 1] = 0;
1269 if (cur == NULL) {
1270 fprintf(output, "%s", shift);
1271 fprintf(output, "Node is NULL !\n");
1272 return;
1273
1274 }
1275
1276 while (cur != NULL) {
1277 tmp = cur;
1278 cur = cur->next;
1279 xmlDebugDumpOneNode(output, tmp, depth);
1280 }
1281 }
1282
1283 static void
1284 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1285 int i;
1286 char shift[100];
1287
1288 for (i = 0;((i < depth) && (i < 25));i++)
1289 shift[2 * i] = shift[2 * i + 1] = ' ';
1290 shift[2 * i] = shift[2 * i + 1] = 0;
1291
1292 if (cur == NULL) {
1293 fprintf(output, "%s", shift);
1294 fprintf(output, "NodeSet is NULL !\n");
1295 return;
1296
1297 }
1298
1299 if (cur != NULL) {
1300 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1301 for (i = 0;i < cur->nodeNr;i++) {
1302 fprintf(output, "%s", shift);
1303 fprintf(output, "%d", i + 1);
1304 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1305 }
1306 }
1307 }
1308
1309 static void
1310 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1311 int i;
1312 char shift[100];
1313
1314 for (i = 0;((i < depth) && (i < 25));i++)
1315 shift[2 * i] = shift[2 * i + 1] = ' ';
1316 shift[2 * i] = shift[2 * i + 1] = 0;
1317
1318 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1319 fprintf(output, "%s", shift);
1320 fprintf(output, "Value Tree is NULL !\n");
1321 return;
1322
1323 }
1324
1325 fprintf(output, "%s", shift);
1326 fprintf(output, "%d", i + 1);
1327 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1328 }
1329 #if defined(LIBXML_XPTR_ENABLED)
1330 static void
1331 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1332 int i;
1333 char shift[100];
1334
1335 for (i = 0;((i < depth) && (i < 25));i++)
1336 shift[2 * i] = shift[2 * i + 1] = ' ';
1337 shift[2 * i] = shift[2 * i + 1] = 0;
1338
1339 if (cur == NULL) {
1340 fprintf(output, "%s", shift);
1341 fprintf(output, "LocationSet is NULL !\n");
1342 return;
1343
1344 }
1345
1346 for (i = 0;i < cur->locNr;i++) {
1347 fprintf(output, "%s", shift);
1348 fprintf(output, "%d : ", i + 1);
1349 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1350 }
1351 }
1352 #endif /* LIBXML_XPTR_ENABLED */
1353
1354 /**
1355 * xmlXPathDebugDumpObject:
1356 * @output: the FILE * to dump the output
1357 * @cur: the object to inspect
1358 * @depth: indentation level
1359 *
1360 * Dump the content of the object for debugging purposes
1361 */
1362 void
1363 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1364 int i;
1365 char shift[100];
1366
1367 if (output == NULL) return;
1368
1369 for (i = 0;((i < depth) && (i < 25));i++)
1370 shift[2 * i] = shift[2 * i + 1] = ' ';
1371 shift[2 * i] = shift[2 * i + 1] = 0;
1372
1373
1374 fprintf(output, "%s", shift);
1375
1376 if (cur == NULL) {
1377 fprintf(output, "Object is empty (NULL)\n");
1378 return;
1379 }
1380 switch(cur->type) {
1381 case XPATH_UNDEFINED:
1382 fprintf(output, "Object is uninitialized\n");
1383 break;
1384 case XPATH_NODESET:
1385 fprintf(output, "Object is a Node Set :\n");
1386 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1387 break;
1388 case XPATH_XSLT_TREE:
1389 fprintf(output, "Object is an XSLT value tree :\n");
1390 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1391 break;
1392 case XPATH_BOOLEAN:
1393 fprintf(output, "Object is a Boolean : ");
1394 if (cur->boolval) fprintf(output, "true\n");
1395 else fprintf(output, "false\n");
1396 break;
1397 case XPATH_NUMBER:
1398 switch (xmlXPathIsInf(cur->floatval)) {
1399 case 1:
1400 fprintf(output, "Object is a number : Infinity\n");
1401 break;
1402 case -1:
1403 fprintf(output, "Object is a number : -Infinity\n");
1404 break;
1405 default:
1406 if (xmlXPathIsNaN(cur->floatval)) {
1407 fprintf(output, "Object is a number : NaN\n");
1408 } else if (cur->floatval == 0) {
1409 /* Omit sign for negative zero. */
1410 fprintf(output, "Object is a number : 0\n");
1411 } else {
1412 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1413 }
1414 }
1415 break;
1416 case XPATH_STRING:
1417 fprintf(output, "Object is a string : ");
1418 xmlDebugDumpString(output, cur->stringval);
1419 fprintf(output, "\n");
1420 break;
1421 case XPATH_POINT:
1422 fprintf(output, "Object is a point : index %d in node", cur->index);
1423 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1424 fprintf(output, "\n");
1425 break;
1426 case XPATH_RANGE:
1427 if ((cur->user2 == NULL) ||
1428 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1429 fprintf(output, "Object is a collapsed range :\n");
1430 fprintf(output, "%s", shift);
1431 if (cur->index >= 0)
1432 fprintf(output, "index %d in ", cur->index);
1433 fprintf(output, "node\n");
1434 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1435 depth + 1);
1436 } else {
1437 fprintf(output, "Object is a range :\n");
1438 fprintf(output, "%s", shift);
1439 fprintf(output, "From ");
1440 if (cur->index >= 0)
1441 fprintf(output, "index %d in ", cur->index);
1442 fprintf(output, "node\n");
1443 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1444 depth + 1);
1445 fprintf(output, "%s", shift);
1446 fprintf(output, "To ");
1447 if (cur->index2 >= 0)
1448 fprintf(output, "index %d in ", cur->index2);
1449 fprintf(output, "node\n");
1450 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1451 depth + 1);
1452 fprintf(output, "\n");
1453 }
1454 break;
1455 case XPATH_LOCATIONSET:
1456 #if defined(LIBXML_XPTR_ENABLED)
1457 fprintf(output, "Object is a Location Set:\n");
1458 xmlXPathDebugDumpLocationSet(output,
1459 (xmlLocationSetPtr) cur->user, depth);
1460 #endif
1461 break;
1462 case XPATH_USERS:
1463 fprintf(output, "Object is user defined\n");
1464 break;
1465 }
1466 }
1467
1468 static void
1469 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1470 xmlXPathStepOpPtr op, int depth) {
1471 int i;
1472 char shift[100];
1473
1474 for (i = 0;((i < depth) && (i < 25));i++)
1475 shift[2 * i] = shift[2 * i + 1] = ' ';
1476 shift[2 * i] = shift[2 * i + 1] = 0;
1477
1478 fprintf(output, "%s", shift);
1479 if (op == NULL) {
1480 fprintf(output, "Step is NULL\n");
1481 return;
1482 }
1483 switch (op->op) {
1484 case XPATH_OP_END:
1485 fprintf(output, "END"); break;
1486 case XPATH_OP_AND:
1487 fprintf(output, "AND"); break;
1488 case XPATH_OP_OR:
1489 fprintf(output, "OR"); break;
1490 case XPATH_OP_EQUAL:
1491 if (op->value)
1492 fprintf(output, "EQUAL =");
1493 else
1494 fprintf(output, "EQUAL !=");
1495 break;
1496 case XPATH_OP_CMP:
1497 if (op->value)
1498 fprintf(output, "CMP <");
1499 else
1500 fprintf(output, "CMP >");
1501 if (!op->value2)
1502 fprintf(output, "=");
1503 break;
1504 case XPATH_OP_PLUS:
1505 if (op->value == 0)
1506 fprintf(output, "PLUS -");
1507 else if (op->value == 1)
1508 fprintf(output, "PLUS +");
1509 else if (op->value == 2)
1510 fprintf(output, "PLUS unary -");
1511 else if (op->value == 3)
1512 fprintf(output, "PLUS unary - -");
1513 break;
1514 case XPATH_OP_MULT:
1515 if (op->value == 0)
1516 fprintf(output, "MULT *");
1517 else if (op->value == 1)
1518 fprintf(output, "MULT div");
1519 else
1520 fprintf(output, "MULT mod");
1521 break;
1522 case XPATH_OP_UNION:
1523 fprintf(output, "UNION"); break;
1524 case XPATH_OP_ROOT:
1525 fprintf(output, "ROOT"); break;
1526 case XPATH_OP_NODE:
1527 fprintf(output, "NODE"); break;
1528 case XPATH_OP_RESET:
1529 fprintf(output, "RESET"); break;
1530 case XPATH_OP_SORT:
1531 fprintf(output, "SORT"); break;
1532 case XPATH_OP_COLLECT: {
1533 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1534 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1535 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1536 const xmlChar *prefix = op->value4;
1537 const xmlChar *name = op->value5;
1538
1539 fprintf(output, "COLLECT ");
1540 switch (axis) {
1541 case AXIS_ANCESTOR:
1542 fprintf(output, " 'ancestors' "); break;
1543 case AXIS_ANCESTOR_OR_SELF:
1544 fprintf(output, " 'ancestors-or-self' "); break;
1545 case AXIS_ATTRIBUTE:
1546 fprintf(output, " 'attributes' "); break;
1547 case AXIS_CHILD:
1548 fprintf(output, " 'child' "); break;
1549 case AXIS_DESCENDANT:
1550 fprintf(output, " 'descendant' "); break;
1551 case AXIS_DESCENDANT_OR_SELF:
1552 fprintf(output, " 'descendant-or-self' "); break;
1553 case AXIS_FOLLOWING:
1554 fprintf(output, " 'following' "); break;
1555 case AXIS_FOLLOWING_SIBLING:
1556 fprintf(output, " 'following-siblings' "); break;
1557 case AXIS_NAMESPACE:
1558 fprintf(output, " 'namespace' "); break;
1559 case AXIS_PARENT:
1560 fprintf(output, " 'parent' "); break;
1561 case AXIS_PRECEDING:
1562 fprintf(output, " 'preceding' "); break;
1563 case AXIS_PRECEDING_SIBLING:
1564 fprintf(output, " 'preceding-sibling' "); break;
1565 case AXIS_SELF:
1566 fprintf(output, " 'self' "); break;
1567 }
1568 switch (test) {
1569 case NODE_TEST_NONE:
1570 fprintf(output, "'none' "); break;
1571 case NODE_TEST_TYPE:
1572 fprintf(output, "'type' "); break;
1573 case NODE_TEST_PI:
1574 fprintf(output, "'PI' "); break;
1575 case NODE_TEST_ALL:
1576 fprintf(output, "'all' "); break;
1577 case NODE_TEST_NS:
1578 fprintf(output, "'namespace' "); break;
1579 case NODE_TEST_NAME:
1580 fprintf(output, "'name' "); break;
1581 }
1582 switch (type) {
1583 case NODE_TYPE_NODE:
1584 fprintf(output, "'node' "); break;
1585 case NODE_TYPE_COMMENT:
1586 fprintf(output, "'comment' "); break;
1587 case NODE_TYPE_TEXT:
1588 fprintf(output, "'text' "); break;
1589 case NODE_TYPE_PI:
1590 fprintf(output, "'PI' "); break;
1591 }
1592 if (prefix != NULL)
1593 fprintf(output, "%s:", prefix);
1594 if (name != NULL)
1595 fprintf(output, "%s", (const char *) name);
1596 break;
1597
1598 }
1599 case XPATH_OP_VALUE: {
1600 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1601
1602 fprintf(output, "ELEM ");
1603 xmlXPathDebugDumpObject(output, object, 0);
1604 goto finish;
1605 }
1606 case XPATH_OP_VARIABLE: {
1607 const xmlChar *prefix = op->value5;
1608 const xmlChar *name = op->value4;
1609
1610 if (prefix != NULL)
1611 fprintf(output, "VARIABLE %s:%s", prefix, name);
1612 else
1613 fprintf(output, "VARIABLE %s", name);
1614 break;
1615 }
1616 case XPATH_OP_FUNCTION: {
1617 int nbargs = op->value;
1618 const xmlChar *prefix = op->value5;
1619 const xmlChar *name = op->value4;
1620
1621 if (prefix != NULL)
1622 fprintf(output, "FUNCTION %s:%s(%d args)",
1623 prefix, name, nbargs);
1624 else
1625 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1626 break;
1627 }
1628 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1629 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1630 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1631 #ifdef LIBXML_XPTR_ENABLED
1632 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1633 #endif
1634 default:
1635 fprintf(output, "UNKNOWN %d\n", op->op); return;
1636 }
1637 fprintf(output, "\n");
1638 finish:
1639 if (op->ch1 >= 0)
1640 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1641 if (op->ch2 >= 0)
1642 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1643 }
1644
1645 /**
1646 * xmlXPathDebugDumpCompExpr:
1647 * @output: the FILE * for the output
1648 * @comp: the precompiled XPath expression
1649 * @depth: the indentation level.
1650 *
1651 * Dumps the tree of the compiled XPath expression.
1652 */
1653 void
1654 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1655 int depth) {
1656 int i;
1657 char shift[100];
1658
1659 if ((output == NULL) || (comp == NULL)) return;
1660
1661 for (i = 0;((i < depth) && (i < 25));i++)
1662 shift[2 * i] = shift[2 * i + 1] = ' ';
1663 shift[2 * i] = shift[2 * i + 1] = 0;
1664
1665 fprintf(output, "%s", shift);
1666
1667 #ifdef XPATH_STREAMING
1668 if (comp->stream) {
1669 fprintf(output, "Streaming Expression\n");
1670 } else
1671 #endif
1672 {
1673 fprintf(output, "Compiled Expression : %d elements\n",
1674 comp->nbStep);
1675 i = comp->last;
1676 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1677 }
1678 }
1679
1680 #ifdef XP_DEBUG_OBJ_USAGE
1681
1682 /*
1683 * XPath object usage related debugging variables.
1684 */
1685 static int xmlXPathDebugObjCounterUndefined = 0;
1686 static int xmlXPathDebugObjCounterNodeset = 0;
1687 static int xmlXPathDebugObjCounterBool = 0;
1688 static int xmlXPathDebugObjCounterNumber = 0;
1689 static int xmlXPathDebugObjCounterString = 0;
1690 static int xmlXPathDebugObjCounterPoint = 0;
1691 static int xmlXPathDebugObjCounterRange = 0;
1692 static int xmlXPathDebugObjCounterLocset = 0;
1693 static int xmlXPathDebugObjCounterUsers = 0;
1694 static int xmlXPathDebugObjCounterXSLTTree = 0;
1695 static int xmlXPathDebugObjCounterAll = 0;
1696
1697 static int xmlXPathDebugObjTotalUndefined = 0;
1698 static int xmlXPathDebugObjTotalNodeset = 0;
1699 static int xmlXPathDebugObjTotalBool = 0;
1700 static int xmlXPathDebugObjTotalNumber = 0;
1701 static int xmlXPathDebugObjTotalString = 0;
1702 static int xmlXPathDebugObjTotalPoint = 0;
1703 static int xmlXPathDebugObjTotalRange = 0;
1704 static int xmlXPathDebugObjTotalLocset = 0;
1705 static int xmlXPathDebugObjTotalUsers = 0;
1706 static int xmlXPathDebugObjTotalXSLTTree = 0;
1707 static int xmlXPathDebugObjTotalAll = 0;
1708
1709 static int xmlXPathDebugObjMaxUndefined = 0;
1710 static int xmlXPathDebugObjMaxNodeset = 0;
1711 static int xmlXPathDebugObjMaxBool = 0;
1712 static int xmlXPathDebugObjMaxNumber = 0;
1713 static int xmlXPathDebugObjMaxString = 0;
1714 static int xmlXPathDebugObjMaxPoint = 0;
1715 static int xmlXPathDebugObjMaxRange = 0;
1716 static int xmlXPathDebugObjMaxLocset = 0;
1717 static int xmlXPathDebugObjMaxUsers = 0;
1718 static int xmlXPathDebugObjMaxXSLTTree = 0;
1719 static int xmlXPathDebugObjMaxAll = 0;
1720
1721 /* REVISIT TODO: Make this static when committing */
1722 static void
1723 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1724 {
1725 if (ctxt != NULL) {
1726 if (ctxt->cache != NULL) {
1727 xmlXPathContextCachePtr cache =
1728 (xmlXPathContextCachePtr) ctxt->cache;
1729
1730 cache->dbgCachedAll = 0;
1731 cache->dbgCachedNodeset = 0;
1732 cache->dbgCachedString = 0;
1733 cache->dbgCachedBool = 0;
1734 cache->dbgCachedNumber = 0;
1735 cache->dbgCachedPoint = 0;
1736 cache->dbgCachedRange = 0;
1737 cache->dbgCachedLocset = 0;
1738 cache->dbgCachedUsers = 0;
1739 cache->dbgCachedXSLTTree = 0;
1740 cache->dbgCachedUndefined = 0;
1741
1742 cache->dbgReusedAll = 0;
1743 cache->dbgReusedNodeset = 0;
1744 cache->dbgReusedString = 0;
1745 cache->dbgReusedBool = 0;
1746 cache->dbgReusedNumber = 0;
1747 cache->dbgReusedPoint = 0;
1748 cache->dbgReusedRange = 0;
1749 cache->dbgReusedLocset = 0;
1750 cache->dbgReusedUsers = 0;
1751 cache->dbgReusedXSLTTree = 0;
1752 cache->dbgReusedUndefined = 0;
1753 }
1754 }
1755
1756 xmlXPathDebugObjCounterUndefined = 0;
1757 xmlXPathDebugObjCounterNodeset = 0;
1758 xmlXPathDebugObjCounterBool = 0;
1759 xmlXPathDebugObjCounterNumber = 0;
1760 xmlXPathDebugObjCounterString = 0;
1761 xmlXPathDebugObjCounterPoint = 0;
1762 xmlXPathDebugObjCounterRange = 0;
1763 xmlXPathDebugObjCounterLocset = 0;
1764 xmlXPathDebugObjCounterUsers = 0;
1765 xmlXPathDebugObjCounterXSLTTree = 0;
1766 xmlXPathDebugObjCounterAll = 0;
1767
1768 xmlXPathDebugObjTotalUndefined = 0;
1769 xmlXPathDebugObjTotalNodeset = 0;
1770 xmlXPathDebugObjTotalBool = 0;
1771 xmlXPathDebugObjTotalNumber = 0;
1772 xmlXPathDebugObjTotalString = 0;
1773 xmlXPathDebugObjTotalPoint = 0;
1774 xmlXPathDebugObjTotalRange = 0;
1775 xmlXPathDebugObjTotalLocset = 0;
1776 xmlXPathDebugObjTotalUsers = 0;
1777 xmlXPathDebugObjTotalXSLTTree = 0;
1778 xmlXPathDebugObjTotalAll = 0;
1779
1780 xmlXPathDebugObjMaxUndefined = 0;
1781 xmlXPathDebugObjMaxNodeset = 0;
1782 xmlXPathDebugObjMaxBool = 0;
1783 xmlXPathDebugObjMaxNumber = 0;
1784 xmlXPathDebugObjMaxString = 0;
1785 xmlXPathDebugObjMaxPoint = 0;
1786 xmlXPathDebugObjMaxRange = 0;
1787 xmlXPathDebugObjMaxLocset = 0;
1788 xmlXPathDebugObjMaxUsers = 0;
1789 xmlXPathDebugObjMaxXSLTTree = 0;
1790 xmlXPathDebugObjMaxAll = 0;
1791
1792 }
1793
1794 static void
1795 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1796 xmlXPathObjectType objType)
1797 {
1798 int isCached = 0;
1799
1800 if (ctxt != NULL) {
1801 if (ctxt->cache != NULL) {
1802 xmlXPathContextCachePtr cache =
1803 (xmlXPathContextCachePtr) ctxt->cache;
1804
1805 isCached = 1;
1806
1807 cache->dbgReusedAll++;
1808 switch (objType) {
1809 case XPATH_UNDEFINED:
1810 cache->dbgReusedUndefined++;
1811 break;
1812 case XPATH_NODESET:
1813 cache->dbgReusedNodeset++;
1814 break;
1815 case XPATH_BOOLEAN:
1816 cache->dbgReusedBool++;
1817 break;
1818 case XPATH_NUMBER:
1819 cache->dbgReusedNumber++;
1820 break;
1821 case XPATH_STRING:
1822 cache->dbgReusedString++;
1823 break;
1824 case XPATH_POINT:
1825 cache->dbgReusedPoint++;
1826 break;
1827 case XPATH_RANGE:
1828 cache->dbgReusedRange++;
1829 break;
1830 case XPATH_LOCATIONSET:
1831 cache->dbgReusedLocset++;
1832 break;
1833 case XPATH_USERS:
1834 cache->dbgReusedUsers++;
1835 break;
1836 case XPATH_XSLT_TREE:
1837 cache->dbgReusedXSLTTree++;
1838 break;
1839 default:
1840 break;
1841 }
1842 }
1843 }
1844
1845 switch (objType) {
1846 case XPATH_UNDEFINED:
1847 if (! isCached)
1848 xmlXPathDebugObjTotalUndefined++;
1849 xmlXPathDebugObjCounterUndefined++;
1850 if (xmlXPathDebugObjCounterUndefined >
1851 xmlXPathDebugObjMaxUndefined)
1852 xmlXPathDebugObjMaxUndefined =
1853 xmlXPathDebugObjCounterUndefined;
1854 break;
1855 case XPATH_NODESET:
1856 if (! isCached)
1857 xmlXPathDebugObjTotalNodeset++;
1858 xmlXPathDebugObjCounterNodeset++;
1859 if (xmlXPathDebugObjCounterNodeset >
1860 xmlXPathDebugObjMaxNodeset)
1861 xmlXPathDebugObjMaxNodeset =
1862 xmlXPathDebugObjCounterNodeset;
1863 break;
1864 case XPATH_BOOLEAN:
1865 if (! isCached)
1866 xmlXPathDebugObjTotalBool++;
1867 xmlXPathDebugObjCounterBool++;
1868 if (xmlXPathDebugObjCounterBool >
1869 xmlXPathDebugObjMaxBool)
1870 xmlXPathDebugObjMaxBool =
1871 xmlXPathDebugObjCounterBool;
1872 break;
1873 case XPATH_NUMBER:
1874 if (! isCached)
1875 xmlXPathDebugObjTotalNumber++;
1876 xmlXPathDebugObjCounterNumber++;
1877 if (xmlXPathDebugObjCounterNumber >
1878 xmlXPathDebugObjMaxNumber)
1879 xmlXPathDebugObjMaxNumber =
1880 xmlXPathDebugObjCounterNumber;
1881 break;
1882 case XPATH_STRING:
1883 if (! isCached)
1884 xmlXPathDebugObjTotalString++;
1885 xmlXPathDebugObjCounterString++;
1886 if (xmlXPathDebugObjCounterString >
1887 xmlXPathDebugObjMaxString)
1888 xmlXPathDebugObjMaxString =
1889 xmlXPathDebugObjCounterString;
1890 break;
1891 case XPATH_POINT:
1892 if (! isCached)
1893 xmlXPathDebugObjTotalPoint++;
1894 xmlXPathDebugObjCounterPoint++;
1895 if (xmlXPathDebugObjCounterPoint >
1896 xmlXPathDebugObjMaxPoint)
1897 xmlXPathDebugObjMaxPoint =
1898 xmlXPathDebugObjCounterPoint;
1899 break;
1900 case XPATH_RANGE:
1901 if (! isCached)
1902 xmlXPathDebugObjTotalRange++;
1903 xmlXPathDebugObjCounterRange++;
1904 if (xmlXPathDebugObjCounterRange >
1905 xmlXPathDebugObjMaxRange)
1906 xmlXPathDebugObjMaxRange =
1907 xmlXPathDebugObjCounterRange;
1908 break;
1909 case XPATH_LOCATIONSET:
1910 if (! isCached)
1911 xmlXPathDebugObjTotalLocset++;
1912 xmlXPathDebugObjCounterLocset++;
1913 if (xmlXPathDebugObjCounterLocset >
1914 xmlXPathDebugObjMaxLocset)
1915 xmlXPathDebugObjMaxLocset =
1916 xmlXPathDebugObjCounterLocset;
1917 break;
1918 case XPATH_USERS:
1919 if (! isCached)
1920 xmlXPathDebugObjTotalUsers++;
1921 xmlXPathDebugObjCounterUsers++;
1922 if (xmlXPathDebugObjCounterUsers >
1923 xmlXPathDebugObjMaxUsers)
1924 xmlXPathDebugObjMaxUsers =
1925 xmlXPathDebugObjCounterUsers;
1926 break;
1927 case XPATH_XSLT_TREE:
1928 if (! isCached)
1929 xmlXPathDebugObjTotalXSLTTree++;
1930 xmlXPathDebugObjCounterXSLTTree++;
1931 if (xmlXPathDebugObjCounterXSLTTree >
1932 xmlXPathDebugObjMaxXSLTTree)
1933 xmlXPathDebugObjMaxXSLTTree =
1934 xmlXPathDebugObjCounterXSLTTree;
1935 break;
1936 default:
1937 break;
1938 }
1939 if (! isCached)
1940 xmlXPathDebugObjTotalAll++;
1941 xmlXPathDebugObjCounterAll++;
1942 if (xmlXPathDebugObjCounterAll >
1943 xmlXPathDebugObjMaxAll)
1944 xmlXPathDebugObjMaxAll =
1945 xmlXPathDebugObjCounterAll;
1946 }
1947
1948 static void
1949 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1950 xmlXPathObjectType objType)
1951 {
1952 int isCached = 0;
1953
1954 if (ctxt != NULL) {
1955 if (ctxt->cache != NULL) {
1956 xmlXPathContextCachePtr cache =
1957 (xmlXPathContextCachePtr) ctxt->cache;
1958
1959 isCached = 1;
1960
1961 cache->dbgCachedAll++;
1962 switch (objType) {
1963 case XPATH_UNDEFINED:
1964 cache->dbgCachedUndefined++;
1965 break;
1966 case XPATH_NODESET:
1967 cache->dbgCachedNodeset++;
1968 break;
1969 case XPATH_BOOLEAN:
1970 cache->dbgCachedBool++;
1971 break;
1972 case XPATH_NUMBER:
1973 cache->dbgCachedNumber++;
1974 break;
1975 case XPATH_STRING:
1976 cache->dbgCachedString++;
1977 break;
1978 case XPATH_POINT:
1979 cache->dbgCachedPoint++;
1980 break;
1981 case XPATH_RANGE:
1982 cache->dbgCachedRange++;
1983 break;
1984 case XPATH_LOCATIONSET:
1985 cache->dbgCachedLocset++;
1986 break;
1987 case XPATH_USERS:
1988 cache->dbgCachedUsers++;
1989 break;
1990 case XPATH_XSLT_TREE:
1991 cache->dbgCachedXSLTTree++;
1992 break;
1993 default:
1994 break;
1995 }
1996
1997 }
1998 }
1999 switch (objType) {
2000 case XPATH_UNDEFINED:
2001 xmlXPathDebugObjCounterUndefined--;
2002 break;
2003 case XPATH_NODESET:
2004 xmlXPathDebugObjCounterNodeset--;
2005 break;
2006 case XPATH_BOOLEAN:
2007 xmlXPathDebugObjCounterBool--;
2008 break;
2009 case XPATH_NUMBER:
2010 xmlXPathDebugObjCounterNumber--;
2011 break;
2012 case XPATH_STRING:
2013 xmlXPathDebugObjCounterString--;
2014 break;
2015 case XPATH_POINT:
2016 xmlXPathDebugObjCounterPoint--;
2017 break;
2018 case XPATH_RANGE:
2019 xmlXPathDebugObjCounterRange--;
2020 break;
2021 case XPATH_LOCATIONSET:
2022 xmlXPathDebugObjCounterLocset--;
2023 break;
2024 case XPATH_USERS:
2025 xmlXPathDebugObjCounterUsers--;
2026 break;
2027 case XPATH_XSLT_TREE:
2028 xmlXPathDebugObjCounterXSLTTree--;
2029 break;
2030 default:
2031 break;
2032 }
2033 xmlXPathDebugObjCounterAll--;
2034 }
2035
2036 /* REVISIT TODO: Make this static when committing */
2037 static void
2038 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2039 {
2040 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2041 reqXSLTTree, reqUndefined;
2042 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2043 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2044 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2045 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2046 int leftObjs = xmlXPathDebugObjCounterAll;
2047
2048 reqAll = xmlXPathDebugObjTotalAll;
2049 reqNodeset = xmlXPathDebugObjTotalNodeset;
2050 reqString = xmlXPathDebugObjTotalString;
2051 reqBool = xmlXPathDebugObjTotalBool;
2052 reqNumber = xmlXPathDebugObjTotalNumber;
2053 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2054 reqUndefined = xmlXPathDebugObjTotalUndefined;
2055
2056 printf("# XPath object usage:\n");
2057
2058 if (ctxt != NULL) {
2059 if (ctxt->cache != NULL) {
2060 xmlXPathContextCachePtr cache =
2061 (xmlXPathContextCachePtr) ctxt->cache;
2062
2063 reAll = cache->dbgReusedAll;
2064 reqAll += reAll;
2065 reNodeset = cache->dbgReusedNodeset;
2066 reqNodeset += reNodeset;
2067 reString = cache->dbgReusedString;
2068 reqString += reString;
2069 reBool = cache->dbgReusedBool;
2070 reqBool += reBool;
2071 reNumber = cache->dbgReusedNumber;
2072 reqNumber += reNumber;
2073 reXSLTTree = cache->dbgReusedXSLTTree;
2074 reqXSLTTree += reXSLTTree;
2075 reUndefined = cache->dbgReusedUndefined;
2076 reqUndefined += reUndefined;
2077
2078 caAll = cache->dbgCachedAll;
2079 caBool = cache->dbgCachedBool;
2080 caNodeset = cache->dbgCachedNodeset;
2081 caString = cache->dbgCachedString;
2082 caNumber = cache->dbgCachedNumber;
2083 caXSLTTree = cache->dbgCachedXSLTTree;
2084 caUndefined = cache->dbgCachedUndefined;
2085
2086 if (cache->nodesetObjs)
2087 leftObjs -= cache->nodesetObjs->number;
2088 if (cache->stringObjs)
2089 leftObjs -= cache->stringObjs->number;
2090 if (cache->booleanObjs)
2091 leftObjs -= cache->booleanObjs->number;
2092 if (cache->numberObjs)
2093 leftObjs -= cache->numberObjs->number;
2094 if (cache->miscObjs)
2095 leftObjs -= cache->miscObjs->number;
2096 }
2097 }
2098
2099 printf("# all\n");
2100 printf("# total : %d\n", reqAll);
2101 printf("# left : %d\n", leftObjs);
2102 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2103 printf("# reused : %d\n", reAll);
2104 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2105
2106 printf("# node-sets\n");
2107 printf("# total : %d\n", reqNodeset);
2108 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2109 printf("# reused : %d\n", reNodeset);
2110 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2111
2112 printf("# strings\n");
2113 printf("# total : %d\n", reqString);
2114 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2115 printf("# reused : %d\n", reString);
2116 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2117
2118 printf("# booleans\n");
2119 printf("# total : %d\n", reqBool);
2120 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2121 printf("# reused : %d\n", reBool);
2122 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2123
2124 printf("# numbers\n");
2125 printf("# total : %d\n", reqNumber);
2126 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2127 printf("# reused : %d\n", reNumber);
2128 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2129
2130 printf("# XSLT result tree fragments\n");
2131 printf("# total : %d\n", reqXSLTTree);
2132 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2133 printf("# reused : %d\n", reXSLTTree);
2134 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2135
2136 printf("# undefined\n");
2137 printf("# total : %d\n", reqUndefined);
2138 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2139 printf("# reused : %d\n", reUndefined);
2140 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2141
2142 }
2143
2144 #endif /* XP_DEBUG_OBJ_USAGE */
2145
2146 #endif /* LIBXML_DEBUG_ENABLED */
2147
2148 /************************************************************************
2149 * *
2150 * XPath object caching *
2151 * *
2152 ************************************************************************/
2153
2154 /**
2155 * xmlXPathNewCache:
2156 *
2157 * Create a new object cache
2158 *
2159 * Returns the xmlXPathCache just allocated.
2160 */
2161 static xmlXPathContextCachePtr
2162 xmlXPathNewCache(void)
2163 {
2164 xmlXPathContextCachePtr ret;
2165
2166 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2167 if (ret == NULL) {
2168 xmlXPathErrMemory(NULL, "creating object cache\n");
2169 return(NULL);
2170 }
2171 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2172 ret->maxNodeset = 100;
2173 ret->maxString = 100;
2174 ret->maxBoolean = 100;
2175 ret->maxNumber = 100;
2176 ret->maxMisc = 100;
2177 return(ret);
2178 }
2179
2180 static void
2181 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2182 {
2183 int i;
2184 xmlXPathObjectPtr obj;
2185
2186 if (list == NULL)
2187 return;
2188
2189 for (i = 0; i < list->number; i++) {
2190 obj = list->items[i];
2191 /*
2192 * Note that it is already assured that we don't need to
2193 * look out for namespace nodes in the node-set.
2194 */
2195 if (obj->nodesetval != NULL) {
2196 if (obj->nodesetval->nodeTab != NULL)
2197 xmlFree(obj->nodesetval->nodeTab);
2198 xmlFree(obj->nodesetval);
2199 }
2200 xmlFree(obj);
2201 #ifdef XP_DEBUG_OBJ_USAGE
2202 xmlXPathDebugObjCounterAll--;
2203 #endif
2204 }
2205 xmlPointerListFree(list);
2206 }
2207
2208 static void
2209 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2210 {
2211 if (cache == NULL)
2212 return;
2213 if (cache->nodesetObjs)
2214 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2215 if (cache->stringObjs)
2216 xmlXPathCacheFreeObjectList(cache->stringObjs);
2217 if (cache->booleanObjs)
2218 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2219 if (cache->numberObjs)
2220 xmlXPathCacheFreeObjectList(cache->numberObjs);
2221 if (cache->miscObjs)
2222 xmlXPathCacheFreeObjectList(cache->miscObjs);
2223 xmlFree(cache);
2224 }
2225
2226 /**
2227 * xmlXPathContextSetCache:
2228 *
2229 * @ctxt: the XPath context
2230 * @active: enables/disables (creates/frees) the cache
2231 * @value: a value with semantics dependant on @options
2232 * @options: options (currently only the value 0 is used)
2233 *
2234 * Creates/frees an object cache on the XPath context.
2235 * If activates XPath objects (xmlXPathObject) will be cached internally
2236 * to be reused.
2237 * @options:
2238 * 0: This will set the XPath object caching:
2239 * @value:
2240 * This will set the maximum number of XPath objects
2241 * to be cached per slot
2242 * There are 5 slots for: node-set, string, number, boolean, and
2243 * misc objects. Use <0 for the default number (100).
2244 * Other values for @options have currently no effect.
2245 *
2246 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2247 */
2248 int
2249 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2250 int active,
2251 int value,
2252 int options)
2253 {
2254 if (ctxt == NULL)
2255 return(-1);
2256 if (active) {
2257 xmlXPathContextCachePtr cache;
2258
2259 if (ctxt->cache == NULL) {
2260 ctxt->cache = xmlXPathNewCache();
2261 if (ctxt->cache == NULL)
2262 return(-1);
2263 }
2264 cache = (xmlXPathContextCachePtr) ctxt->cache;
2265 if (options == 0) {
2266 if (value < 0)
2267 value = 100;
2268 cache->maxNodeset = value;
2269 cache->maxString = value;
2270 cache->maxNumber = value;
2271 cache->maxBoolean = value;
2272 cache->maxMisc = value;
2273 }
2274 } else if (ctxt->cache != NULL) {
2275 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2276 ctxt->cache = NULL;
2277 }
2278 return(0);
2279 }
2280
2281 /**
2282 * xmlXPathCacheWrapNodeSet:
2283 * @ctxt: the XPath context
2284 * @val: the NodePtr value
2285 *
2286 * This is the cached version of xmlXPathWrapNodeSet().
2287 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2288 *
2289 * Returns the created or reused object.
2290 */
2291 static xmlXPathObjectPtr
2292 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2293 {
2294 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2295 xmlXPathContextCachePtr cache =
2296 (xmlXPathContextCachePtr) ctxt->cache;
2297
2298 if ((cache->miscObjs != NULL) &&
2299 (cache->miscObjs->number != 0))
2300 {
2301 xmlXPathObjectPtr ret;
2302
2303 ret = (xmlXPathObjectPtr)
2304 cache->miscObjs->items[--cache->miscObjs->number];
2305 ret->type = XPATH_NODESET;
2306 ret->nodesetval = val;
2307 #ifdef XP_DEBUG_OBJ_USAGE
2308 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2309 #endif
2310 return(ret);
2311 }
2312 }
2313
2314 return(xmlXPathWrapNodeSet(val));
2315
2316 }
2317
2318 /**
2319 * xmlXPathCacheWrapString:
2320 * @ctxt: the XPath context
2321 * @val: the xmlChar * value
2322 *
2323 * This is the cached version of xmlXPathWrapString().
2324 * Wraps the @val string into an XPath object.
2325 *
2326 * Returns the created or reused object.
2327 */
2328 static xmlXPathObjectPtr
2329 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2330 {
2331 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2332 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2333
2334 if ((cache->stringObjs != NULL) &&
2335 (cache->stringObjs->number != 0))
2336 {
2337
2338 xmlXPathObjectPtr ret;
2339
2340 ret = (xmlXPathObjectPtr)
2341 cache->stringObjs->items[--cache->stringObjs->number];
2342 ret->type = XPATH_STRING;
2343 ret->stringval = val;
2344 #ifdef XP_DEBUG_OBJ_USAGE
2345 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2346 #endif
2347 return(ret);
2348 } else if ((cache->miscObjs != NULL) &&
2349 (cache->miscObjs->number != 0))
2350 {
2351 xmlXPathObjectPtr ret;
2352 /*
2353 * Fallback to misc-cache.
2354 */
2355 ret = (xmlXPathObjectPtr)
2356 cache->miscObjs->items[--cache->miscObjs->number];
2357
2358 ret->type = XPATH_STRING;
2359 ret->stringval = val;
2360 #ifdef XP_DEBUG_OBJ_USAGE
2361 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2362 #endif
2363 return(ret);
2364 }
2365 }
2366 return(xmlXPathWrapString(val));
2367 }
2368
2369 /**
2370 * xmlXPathCacheNewNodeSet:
2371 * @ctxt: the XPath context
2372 * @val: the NodePtr value
2373 *
2374 * This is the cached version of xmlXPathNewNodeSet().
2375 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2376 * it with the single Node @val
2377 *
2378 * Returns the created or reused object.
2379 */
2380 static xmlXPathObjectPtr
2381 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2382 {
2383 if ((ctxt != NULL) && (ctxt->cache)) {
2384 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2385
2386 if ((cache->nodesetObjs != NULL) &&
2387 (cache->nodesetObjs->number != 0))
2388 {
2389 xmlXPathObjectPtr ret;
2390 /*
2391 * Use the nodset-cache.
2392 */
2393 ret = (xmlXPathObjectPtr)
2394 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2395 ret->type = XPATH_NODESET;
2396 ret->boolval = 0;
2397 if (val) {
2398 if ((ret->nodesetval->nodeMax == 0) ||
2399 (val->type == XML_NAMESPACE_DECL))
2400 {
2401 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2402 } else {
2403 ret->nodesetval->nodeTab[0] = val;
2404 ret->nodesetval->nodeNr = 1;
2405 }
2406 }
2407 #ifdef XP_DEBUG_OBJ_USAGE
2408 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2409 #endif
2410 return(ret);
2411 } else if ((cache->miscObjs != NULL) &&
2412 (cache->miscObjs->number != 0))
2413 {
2414 xmlXPathObjectPtr ret;
2415 /*
2416 * Fallback to misc-cache.
2417 */
2418
2419 ret = (xmlXPathObjectPtr)
2420 cache->miscObjs->items[--cache->miscObjs->number];
2421
2422 ret->type = XPATH_NODESET;
2423 ret->boolval = 0;
2424 ret->nodesetval = xmlXPathNodeSetCreate(val);
2425 if (ret->nodesetval == NULL) {
2426 ctxt->lastError.domain = XML_FROM_XPATH;
2427 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2428 return(NULL);
2429 }
2430 #ifdef XP_DEBUG_OBJ_USAGE
2431 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2432 #endif
2433 return(ret);
2434 }
2435 }
2436 return(xmlXPathNewNodeSet(val));
2437 }
2438
2439 /**
2440 * xmlXPathCacheNewCString:
2441 * @ctxt: the XPath context
2442 * @val: the char * value
2443 *
2444 * This is the cached version of xmlXPathNewCString().
2445 * Acquire an xmlXPathObjectPtr of type string and of value @val
2446 *
2447 * Returns the created or reused object.
2448 */
2449 static xmlXPathObjectPtr
2450 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2451 {
2452 if ((ctxt != NULL) && (ctxt->cache)) {
2453 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2454
2455 if ((cache->stringObjs != NULL) &&
2456 (cache->stringObjs->number != 0))
2457 {
2458 xmlXPathObjectPtr ret;
2459
2460 ret = (xmlXPathObjectPtr)
2461 cache->stringObjs->items[--cache->stringObjs->number];
2462
2463 ret->type = XPATH_STRING;
2464 ret->stringval = xmlStrdup(BAD_CAST val);
2465 #ifdef XP_DEBUG_OBJ_USAGE
2466 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2467 #endif
2468 return(ret);
2469 } else if ((cache->miscObjs != NULL) &&
2470 (cache->miscObjs->number != 0))
2471 {
2472 xmlXPathObjectPtr ret;
2473
2474 ret = (xmlXPathObjectPtr)
2475 cache->miscObjs->items[--cache->miscObjs->number];
2476
2477 ret->type = XPATH_STRING;
2478 ret->stringval = xmlStrdup(BAD_CAST val);
2479 #ifdef XP_DEBUG_OBJ_USAGE
2480 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2481 #endif
2482 return(ret);
2483 }
2484 }
2485 return(xmlXPathNewCString(val));
2486 }
2487
2488 /**
2489 * xmlXPathCacheNewString:
2490 * @ctxt: the XPath context
2491 * @val: the xmlChar * value
2492 *
2493 * This is the cached version of xmlXPathNewString().
2494 * Acquire an xmlXPathObjectPtr of type string and of value @val
2495 *
2496 * Returns the created or reused object.
2497 */
2498 static xmlXPathObjectPtr
2499 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2500 {
2501 if ((ctxt != NULL) && (ctxt->cache)) {
2502 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2503
2504 if ((cache->stringObjs != NULL) &&
2505 (cache->stringObjs->number != 0))
2506 {
2507 xmlXPathObjectPtr ret;
2508
2509 ret = (xmlXPathObjectPtr)
2510 cache->stringObjs->items[--cache->stringObjs->number];
2511 ret->type = XPATH_STRING;
2512 if (val != NULL)
2513 ret->stringval = xmlStrdup(val);
2514 else
2515 ret->stringval = xmlStrdup((const xmlChar *)"");
2516 #ifdef XP_DEBUG_OBJ_USAGE
2517 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2518 #endif
2519 return(ret);
2520 } else if ((cache->miscObjs != NULL) &&
2521 (cache->miscObjs->number != 0))
2522 {
2523 xmlXPathObjectPtr ret;
2524
2525 ret = (xmlXPathObjectPtr)
2526 cache->miscObjs->items[--cache->miscObjs->number];
2527
2528 ret->type = XPATH_STRING;
2529 if (val != NULL)
2530 ret->stringval = xmlStrdup(val);
2531 else
2532 ret->stringval = xmlStrdup((const xmlChar *)"");
2533 #ifdef XP_DEBUG_OBJ_USAGE
2534 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2535 #endif
2536 return(ret);
2537 }
2538 }
2539 return(xmlXPathNewString(val));
2540 }
2541
2542 /**
2543 * xmlXPathCacheNewBoolean:
2544 * @ctxt: the XPath context
2545 * @val: the boolean value
2546 *
2547 * This is the cached version of xmlXPathNewBoolean().
2548 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2549 *
2550 * Returns the created or reused object.
2551 */
2552 static xmlXPathObjectPtr
2553 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2554 {
2555 if ((ctxt != NULL) && (ctxt->cache)) {
2556 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2557
2558 if ((cache->booleanObjs != NULL) &&
2559 (cache->booleanObjs->number != 0))
2560 {
2561 xmlXPathObjectPtr ret;
2562
2563 ret = (xmlXPathObjectPtr)
2564 cache->booleanObjs->items[--cache->booleanObjs->number];
2565 ret->type = XPATH_BOOLEAN;
2566 ret->boolval = (val != 0);
2567 #ifdef XP_DEBUG_OBJ_USAGE
2568 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2569 #endif
2570 return(ret);
2571 } else if ((cache->miscObjs != NULL) &&
2572 (cache->miscObjs->number != 0))
2573 {
2574 xmlXPathObjectPtr ret;
2575
2576 ret = (xmlXPathObjectPtr)
2577 cache->miscObjs->items[--cache->miscObjs->number];
2578
2579 ret->type = XPATH_BOOLEAN;
2580 ret->boolval = (val != 0);
2581 #ifdef XP_DEBUG_OBJ_USAGE
2582 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2583 #endif
2584 return(ret);
2585 }
2586 }
2587 return(xmlXPathNewBoolean(val));
2588 }
2589
2590 /**
2591 * xmlXPathCacheNewFloat:
2592 * @ctxt: the XPath context
2593 * @val: the double value
2594 *
2595 * This is the cached version of xmlXPathNewFloat().
2596 * Acquires an xmlXPathObjectPtr of type double and of value @val
2597 *
2598 * Returns the created or reused object.
2599 */
2600 static xmlXPathObjectPtr
2601 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2602 {
2603 if ((ctxt != NULL) && (ctxt->cache)) {
2604 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2605
2606 if ((cache->numberObjs != NULL) &&
2607 (cache->numberObjs->number != 0))
2608 {
2609 xmlXPathObjectPtr ret;
2610
2611 ret = (xmlXPathObjectPtr)
2612 cache->numberObjs->items[--cache->numberObjs->number];
2613 ret->type = XPATH_NUMBER;
2614 ret->floatval = val;
2615 #ifdef XP_DEBUG_OBJ_USAGE
2616 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2617 #endif
2618 return(ret);
2619 } else if ((cache->miscObjs != NULL) &&
2620 (cache->miscObjs->number != 0))
2621 {
2622 xmlXPathObjectPtr ret;
2623
2624 ret = (xmlXPathObjectPtr)
2625 cache->miscObjs->items[--cache->miscObjs->number];
2626
2627 ret->type = XPATH_NUMBER;
2628 ret->floatval = val;
2629 #ifdef XP_DEBUG_OBJ_USAGE
2630 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2631 #endif
2632 return(ret);
2633 }
2634 }
2635 return(xmlXPathNewFloat(val));
2636 }
2637
2638 /**
2639 * xmlXPathCacheConvertString:
2640 * @ctxt: the XPath context
2641 * @val: an XPath object
2642 *
2643 * This is the cached version of xmlXPathConvertString().
2644 * Converts an existing object to its string() equivalent
2645 *
2646 * Returns a created or reused object, the old one is freed (cached)
2647 * (or the operation is done directly on @val)
2648 */
2649
2650 static xmlXPathObjectPtr
2651 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2652 xmlChar *res = NULL;
2653
2654 if (val == NULL)
2655 return(xmlXPathCacheNewCString(ctxt, ""));
2656
2657 switch (val->type) {
2658 case XPATH_UNDEFINED:
2659 #ifdef DEBUG_EXPR
2660 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2661 #endif
2662 break;
2663 case XPATH_NODESET:
2664 case XPATH_XSLT_TREE:
2665 res = xmlXPathCastNodeSetToString(val->nodesetval);
2666 break;
2667 case XPATH_STRING:
2668 return(val);
2669 case XPATH_BOOLEAN:
2670 res = xmlXPathCastBooleanToString(val->boolval);
2671 break;
2672 case XPATH_NUMBER:
2673 res = xmlXPathCastNumberToString(val->floatval);
2674 break;
2675 case XPATH_USERS:
2676 case XPATH_POINT:
2677 case XPATH_RANGE:
2678 case XPATH_LOCATIONSET:
2679 TODO;
2680 break;
2681 }
2682 xmlXPathReleaseObject(ctxt, val);
2683 if (res == NULL)
2684 return(xmlXPathCacheNewCString(ctxt, ""));
2685 return(xmlXPathCacheWrapString(ctxt, res));
2686 }
2687
2688 /**
2689 * xmlXPathCacheObjectCopy:
2690 * @ctxt: the XPath context
2691 * @val: the original object
2692 *
2693 * This is the cached version of xmlXPathObjectCopy().
2694 * Acquire a copy of a given object
2695 *
2696 * Returns a created or reused created object.
2697 */
2698 static xmlXPathObjectPtr
2699 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2700 {
2701 if (val == NULL)
2702 return(NULL);
2703
2704 if (XP_HAS_CACHE(ctxt)) {
2705 switch (val->type) {
2706 case XPATH_NODESET:
2707 return(xmlXPathCacheWrapNodeSet(ctxt,
2708 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2709 case XPATH_STRING:
2710 return(xmlXPathCacheNewString(ctxt, val->stringval));
2711 case XPATH_BOOLEAN:
2712 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2713 case XPATH_NUMBER:
2714 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2715 default:
2716 break;
2717 }
2718 }
2719 return(xmlXPathObjectCopy(val));
2720 }
2721
2722 /**
2723 * xmlXPathCacheConvertBoolean:
2724 * @ctxt: the XPath context
2725 * @val: an XPath object
2726 *
2727 * This is the cached version of xmlXPathConvertBoolean().
2728 * Converts an existing object to its boolean() equivalent
2729 *
2730 * Returns a created or reused object, the old one is freed (or the operation
2731 * is done directly on @val)
2732 */
2733 static xmlXPathObjectPtr
2734 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2735 xmlXPathObjectPtr ret;
2736
2737 if (val == NULL)
2738 return(xmlXPathCacheNewBoolean(ctxt, 0));
2739 if (val->type == XPATH_BOOLEAN)
2740 return(val);
2741 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2742 xmlXPathReleaseObject(ctxt, val);
2743 return(ret);
2744 }
2745
2746 /**
2747 * xmlXPathCacheConvertNumber:
2748 * @ctxt: the XPath context
2749 * @val: an XPath object
2750 *
2751 * This is the cached version of xmlXPathConvertNumber().
2752 * Converts an existing object to its number() equivalent
2753 *
2754 * Returns a created or reused object, the old one is freed (or the operation
2755 * is done directly on @val)
2756 */
2757 static xmlXPathObjectPtr
2758 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2759 xmlXPathObjectPtr ret;
2760
2761 if (val == NULL)
2762 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2763 if (val->type == XPATH_NUMBER)
2764 return(val);
2765 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2766 xmlXPathReleaseObject(ctxt, val);
2767 return(ret);
2768 }
2769
2770 /************************************************************************
2771 * *
2772 * Parser stacks related functions and macros *
2773 * *
2774 ************************************************************************/
2775
2776 /**
2777 * xmlXPathSetFrame:
2778 * @ctxt: an XPath parser context
2779 *
2780 * Set the callee evaluation frame
2781 *
2782 * Returns the previous frame value to be restored once done
2783 */
2784 static int
2785 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2786 int ret;
2787
2788 if (ctxt == NULL)
2789 return(0);
2790 ret = ctxt->valueFrame;
2791 ctxt->valueFrame = ctxt->valueNr;
2792 return(ret);
2793 }
2794
2795 /**
2796 * xmlXPathPopFrame:
2797 * @ctxt: an XPath parser context
2798 * @frame: the previous frame value
2799 *
2800 * Remove the callee evaluation frame
2801 */
2802 static void
2803 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2804 if (ctxt == NULL)
2805 return;
2806 if (ctxt->valueNr < ctxt->valueFrame) {
2807 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2808 }
2809 ctxt->valueFrame = frame;
2810 }
2811
2812 /**
2813 * valuePop:
2814 * @ctxt: an XPath evaluation context
2815 *
2816 * Pops the top XPath object from the value stack
2817 *
2818 * Returns the XPath object just removed
2819 */
2820 xmlXPathObjectPtr
2821 valuePop(xmlXPathParserContextPtr ctxt)
2822 {
2823 xmlXPathObjectPtr ret;
2824
2825 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2826 return (NULL);
2827
2828 if (ctxt->valueNr <= ctxt->valueFrame) {
2829 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2830 return (NULL);
2831 }
2832
2833 ctxt->valueNr--;
2834 if (ctxt->valueNr > 0)
2835 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2836 else
2837 ctxt->value = NULL;
2838 ret = ctxt->valueTab[ctxt->valueNr];
2839 ctxt->valueTab[ctxt->valueNr] = NULL;
2840 return (ret);
2841 }
2842 /**
2843 * valuePush:
2844 * @ctxt: an XPath evaluation context
2845 * @value: the XPath object
2846 *
2847 * Pushes a new XPath object on top of the value stack
2848 *
2849 * returns the number of items on the value stack
2850 */
2851 int
2852 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2853 {
2854 if ((ctxt == NULL) || (value == NULL)) return(-1);
2855 if (ctxt->valueNr >= ctxt->valueMax) {
2856 xmlXPathObjectPtr *tmp;
2857
2858 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2859 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2860 ctxt->error = XPATH_MEMORY_ERROR;
2861 return (0);
2862 }
2863 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2864 2 * ctxt->valueMax *
2865 sizeof(ctxt->valueTab[0]));
2866 if (tmp == NULL) {
2867 xmlXPathErrMemory(NULL, "pushing value\n");
2868 ctxt->error = XPATH_MEMORY_ERROR;
2869 return (0);
2870 }
2871 ctxt->valueMax *= 2;
2872 ctxt->valueTab = tmp;
2873 }
2874 ctxt->valueTab[ctxt->valueNr] = value;
2875 ctxt->value = value;
2876 return (ctxt->valueNr++);
2877 }
2878
2879 /**
2880 * xmlXPathPopBoolean:
2881 * @ctxt: an XPath parser context
2882 *
2883 * Pops a boolean from the stack, handling conversion if needed.
2884 * Check error with #xmlXPathCheckError.
2885 *
2886 * Returns the boolean
2887 */
2888 int
2889 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2890 xmlXPathObjectPtr obj;
2891 int ret;
2892
2893 obj = valuePop(ctxt);
2894 if (obj == NULL) {
2895 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2896 return(0);
2897 }
2898 if (obj->type != XPATH_BOOLEAN)
2899 ret = xmlXPathCastToBoolean(obj);
2900 else
2901 ret = obj->boolval;
2902 xmlXPathReleaseObject(ctxt->context, obj);
2903 return(ret);
2904 }
2905
2906 /**
2907 * xmlXPathPopNumber:
2908 * @ctxt: an XPath parser context
2909 *
2910 * Pops a number from the stack, handling conversion if needed.
2911 * Check error with #xmlXPathCheckError.
2912 *
2913 * Returns the number
2914 */
2915 double
2916 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2917 xmlXPathObjectPtr obj;
2918 double ret;
2919
2920 obj = valuePop(ctxt);
2921 if (obj == NULL) {
2922 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2923 return(0);
2924 }
2925 if (obj->type != XPATH_NUMBER)
2926 ret = xmlXPathCastToNumber(obj);
2927 else
2928 ret = obj->floatval;
2929 xmlXPathReleaseObject(ctxt->context, obj);
2930 return(ret);
2931 }
2932
2933 /**
2934 * xmlXPathPopString:
2935 * @ctxt: an XPath parser context
2936 *
2937 * Pops a string from the stack, handling conversion if needed.
2938 * Check error with #xmlXPathCheckError.
2939 *
2940 * Returns the string
2941 */
2942 xmlChar *
2943 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2944 xmlXPathObjectPtr obj;
2945 xmlChar * ret;
2946
2947 obj = valuePop(ctxt);
2948 if (obj == NULL) {
2949 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2950 return(NULL);
2951 }
2952 ret = xmlXPathCastToString(obj); /* this does required strdup */
2953 /* TODO: needs refactoring somewhere else */
2954 if (obj->stringval == ret)
2955 obj->stringval = NULL;
2956 xmlXPathReleaseObject(ctxt->context, obj);
2957 return(ret);
2958 }
2959
2960 /**
2961 * xmlXPathPopNodeSet:
2962 * @ctxt: an XPath parser context
2963 *
2964 * Pops a node-set from the stack, handling conversion if needed.
2965 * Check error with #xmlXPathCheckError.
2966 *
2967 * Returns the node-set
2968 */
2969 xmlNodeSetPtr
2970 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2971 xmlXPathObjectPtr obj;
2972 xmlNodeSetPtr ret;
2973
2974 if (ctxt == NULL) return(NULL);
2975 if (ctxt->value == NULL) {
2976 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2977 return(NULL);
2978 }
2979 if (!xmlXPathStackIsNodeSet(ctxt)) {
2980 xmlXPathSetTypeError(ctxt);
2981 return(NULL);
2982 }
2983 obj = valuePop(ctxt);
2984 ret = obj->nodesetval;
2985 #if 0
2986 /* to fix memory leak of not clearing obj->user */
2987 if (obj->boolval && obj->user != NULL)
2988 xmlFreeNodeList((xmlNodePtr) obj->user);
2989 #endif
2990 obj->nodesetval = NULL;
2991 xmlXPathReleaseObject(ctxt->context, obj);
2992 return(ret);
2993 }
2994
2995 /**
2996 * xmlXPathPopExternal:
2997 * @ctxt: an XPath parser context
2998 *
2999 * Pops an external object from the stack, handling conversion if needed.
3000 * Check error with #xmlXPathCheckError.
3001 *
3002 * Returns the object
3003 */
3004 void *
3005 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3006 xmlXPathObjectPtr obj;
3007 void * ret;
3008
3009 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3010 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3011 return(NULL);
3012 }
3013 if (ctxt->value->type != XPATH_USERS) {
3014 xmlXPathSetTypeError(ctxt);
3015 return(NULL);
3016 }
3017 obj = valuePop(ctxt);
3018 ret = obj->user;
3019 obj->user = NULL;
3020 xmlXPathReleaseObject(ctxt->context, obj);
3021 return(ret);
3022 }
3023
3024 /*
3025 * Macros for accessing the content. Those should be used only by the parser,
3026 * and not exported.
3027 *
3028 * Dirty macros, i.e. one need to make assumption on the context to use them
3029 *
3030 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3031 * CUR returns the current xmlChar value, i.e. a 8 bit value
3032 * in ISO-Latin or UTF-8.
3033 * This should be used internally by the parser
3034 * only to compare to ASCII values otherwise it would break when
3035 * running with UTF-8 encoding.
3036 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3037 * to compare on ASCII based substring.
3038 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3039 * strings within the parser.
3040 * CURRENT Returns the current char value, with the full decoding of
3041 * UTF-8 if we are using this mode. It returns an int.
3042 * NEXT Skip to the next character, this does the proper decoding
3043 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3044 * It returns the pointer to the current xmlChar.
3045 */
3046
3047 #define CUR (*ctxt->cur)
3048 #define SKIP(val) ctxt->cur += (val)
3049 #define NXT(val) ctxt->cur[(val)]
3050 #define CUR_PTR ctxt->cur
3051 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3052
3053 #define COPY_BUF(l,b,i,v) \
3054 if (l == 1) b[i++] = (xmlChar) v; \
3055 else i += xmlCopyChar(l,&b[i],v)
3056
3057 #define NEXTL(l) ctxt->cur += l
3058
3059 #define SKIP_BLANKS \
3060 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3061
3062 #define CURRENT (*ctxt->cur)
3063 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3064
3065
3066 #ifndef DBL_DIG
3067 #define DBL_DIG 16
3068 #endif
3069 #ifndef DBL_EPSILON
3070 #define DBL_EPSILON 1E-9
3071 #endif
3072
3073 #define UPPER_DOUBLE 1E9
3074 #define LOWER_DOUBLE 1E-5
3075 #define LOWER_DOUBLE_EXP 5
3076
3077 #define INTEGER_DIGITS DBL_DIG
3078 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3079 #define EXPONENT_DIGITS (3 + 2)
3080
3081 /**
3082 * xmlXPathFormatNumber:
3083 * @number: number to format
3084 * @buffer: output buffer
3085 * @buffersize: size of output buffer
3086 *
3087 * Convert the number into a string representation.
3088 */
3089 static void
3090 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3091 {
3092 switch (xmlXPathIsInf(number)) {
3093 case 1:
3094 if (buffersize > (int)sizeof("Infinity"))
3095 snprintf(buffer, buffersize, "Infinity");
3096 break;
3097 case -1:
3098 if (buffersize > (int)sizeof("-Infinity"))
3099 snprintf(buffer, buffersize, "-Infinity");
3100 break;
3101 default:
3102 if (xmlXPathIsNaN(number)) {
3103 if (buffersize > (int)sizeof("NaN"))
3104 snprintf(buffer, buffersize, "NaN");
3105 } else if (number == 0) {
3106 /* Omit sign for negative zero. */
3107 snprintf(buffer, buffersize, "0");
3108 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3109 (number == (int) number)) {
3110 char work[30];
3111 char *ptr, *cur;
3112 int value = (int) number;
3113
3114 ptr = &buffer[0];
3115 if (value == 0) {
3116 *ptr++ = '0';
3117 } else {
3118 snprintf(work, 29, "%d", value);
3119 cur = &work[0];
3120 while ((*cur) && (ptr - buffer < buffersize)) {
3121 *ptr++ = *cur++;
3122 }
3123 }
3124 if (ptr - buffer < buffersize) {
3125 *ptr = 0;
3126 } else if (buffersize > 0) {
3127 ptr--;
3128 *ptr = 0;
3129 }
3130 } else {
3131 /*
3132 For the dimension of work,
3133 DBL_DIG is number of significant digits
3134 EXPONENT is only needed for "scientific notation"
3135 3 is sign, decimal point, and terminating zero
3136 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3137 Note that this dimension is slightly (a few characters)
3138 larger than actually necessary.
3139 */
3140 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3141 int integer_place, fraction_place;
3142 char *ptr;
3143 char *after_fraction;
3144 double absolute_value;
3145 int size;
3146
3147 absolute_value = fabs(number);
3148
3149 /*
3150 * First choose format - scientific or regular floating point.
3151 * In either case, result is in work, and after_fraction points
3152 * just past the fractional part.
3153 */
3154 if ( ((absolute_value > UPPER_DOUBLE) ||
3155 (absolute_value < LOWER_DOUBLE)) &&
3156 (absolute_value != 0.0) ) {
3157 /* Use scientific notation */
3158 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3159 fraction_place = DBL_DIG - 1;
3160 size = snprintf(work, sizeof(work),"%*.*e",
3161 integer_place, fraction_place, number);
3162 while ((size > 0) && (work[size] != 'e')) size--;
3163
3164 }
3165 else {
3166 /* Use regular notation */
3167 if (absolute_value > 0.0) {
3168 integer_place = (int)log10(absolute_value);
3169 if (integer_place > 0)
3170 fraction_place = DBL_DIG - integer_place - 1;
3171 else
3172 fraction_place = DBL_DIG - integer_place;
3173 } else {
3174 fraction_place = 1;
3175 }
3176 size = snprintf(work, sizeof(work), "%0.*f",
3177 fraction_place, number);
3178 }
3179
3180 /* Remove leading spaces sometimes inserted by snprintf */
3181 while (work[0] == ' ') {
3182 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3183 size--;
3184 }
3185
3186 /* Remove fractional trailing zeroes */
3187 after_fraction = work + size;
3188 ptr = after_fraction;
3189 while (*(--ptr) == '0')
3190 ;
3191 if (*ptr != '.')
3192 ptr++;
3193 while ((*ptr++ = *after_fraction++) != 0);
3194
3195 /* Finally copy result back to caller */
3196 size = strlen(work) + 1;
3197 if (size > buffersize) {
3198 work[buffersize - 1] = 0;
3199 size = buffersize;
3200 }
3201 memmove(buffer, work, size);
3202 }
3203 break;
3204 }
3205 }
3206
3207
3208 /************************************************************************
3209 * *
3210 * Routines to handle NodeSets *
3211 * *
3212 ************************************************************************/
3213
3214 /**
3215 * xmlXPathOrderDocElems:
3216 * @doc: an input document
3217 *
3218 * Call this routine to speed up XPath computation on static documents.
3219 * This stamps all the element nodes with the document order
3220 * Like for line information, the order is kept in the element->content
3221 * field, the value stored is actually - the node number (starting at -1)
3222 * to be able to differentiate from line numbers.
3223 *
3224 * Returns the number of elements found in the document or -1 in case
3225 * of error.
3226 */
3227 long
3228 xmlXPathOrderDocElems(xmlDocPtr doc) {
3229 ptrdiff_t count = 0;
3230 xmlNodePtr cur;
3231