ReactOS  0.4.15-dev-488-gc7a1924
xpath.c
Go to the documentation of this file.
1 /*
2  * xpath.c: XML Path Language implementation
3  * XPath is a language for addressing parts of an XML document,
4  * designed to be used by both XSLT and XPointer
5  *
6  * Reference: W3C Recommendation 16 November 1999
7  * http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  * http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16 
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21 
22 #define IN_LIBXML
23 #include "libxml.h"
24 
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28 
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 
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 
157 static int
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:
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:
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 available.
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 available.
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 algorithm from timsort.h
439  */
440 #ifdef WITH_TIM_SORT
441 #define SORT_NAME libxml_domnode
442 #define SORT_TYPE xmlNodePtr
443 
453 static
455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
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 INFINITY
481 #define INFINITY (DBL_MAX * DBL_MAX)
482 #endif
483 
484 #ifndef NAN
485 #define NAN (INFINITY / INFINITY)
486 #endif
487 
488 double xmlXPathNAN;
489 double xmlXPathPINF;
490 double xmlXPathNINF;
491 
497 void
498 xmlXPathInit(void) {
499  xmlXPathNAN = NAN;
500  xmlXPathPINF = INFINITY;
501  xmlXPathNINF = -INFINITY;
502 }
503 
510 int
511 xmlXPathIsNaN(double val) {
512 #ifdef isnan
513  return isnan(val);
514 #else
515  return !(val == val);
516 #endif
517 }
518 
525 int
526 xmlXPathIsInf(double val) {
527 #ifdef isinf
528  return isinf(val) ? (val > 0 ? 1 : -1) : 0;
529 #else
530  if (val >= INFINITY)
531  return 1;
532  if (val <= -INFINITY)
533  return -1;
534  return 0;
535 #endif
536 }
537 
538 #endif /* SCHEMAS or XPATH */
539 
540 #ifdef LIBXML_XPATH_ENABLED
541 
542 /*
543  * TODO: when compatibility allows remove all "fake node libxslt" strings
544  * the test should just be name[0] = ' '
545  */
546 #ifdef DEBUG_XPATH_EXPRESSION
547 #define DEBUG_STEP
548 #define DEBUG_EXPR
549 #define DEBUG_EVAL_COUNTS
550 #endif
551 
552 static xmlNs xmlXPathXMLNamespaceStruct = {
553  NULL,
556  BAD_CAST "xml",
557  NULL,
558  NULL
559 };
560 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
561 #ifndef LIBXML_THREAD_ENABLED
562 /*
563  * Optimizer is disabled only when threaded apps are detected while
564  * the library ain't compiled for thread safety.
565  */
566 static int xmlXPathDisableOptimizer = 0;
567 #endif
568 
569 /************************************************************************
570  * *
571  * Error handling routines *
572  * *
573  ************************************************************************/
574 
581 #define XP_ERRORNULL(X) \
582  { xmlXPathErr(ctxt, X); return(NULL); }
583 
584 /*
585  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
586  */
587 static const char *xmlXPathErrorMessages[] = {
588  "Ok\n",
589  "Number encoding\n",
590  "Unfinished literal\n",
591  "Start of literal\n",
592  "Expected $ for variable reference\n",
593  "Undefined variable\n",
594  "Invalid predicate\n",
595  "Invalid expression\n",
596  "Missing closing curly brace\n",
597  "Unregistered function\n",
598  "Invalid operand\n",
599  "Invalid type\n",
600  "Invalid number of arguments\n",
601  "Invalid context size\n",
602  "Invalid context position\n",
603  "Memory allocation error\n",
604  "Syntax error\n",
605  "Resource error\n",
606  "Sub resource error\n",
607  "Undefined namespace prefix\n",
608  "Encoding error\n",
609  "Char out of XML range\n",
610  "Invalid or incomplete context\n",
611  "Stack usage error\n",
612  "Forbidden variable\n",
613  "Operation limit exceeded\n",
614  "Recursion limit exceeded\n",
615  "?? Unknown error ??\n" /* Must be last in the list! */
616 };
617 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
618  sizeof(xmlXPathErrorMessages[0])) - 1)
619 
626 static void
627 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
628 {
629  if (ctxt != NULL) {
630  xmlResetError(&ctxt->lastError);
631  if (extra) {
632  xmlChar buf[200];
633 
634  xmlStrPrintf(buf, 200,
635  "Memory allocation failed : %s\n",
636  extra);
637  ctxt->lastError.message = (char *) xmlStrdup(buf);
638  } else {
639  ctxt->lastError.message = (char *)
640  xmlStrdup(BAD_CAST "Memory allocation failed\n");
641  }
642  ctxt->lastError.domain = XML_FROM_XPATH;
643  ctxt->lastError.code = XML_ERR_NO_MEMORY;
644  if (ctxt->error != NULL)
645  ctxt->error(ctxt->userData, &ctxt->lastError);
646  } else {
647  if (extra)
648  __xmlRaiseError(NULL, NULL, NULL,
651  extra, NULL, NULL, 0, 0,
652  "Memory allocation failed : %s\n", extra);
653  else
654  __xmlRaiseError(NULL, NULL, NULL,
657  NULL, NULL, NULL, 0, 0,
658  "Memory allocation failed\n");
659  }
660 }
661 
669 static void
670 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
671 {
672  if (ctxt == NULL)
673  xmlXPathErrMemory(NULL, extra);
674  else {
675  ctxt->error = XPATH_MEMORY_ERROR;
676  xmlXPathErrMemory(ctxt->context, extra);
677  }
678 }
679 
687 void
688 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
689 {
690  if ((error < 0) || (error > MAXERRNO))
691  error = MAXERRNO;
692  if (ctxt == NULL) {
693  __xmlRaiseError(NULL, NULL, NULL,
695  error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
696  XML_ERR_ERROR, NULL, 0,
697  NULL, NULL, NULL, 0, 0,
698  "%s", xmlXPathErrorMessages[error]);
699  return;
700  }
701  ctxt->error = error;
702  if (ctxt->context == NULL) {
703  __xmlRaiseError(NULL, NULL, NULL,
705  error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
706  XML_ERR_ERROR, NULL, 0,
707  (const char *) ctxt->base, NULL, NULL,
708  ctxt->cur - ctxt->base, 0,
709  "%s", xmlXPathErrorMessages[error]);
710  return;
711  }
712 
713  /* cleanup current last error */
714  xmlResetError(&ctxt->context->lastError);
715 
716  ctxt->context->lastError.domain = XML_FROM_XPATH;
717  ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
718  XPATH_EXPRESSION_OK;
719  ctxt->context->lastError.level = XML_ERR_ERROR;
720  ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
721  ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
722  ctxt->context->lastError.node = ctxt->context->debugNode;
723  if (ctxt->context->error != NULL) {
724  ctxt->context->error(ctxt->context->userData,
725  &ctxt->context->lastError);
726  } else {
727  __xmlRaiseError(NULL, NULL, NULL,
728  NULL, ctxt->context->debugNode, XML_FROM_XPATH,
729  error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
730  XML_ERR_ERROR, NULL, 0,
731  (const char *) ctxt->base, NULL, NULL,
732  ctxt->cur - ctxt->base, 0,
733  "%s", xmlXPathErrorMessages[error]);
734  }
735 
736 }
737 
747 void
748 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
749  int line ATTRIBUTE_UNUSED, int no) {
750  xmlXPathErr(ctxt, no);
751 }
752 
761 static int
762 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
763  xmlXPathContextPtr xpctxt = ctxt->context;
764 
765  if ((opCount > xpctxt->opLimit) ||
766  (xpctxt->opCount > xpctxt->opLimit - opCount)) {
767  xpctxt->opCount = xpctxt->opLimit;
768  xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
769  return(-1);
770  }
771 
772  xpctxt->opCount += opCount;
773  return(0);
774 }
775 
776 #define OP_LIMIT_EXCEEDED(ctxt, n) \
777  ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
778 
779 /************************************************************************
780  * *
781  * Utilities *
782  * *
783  ************************************************************************/
784 
790 typedef struct _xmlPointerList xmlPointerList;
791 typedef xmlPointerList *xmlPointerListPtr;
792 struct _xmlPointerList {
793  void **items;
794  int number;
795  int size;
796 };
797 /*
798 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
799 * and here, we should make the functions public.
800 */
801 static int
802 xmlPointerListAddSize(xmlPointerListPtr list,
803  void *item,
804  int initialSize)
805 {
806  if (list->items == NULL) {
807  if (initialSize <= 0)
808  initialSize = 1;
809  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
810  if (list->items == NULL) {
811  xmlXPathErrMemory(NULL,
812  "xmlPointerListCreate: allocating item\n");
813  return(-1);
814  }
815  list->number = 0;
816  list->size = initialSize;
817  } else if (list->size <= list->number) {
818  if (list->size > 50000000) {
819  xmlXPathErrMemory(NULL,
820  "xmlPointerListAddSize: re-allocating item\n");
821  return(-1);
822  }
823  list->size *= 2;
824  list->items = (void **) xmlRealloc(list->items,
825  list->size * sizeof(void *));
826  if (list->items == NULL) {
827  xmlXPathErrMemory(NULL,
828  "xmlPointerListAddSize: re-allocating item\n");
829  list->size = 0;
830  return(-1);
831  }
832  }
833  list->items[list->number++] = item;
834  return(0);
835 }
836 
844 static xmlPointerListPtr
845 xmlPointerListCreate(int initialSize)
846 {
847  xmlPointerListPtr ret;
848 
849  ret = xmlMalloc(sizeof(xmlPointerList));
850  if (ret == NULL) {
851  xmlXPathErrMemory(NULL,
852  "xmlPointerListCreate: allocating item\n");
853  return (NULL);
854  }
855  memset(ret, 0, sizeof(xmlPointerList));
856  if (initialSize > 0) {
857  xmlPointerListAddSize(ret, NULL, initialSize);
858  ret->number = 0;
859  }
860  return (ret);
861 }
862 
869 static void
870 xmlPointerListFree(xmlPointerListPtr list)
871 {
872  if (list == NULL)
873  return;
874  if (list->items != NULL)
875  xmlFree(list->items);
876  xmlFree(list);
877 }
878 
879 /************************************************************************
880  * *
881  * Parser Types *
882  * *
883  ************************************************************************/
884 
885 /*
886  * Types are private:
887  */
888 
889 typedef enum {
890  XPATH_OP_END=0,
891  XPATH_OP_AND,
892  XPATH_OP_OR,
893  XPATH_OP_EQUAL,
894  XPATH_OP_CMP,
895  XPATH_OP_PLUS,
896  XPATH_OP_MULT,
897  XPATH_OP_UNION,
898  XPATH_OP_ROOT,
899  XPATH_OP_NODE,
900  XPATH_OP_COLLECT,
901  XPATH_OP_VALUE, /* 11 */
902  XPATH_OP_VARIABLE,
903  XPATH_OP_FUNCTION,
904  XPATH_OP_ARG,
905  XPATH_OP_PREDICATE,
906  XPATH_OP_FILTER, /* 16 */
907  XPATH_OP_SORT /* 17 */
908 #ifdef LIBXML_XPTR_ENABLED
909  ,XPATH_OP_RANGETO
910 #endif
911 } xmlXPathOp;
912 
913 typedef enum {
914  AXIS_ANCESTOR = 1,
915  AXIS_ANCESTOR_OR_SELF,
917  AXIS_CHILD,
918  AXIS_DESCENDANT,
919  AXIS_DESCENDANT_OR_SELF,
920  AXIS_FOLLOWING,
921  AXIS_FOLLOWING_SIBLING,
922  AXIS_NAMESPACE,
923  AXIS_PARENT,
924  AXIS_PRECEDING,
925  AXIS_PRECEDING_SIBLING,
926  AXIS_SELF
927 } xmlXPathAxisVal;
928 
929 typedef enum {
930  NODE_TEST_NONE = 0,
931  NODE_TEST_TYPE = 1,
932  NODE_TEST_PI = 2,
933  NODE_TEST_ALL = 3,
934  NODE_TEST_NS = 4,
935  NODE_TEST_NAME = 5
936 } xmlXPathTestVal;
937 
938 typedef enum {
939  NODE_TYPE_NODE = 0,
940  NODE_TYPE_COMMENT = XML_COMMENT_NODE,
941  NODE_TYPE_TEXT = XML_TEXT_NODE,
942  NODE_TYPE_PI = XML_PI_NODE
943 } xmlXPathTypeVal;
944 
945 typedef struct _xmlXPathStepOp xmlXPathStepOp;
946 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
947 struct _xmlXPathStepOp {
948  xmlXPathOp op; /* The identifier of the operation */
949  int ch1; /* First child */
950  int ch2; /* Second child */
951  int value;
952  int value2;
953  int value3;
954  void *value4;
955  void *value5;
956  xmlXPathFunction cache;
957  void *cacheURI;
958 };
959 
960 struct _xmlXPathCompExpr {
961  int nbStep; /* Number of steps in this expression */
962  int maxStep; /* Maximum number of steps allocated */
963  xmlXPathStepOp *steps; /* ops for computation of this expression */
964  int last; /* index of last step in expression */
965  xmlChar *expr; /* the expression being computed */
966  xmlDictPtr dict; /* the dictionary to use if any */
967 #ifdef DEBUG_EVAL_COUNTS
968  int nb;
969  xmlChar *string;
970 #endif
971 #ifdef XPATH_STREAMING
972  xmlPatternPtr stream;
973 #endif
974 };
975 
976 /************************************************************************
977  * *
978  * Forward declarations *
979  * *
980  ************************************************************************/
981 static void
982 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
983 static void
984 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
985 static int
986 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
987  xmlXPathStepOpPtr op, xmlNodePtr *first);
988 static int
989 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
990  xmlXPathStepOpPtr op,
991  int isPredicate);
992 static void
993 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
994 
995 /************************************************************************
996  * *
997  * Parser Type functions *
998  * *
999  ************************************************************************/
1000 
1008 static xmlXPathCompExprPtr
1009 xmlXPathNewCompExpr(void) {
1010  xmlXPathCompExprPtr cur;
1011 
1012  cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1013  if (cur == NULL) {
1014  xmlXPathErrMemory(NULL, "allocating component\n");
1015  return(NULL);
1016  }
1017  memset(cur, 0, sizeof(xmlXPathCompExpr));
1018  cur->maxStep = 10;
1019  cur->nbStep = 0;
1020  cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1021  sizeof(xmlXPathStepOp));
1022  if (cur->steps == NULL) {
1023  xmlXPathErrMemory(NULL, "allocating steps\n");
1024  xmlFree(cur);
1025  return(NULL);
1026  }
1027  memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1028  cur->last = -1;
1029 #ifdef DEBUG_EVAL_COUNTS
1030  cur->nb = 0;
1031 #endif
1032  return(cur);
1033 }
1034 
1041 void
1042 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1043 {
1044  xmlXPathStepOpPtr op;
1045  int i;
1046 
1047  if (comp == NULL)
1048  return;
1049  if (comp->dict == NULL) {
1050  for (i = 0; i < comp->nbStep; i++) {
1051  op = &comp->steps[i];
1052  if (op->value4 != NULL) {
1053  if (op->op == XPATH_OP_VALUE)
1054  xmlXPathFreeObject(op->value4);
1055  else
1056  xmlFree(op->value4);
1057  }
1058  if (op->value5 != NULL)
1059  xmlFree(op->value5);
1060  }
1061  } else {
1062  for (i = 0; i < comp->nbStep; i++) {
1063  op = &comp->steps[i];
1064  if (op->value4 != NULL) {
1065  if (op->op == XPATH_OP_VALUE)
1066  xmlXPathFreeObject(op->value4);
1067  }
1068  }
1069  xmlDictFree(comp->dict);
1070  }
1071  if (comp->steps != NULL) {
1072  xmlFree(comp->steps);
1073  }
1074 #ifdef DEBUG_EVAL_COUNTS
1075  if (comp->string != NULL) {
1076  xmlFree(comp->string);
1077  }
1078 #endif
1079 #ifdef XPATH_STREAMING
1080  if (comp->stream != NULL) {
1081  xmlFreePatternList(comp->stream);
1082  }
1083 #endif
1084  if (comp->expr != NULL) {
1085  xmlFree(comp->expr);
1086  }
1087 
1088  xmlFree(comp);
1089 }
1090 
1107 static int
1108 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1109  xmlXPathOp op, int value,
1110  int value2, int value3, void *value4, void *value5) {
1111  xmlXPathCompExprPtr comp = ctxt->comp;
1112  if (comp->nbStep >= comp->maxStep) {
1113  xmlXPathStepOp *real;
1114 
1115  if (comp->maxStep >= XPATH_MAX_STEPS) {
1116  xmlXPathPErrMemory(ctxt, "adding step\n");
1117  return(-1);
1118  }
1119  comp->maxStep *= 2;
1120  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1121  comp->maxStep * sizeof(xmlXPathStepOp));
1122  if (real == NULL) {
1123  comp->maxStep /= 2;
1124  xmlXPathPErrMemory(ctxt, "adding step\n");
1125  return(-1);
1126  }
1127  comp->steps = real;
1128  }
1129  comp->last = comp->nbStep;
1130  comp->steps[comp->nbStep].ch1 = ch1;
1131  comp->steps[comp->nbStep].ch2 = ch2;
1132  comp->steps[comp->nbStep].op = op;
1133  comp->steps[comp->nbStep].value = value;
1134  comp->steps[comp->nbStep].value2 = value2;
1135  comp->steps[comp->nbStep].value3 = value3;
1136  if ((comp->dict != NULL) &&
1137  ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1138  (op == XPATH_OP_COLLECT))) {
1139  if (value4 != NULL) {
1140  comp->steps[comp->nbStep].value4 = (xmlChar *)
1141  (void *)xmlDictLookup(comp->dict, value4, -1);
1142  xmlFree(value4);
1143  } else
1144  comp->steps[comp->nbStep].value4 = NULL;
1145  if (value5 != NULL) {
1146  comp->steps[comp->nbStep].value5 = (xmlChar *)
1147  (void *)xmlDictLookup(comp->dict, value5, -1);
1148  xmlFree(value5);
1149  } else
1150  comp->steps[comp->nbStep].value5 = NULL;
1151  } else {
1152  comp->steps[comp->nbStep].value4 = value4;
1153  comp->steps[comp->nbStep].value5 = value5;
1154  }
1155  comp->steps[comp->nbStep].cache = NULL;
1156  return(comp->nbStep++);
1157 }
1158 
1166 static void
1167 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1168  int tmp;
1169 
1170 #ifndef LIBXML_THREAD_ENABLED
1171  /*
1172  * Since this manipulates possibly shared variables, this is
1173  * disabled if one detects that the library is used in a multithreaded
1174  * application
1175  */
1176  if (xmlXPathDisableOptimizer)
1177  return;
1178 #endif
1179 
1180  tmp = op->ch1;
1181  op->ch1 = op->ch2;
1182  op->ch2 = tmp;
1183 }
1184 
1185 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1186  xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1187  (op), (val), (val2), (val3), (val4), (val5))
1188 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1189  xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1190  (op), (val), (val2), (val3), (val4), (val5))
1191 
1192 #define PUSH_LEAVE_EXPR(op, val, val2) \
1193 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1194 
1195 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1196 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1197 
1198 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1199 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1200  (val), (val2), 0 ,NULL ,NULL)
1201 
1202 /************************************************************************
1203  * *
1204  * XPath object cache structures *
1205  * *
1206  ************************************************************************/
1207 
1208 /* #define XP_DEFAULT_CACHE_ON */
1209 
1210 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1211 
1212 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1213 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1214 struct _xmlXPathContextCache {
1215  xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1216  xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1217  xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1218  xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1219  xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1220  int maxNodeset;
1221  int maxString;
1222  int maxBoolean;
1223  int maxNumber;
1224  int maxMisc;
1225 #ifdef XP_DEBUG_OBJ_USAGE
1226  int dbgCachedAll;
1227  int dbgCachedNodeset;
1228  int dbgCachedString;
1229  int dbgCachedBool;
1230  int dbgCachedNumber;
1231  int dbgCachedPoint;
1232  int dbgCachedRange;
1233  int dbgCachedLocset;
1234  int dbgCachedUsers;
1235  int dbgCachedXSLTTree;
1236  int dbgCachedUndefined;
1237 
1238 
1239  int dbgReusedAll;
1240  int dbgReusedNodeset;
1241  int dbgReusedString;
1242  int dbgReusedBool;
1243  int dbgReusedNumber;
1244  int dbgReusedPoint;
1245  int dbgReusedRange;
1246  int dbgReusedLocset;
1247  int dbgReusedUsers;
1248  int dbgReusedXSLTTree;
1249  int dbgReusedUndefined;
1250 
1251 #endif
1252 };
1253 
1254 /************************************************************************
1255  * *
1256  * Debugging related functions *
1257  * *
1258  ************************************************************************/
1259 
1260 #define STRANGE \
1261  xmlGenericError(xmlGenericErrorContext, \
1262  "Internal error at %s:%d\n", \
1263  __FILE__, __LINE__);
1264 
1265 #ifdef LIBXML_DEBUG_ENABLED
1266 static void
1267 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1268  int i;
1269  char shift[100];
1270 
1271  for (i = 0;((i < depth) && (i < 25));i++)
1272  shift[2 * i] = shift[2 * i + 1] = ' ';
1273  shift[2 * i] = shift[2 * i + 1] = 0;
1274  if (cur == NULL) {
1275  fprintf(output, "%s", shift);
1276  fprintf(output, "Node is NULL !\n");
1277  return;
1278 
1279  }
1280 
1281  if ((cur->type == XML_DOCUMENT_NODE) ||
1282  (cur->type == XML_HTML_DOCUMENT_NODE)) {
1283  fprintf(output, "%s", shift);
1284  fprintf(output, " /\n");
1285  } else if (cur->type == XML_ATTRIBUTE_NODE)
1286  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1287  else
1288  xmlDebugDumpOneNode(output, cur, depth);
1289 }
1290 static void
1291 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1292  xmlNodePtr tmp;
1293  int i;
1294  char shift[100];
1295 
1296  for (i = 0;((i < depth) && (i < 25));i++)
1297  shift[2 * i] = shift[2 * i + 1] = ' ';
1298  shift[2 * i] = shift[2 * i + 1] = 0;
1299  if (cur == NULL) {
1300  fprintf(output, "%s", shift);
1301  fprintf(output, "Node is NULL !\n");
1302  return;
1303 
1304  }
1305 
1306  while (cur != NULL) {
1307  tmp = cur;
1308  cur = cur->next;
1309  xmlDebugDumpOneNode(output, tmp, depth);
1310  }
1311 }
1312 
1313 static void
1314 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1315  int i;
1316  char shift[100];
1317 
1318  for (i = 0;((i < depth) && (i < 25));i++)
1319  shift[2 * i] = shift[2 * i + 1] = ' ';
1320  shift[2 * i] = shift[2 * i + 1] = 0;
1321 
1322  if (cur == NULL) {
1323  fprintf(output, "%s", shift);
1324  fprintf(output, "NodeSet is NULL !\n");
1325  return;
1326 
1327  }
1328 
1329  if (cur != NULL) {
1330  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1331  for (i = 0;i < cur->nodeNr;i++) {
1332  fprintf(output, "%s", shift);
1333  fprintf(output, "%d", i + 1);
1334  xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1335  }
1336  }
1337 }
1338 
1339 static void
1340 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1341  int i;
1342  char shift[100];
1343 
1344  for (i = 0;((i < depth) && (i < 25));i++)
1345  shift[2 * i] = shift[2 * i + 1] = ' ';
1346  shift[2 * i] = shift[2 * i + 1] = 0;
1347 
1348  if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1349  fprintf(output, "%s", shift);
1350  fprintf(output, "Value Tree is NULL !\n");
1351  return;
1352 
1353  }
1354 
1355  fprintf(output, "%s", shift);
1356  fprintf(output, "%d", i + 1);
1357  xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1358 }
1359 #if defined(LIBXML_XPTR_ENABLED)
1360 static void
1361 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1362  int i;
1363  char shift[100];
1364 
1365  for (i = 0;((i < depth) && (i < 25));i++)
1366  shift[2 * i] = shift[2 * i + 1] = ' ';
1367  shift[2 * i] = shift[2 * i + 1] = 0;
1368 
1369  if (cur == NULL) {
1370  fprintf(output, "%s", shift);
1371  fprintf(output, "LocationSet is NULL !\n");
1372  return;
1373 
1374  }
1375 
1376  for (i = 0;i < cur->locNr;i++) {
1377  fprintf(output, "%s", shift);
1378  fprintf(output, "%d : ", i + 1);
1379  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1380  }
1381 }
1382 #endif /* LIBXML_XPTR_ENABLED */
1383 
1392 void
1393 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1394  int i;
1395  char shift[100];
1396 
1397  if (output == NULL) return;
1398 
1399  for (i = 0;((i < depth) && (i < 25));i++)
1400  shift[2 * i] = shift[2 * i + 1] = ' ';
1401  shift[2 * i] = shift[2 * i + 1] = 0;
1402 
1403 
1404  fprintf(output, "%s", shift);
1405 
1406  if (cur == NULL) {
1407  fprintf(output, "Object is empty (NULL)\n");
1408  return;
1409  }
1410  switch(cur->type) {
1411  case XPATH_UNDEFINED:
1412  fprintf(output, "Object is uninitialized\n");
1413  break;
1414  case XPATH_NODESET:
1415  fprintf(output, "Object is a Node Set :\n");
1416  xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1417  break;
1418  case XPATH_XSLT_TREE:
1419  fprintf(output, "Object is an XSLT value tree :\n");
1420  xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1421  break;
1422  case XPATH_BOOLEAN:
1423  fprintf(output, "Object is a Boolean : ");
1424  if (cur->boolval) fprintf(output, "true\n");
1425  else fprintf(output, "false\n");
1426  break;
1427  case XPATH_NUMBER:
1428  switch (xmlXPathIsInf(cur->floatval)) {
1429  case 1:
1430  fprintf(output, "Object is a number : Infinity\n");
1431  break;
1432  case -1:
1433  fprintf(output, "Object is a number : -Infinity\n");
1434  break;
1435  default:
1436  if (xmlXPathIsNaN(cur->floatval)) {
1437  fprintf(output, "Object is a number : NaN\n");
1438  } else if (cur->floatval == 0) {
1439  /* Omit sign for negative zero. */
1440  fprintf(output, "Object is a number : 0\n");
1441  } else {
1442  fprintf(output, "Object is a number : %0g\n", cur->floatval);
1443  }
1444  }
1445  break;
1446  case XPATH_STRING:
1447  fprintf(output, "Object is a string : ");
1448  xmlDebugDumpString(output, cur->stringval);
1449  fprintf(output, "\n");
1450  break;
1451  case XPATH_POINT:
1452  fprintf(output, "Object is a point : index %d in node", cur->index);
1453  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1454  fprintf(output, "\n");
1455  break;
1456  case XPATH_RANGE:
1457  if ((cur->user2 == NULL) ||
1458  ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1459  fprintf(output, "Object is a collapsed range :\n");
1460  fprintf(output, "%s", shift);
1461  if (cur->index >= 0)
1462  fprintf(output, "index %d in ", cur->index);
1463  fprintf(output, "node\n");
1464  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1465  depth + 1);
1466  } else {
1467  fprintf(output, "Object is a range :\n");
1468  fprintf(output, "%s", shift);
1469  fprintf(output, "From ");
1470  if (cur->index >= 0)
1471  fprintf(output, "index %d in ", cur->index);
1472  fprintf(output, "node\n");
1473  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1474  depth + 1);
1475  fprintf(output, "%s", shift);
1476  fprintf(output, "To ");
1477  if (cur->index2 >= 0)
1478  fprintf(output, "index %d in ", cur->index2);
1479  fprintf(output, "node\n");
1480  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1481  depth + 1);
1482  fprintf(output, "\n");
1483  }
1484  break;
1485  case XPATH_LOCATIONSET:
1486 #if defined(LIBXML_XPTR_ENABLED)
1487  fprintf(output, "Object is a Location Set:\n");
1488  xmlXPathDebugDumpLocationSet(output,
1489  (xmlLocationSetPtr) cur->user, depth);
1490 #endif
1491  break;
1492  case XPATH_USERS:
1493  fprintf(output, "Object is user defined\n");
1494  break;
1495  }
1496 }
1497 
1498 static void
1499 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1500  xmlXPathStepOpPtr op, int depth) {
1501  int i;
1502  char shift[100];
1503 
1504  for (i = 0;((i < depth) && (i < 25));i++)
1505  shift[2 * i] = shift[2 * i + 1] = ' ';
1506  shift[2 * i] = shift[2 * i + 1] = 0;
1507 
1508  fprintf(output, "%s", shift);
1509  if (op == NULL) {
1510  fprintf(output, "Step is NULL\n");
1511  return;
1512  }
1513  switch (op->op) {
1514  case XPATH_OP_END:
1515  fprintf(output, "END"); break;
1516  case XPATH_OP_AND:
1517  fprintf(output, "AND"); break;
1518  case XPATH_OP_OR:
1519  fprintf(output, "OR"); break;
1520  case XPATH_OP_EQUAL:
1521  if (op->value)
1522  fprintf(output, "EQUAL =");
1523  else
1524  fprintf(output, "EQUAL !=");
1525  break;
1526  case XPATH_OP_CMP:
1527  if (op->value)
1528  fprintf(output, "CMP <");
1529  else
1530  fprintf(output, "CMP >");
1531  if (!op->value2)
1532  fprintf(output, "=");
1533  break;
1534  case XPATH_OP_PLUS:
1535  if (op->value == 0)
1536  fprintf(output, "PLUS -");
1537  else if (op->value == 1)
1538  fprintf(output, "PLUS +");
1539  else if (op->value == 2)
1540  fprintf(output, "PLUS unary -");
1541  else if (op->value == 3)
1542  fprintf(output, "PLUS unary - -");
1543  break;
1544  case XPATH_OP_MULT:
1545  if (op->value == 0)
1546  fprintf(output, "MULT *");
1547  else if (op->value == 1)
1548  fprintf(output, "MULT div");
1549  else
1550  fprintf(output, "MULT mod");
1551  break;
1552  case XPATH_OP_UNION:
1553  fprintf(output, "UNION"); break;
1554  case XPATH_OP_ROOT:
1555  fprintf(output, "ROOT"); break;
1556  case XPATH_OP_NODE:
1557  fprintf(output, "NODE"); break;
1558  case XPATH_OP_SORT:
1559  fprintf(output, "SORT"); break;
1560  case XPATH_OP_COLLECT: {
1561  xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1562  xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1563  xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1564  const xmlChar *prefix = op->value4;
1565  const xmlChar *name = op->value5;
1566 
1567  fprintf(output, "COLLECT ");
1568  switch (axis) {
1569  case AXIS_ANCESTOR:
1570  fprintf(output, " 'ancestors' "); break;
1571  case AXIS_ANCESTOR_OR_SELF:
1572  fprintf(output, " 'ancestors-or-self' "); break;
1573  case AXIS_ATTRIBUTE:
1574  fprintf(output, " 'attributes' "); break;
1575  case AXIS_CHILD:
1576  fprintf(output, " 'child' "); break;
1577  case AXIS_DESCENDANT:
1578  fprintf(output, " 'descendant' "); break;
1579  case AXIS_DESCENDANT_OR_SELF:
1580  fprintf(output, " 'descendant-or-self' "); break;
1581  case AXIS_FOLLOWING:
1582  fprintf(output, " 'following' "); break;
1583  case AXIS_FOLLOWING_SIBLING:
1584  fprintf(output, " 'following-siblings' "); break;
1585  case AXIS_NAMESPACE:
1586  fprintf(output, " 'namespace' "); break;
1587  case AXIS_PARENT:
1588  fprintf(output, " 'parent' "); break;
1589  case AXIS_PRECEDING:
1590  fprintf(output, " 'preceding' "); break;
1591  case AXIS_PRECEDING_SIBLING:
1592  fprintf(output, " 'preceding-sibling' "); break;
1593  case AXIS_SELF:
1594  fprintf(output, " 'self' "); break;
1595  }
1596  switch (test) {
1597  case NODE_TEST_NONE:
1598  fprintf(output, "'none' "); break;
1599  case NODE_TEST_TYPE:
1600  fprintf(output, "'type' "); break;
1601  case NODE_TEST_PI:
1602  fprintf(output, "'PI' "); break;
1603  case NODE_TEST_ALL:
1604  fprintf(output, "'all' "); break;
1605  case NODE_TEST_NS:
1606  fprintf(output, "'namespace' "); break;
1607  case NODE_TEST_NAME:
1608  fprintf(output, "'name' "); break;
1609  }
1610  switch (type) {
1611  case NODE_TYPE_NODE:
1612  fprintf(output, "'node' "); break;
1613  case NODE_TYPE_COMMENT:
1614  fprintf(output, "'comment' "); break;
1615  case NODE_TYPE_TEXT:
1616  fprintf(output, "'text' "); break;
1617  case NODE_TYPE_PI:
1618  fprintf(output, "'PI' "); break;
1619  }
1620  if (prefix != NULL)
1621  fprintf(output, "%s:", prefix);
1622  if (name != NULL)
1623  fprintf(output, "%s", (const char *) name);
1624  break;
1625 
1626  }
1627  case XPATH_OP_VALUE: {
1628  xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1629 
1630  fprintf(output, "ELEM ");
1631  xmlXPathDebugDumpObject(output, object, 0);
1632  goto finish;
1633  }
1634  case XPATH_OP_VARIABLE: {
1635  const xmlChar *prefix = op->value5;
1636  const xmlChar *name = op->value4;
1637 
1638  if (prefix != NULL)
1639  fprintf(output, "VARIABLE %s:%s", prefix, name);
1640  else
1641  fprintf(output, "VARIABLE %s", name);
1642  break;
1643  }
1644  case XPATH_OP_FUNCTION: {
1645  int nbargs = op->value;
1646  const xmlChar *prefix = op->value5;
1647  const xmlChar *name = op->value4;
1648 
1649  if (prefix != NULL)
1650  fprintf(output, "FUNCTION %s:%s(%d args)",
1651  prefix, name, nbargs);
1652  else
1653  fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1654  break;
1655  }
1656  case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1657  case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1658  case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1659 #ifdef LIBXML_XPTR_ENABLED
1660  case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1661 #endif
1662  default:
1663  fprintf(output, "UNKNOWN %d\n", op->op); return;
1664  }
1665  fprintf(output, "\n");
1666 finish:
1667  if (op->ch1 >= 0)
1668  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1669  if (op->ch2 >= 0)
1670  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1671 }
1672 
1681 void
1682 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1683  int depth) {
1684  int i;
1685  char shift[100];
1686 
1687  if ((output == NULL) || (comp == NULL)) return;
1688 
1689  for (i = 0;((i < depth) && (i < 25));i++)
1690  shift[2 * i] = shift[2 * i + 1] = ' ';
1691  shift[2 * i] = shift[2 * i + 1] = 0;
1692 
1693  fprintf(output, "%s", shift);
1694 
1695 #ifdef XPATH_STREAMING
1696  if (comp->stream) {
1697  fprintf(output, "Streaming Expression\n");
1698  } else
1699 #endif
1700  {
1701  fprintf(output, "Compiled Expression : %d elements\n",
1702  comp->nbStep);
1703  i = comp->last;
1704  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1705  }
1706 }
1707 
1708 #ifdef XP_DEBUG_OBJ_USAGE
1709 
1710 /*
1711 * XPath object usage related debugging variables.
1712 */
1713 static int xmlXPathDebugObjCounterUndefined = 0;
1714 static int xmlXPathDebugObjCounterNodeset = 0;
1715 static int xmlXPathDebugObjCounterBool = 0;
1716 static int xmlXPathDebugObjCounterNumber = 0;
1717 static int xmlXPathDebugObjCounterString = 0;
1718 static int xmlXPathDebugObjCounterPoint = 0;
1719 static int xmlXPathDebugObjCounterRange = 0;
1720 static int xmlXPathDebugObjCounterLocset = 0;
1721 static int xmlXPathDebugObjCounterUsers = 0;
1722 static int xmlXPathDebugObjCounterXSLTTree = 0;
1723 static int xmlXPathDebugObjCounterAll = 0;
1724 
1725 static int xmlXPathDebugObjTotalUndefined = 0;
1726 static int xmlXPathDebugObjTotalNodeset = 0;
1727 static int xmlXPathDebugObjTotalBool = 0;
1728 static int xmlXPathDebugObjTotalNumber = 0;
1729 static int xmlXPathDebugObjTotalString = 0;
1730 static int xmlXPathDebugObjTotalPoint = 0;
1731 static int xmlXPathDebugObjTotalRange = 0;
1732 static int xmlXPathDebugObjTotalLocset = 0;
1733 static int xmlXPathDebugObjTotalUsers = 0;
1734 static int xmlXPathDebugObjTotalXSLTTree = 0;
1735 static int xmlXPathDebugObjTotalAll = 0;
1736 
1737 static int xmlXPathDebugObjMaxUndefined = 0;
1738 static int xmlXPathDebugObjMaxNodeset = 0;
1739 static int xmlXPathDebugObjMaxBool = 0;
1740 static int xmlXPathDebugObjMaxNumber = 0;
1741 static int xmlXPathDebugObjMaxString = 0;
1742 static int xmlXPathDebugObjMaxPoint = 0;
1743 static int xmlXPathDebugObjMaxRange = 0;
1744 static int xmlXPathDebugObjMaxLocset = 0;
1745 static int xmlXPathDebugObjMaxUsers = 0;
1746 static int xmlXPathDebugObjMaxXSLTTree = 0;
1747 static int xmlXPathDebugObjMaxAll = 0;
1748 
1749 /* REVISIT TODO: Make this static when committing */
1750 static void
1751 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1752 {
1753  if (ctxt != NULL) {
1754  if (ctxt->cache != NULL) {
1755  xmlXPathContextCachePtr cache =
1756  (xmlXPathContextCachePtr) ctxt->cache;
1757 
1758  cache->dbgCachedAll = 0;
1759  cache->dbgCachedNodeset = 0;
1760  cache->dbgCachedString = 0;
1761  cache->dbgCachedBool = 0;
1762  cache->dbgCachedNumber = 0;
1763  cache->dbgCachedPoint = 0;
1764  cache->dbgCachedRange = 0;
1765  cache->dbgCachedLocset = 0;
1766  cache->dbgCachedUsers = 0;
1767  cache->dbgCachedXSLTTree = 0;
1768  cache->dbgCachedUndefined = 0;
1769 
1770  cache->dbgReusedAll = 0;
1771  cache->dbgReusedNodeset = 0;
1772  cache->dbgReusedString = 0;
1773  cache->dbgReusedBool = 0;
1774  cache->dbgReusedNumber = 0;
1775  cache->dbgReusedPoint = 0;
1776  cache->dbgReusedRange = 0;
1777  cache->dbgReusedLocset = 0;
1778  cache->dbgReusedUsers = 0;
1779  cache->dbgReusedXSLTTree = 0;
1780  cache->dbgReusedUndefined = 0;
1781  }
1782  }
1783 
1784  xmlXPathDebugObjCounterUndefined = 0;
1785  xmlXPathDebugObjCounterNodeset = 0;
1786  xmlXPathDebugObjCounterBool = 0;
1787  xmlXPathDebugObjCounterNumber = 0;
1788  xmlXPathDebugObjCounterString = 0;
1789  xmlXPathDebugObjCounterPoint = 0;
1790  xmlXPathDebugObjCounterRange = 0;
1791  xmlXPathDebugObjCounterLocset = 0;
1792  xmlXPathDebugObjCounterUsers = 0;
1793  xmlXPathDebugObjCounterXSLTTree = 0;
1794  xmlXPathDebugObjCounterAll = 0;
1795 
1796  xmlXPathDebugObjTotalUndefined = 0;
1797  xmlXPathDebugObjTotalNodeset = 0;
1798  xmlXPathDebugObjTotalBool = 0;
1799  xmlXPathDebugObjTotalNumber = 0;
1800  xmlXPathDebugObjTotalString = 0;
1801  xmlXPathDebugObjTotalPoint = 0;
1802  xmlXPathDebugObjTotalRange = 0;
1803  xmlXPathDebugObjTotalLocset = 0;
1804  xmlXPathDebugObjTotalUsers = 0;
1805  xmlXPathDebugObjTotalXSLTTree = 0;
1806  xmlXPathDebugObjTotalAll = 0;
1807 
1808  xmlXPathDebugObjMaxUndefined = 0;
1809  xmlXPathDebugObjMaxNodeset = 0;
1810  xmlXPathDebugObjMaxBool = 0;
1811  xmlXPathDebugObjMaxNumber = 0;
1812  xmlXPathDebugObjMaxString = 0;
1813  xmlXPathDebugObjMaxPoint = 0;
1814  xmlXPathDebugObjMaxRange = 0;
1815  xmlXPathDebugObjMaxLocset = 0;
1816  xmlXPathDebugObjMaxUsers = 0;
1817  xmlXPathDebugObjMaxXSLTTree = 0;
1818  xmlXPathDebugObjMaxAll = 0;
1819 
1820 }
1821 
1822 static void
1823 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1824  xmlXPathObjectType objType)
1825 {
1826  int isCached = 0;
1827 
1828  if (ctxt != NULL) {
1829  if (ctxt->cache != NULL) {
1830  xmlXPathContextCachePtr cache =
1831  (xmlXPathContextCachePtr) ctxt->cache;
1832 
1833  isCached = 1;
1834 
1835  cache->dbgReusedAll++;
1836  switch (objType) {
1837  case XPATH_UNDEFINED:
1838  cache->dbgReusedUndefined++;
1839  break;
1840  case XPATH_NODESET:
1841  cache->dbgReusedNodeset++;
1842  break;
1843  case XPATH_BOOLEAN:
1844  cache->dbgReusedBool++;
1845  break;
1846  case XPATH_NUMBER:
1847  cache->dbgReusedNumber++;
1848  break;
1849  case XPATH_STRING:
1850  cache->dbgReusedString++;
1851  break;
1852  case XPATH_POINT:
1853  cache->dbgReusedPoint++;
1854  break;
1855  case XPATH_RANGE:
1856  cache->dbgReusedRange++;
1857  break;
1858  case XPATH_LOCATIONSET:
1859  cache->dbgReusedLocset++;
1860  break;
1861  case XPATH_USERS:
1862  cache->dbgReusedUsers++;
1863  break;
1864  case XPATH_XSLT_TREE:
1865  cache->dbgReusedXSLTTree++;
1866  break;
1867  default:
1868  break;
1869  }
1870  }
1871  }
1872 
1873  switch (objType) {
1874  case XPATH_UNDEFINED:
1875  if (! isCached)
1876  xmlXPathDebugObjTotalUndefined++;
1877  xmlXPathDebugObjCounterUndefined++;
1878  if (xmlXPathDebugObjCounterUndefined >
1879  xmlXPathDebugObjMaxUndefined)
1880  xmlXPathDebugObjMaxUndefined =
1881  xmlXPathDebugObjCounterUndefined;
1882  break;
1883  case XPATH_NODESET:
1884  if (! isCached)
1885  xmlXPathDebugObjTotalNodeset++;
1886  xmlXPathDebugObjCounterNodeset++;
1887  if (xmlXPathDebugObjCounterNodeset >
1888  xmlXPathDebugObjMaxNodeset)
1889  xmlXPathDebugObjMaxNodeset =
1890  xmlXPathDebugObjCounterNodeset;
1891  break;
1892  case XPATH_BOOLEAN:
1893  if (! isCached)
1894  xmlXPathDebugObjTotalBool++;
1895  xmlXPathDebugObjCounterBool++;
1896  if (xmlXPathDebugObjCounterBool >
1897  xmlXPathDebugObjMaxBool)
1898  xmlXPathDebugObjMaxBool =
1899  xmlXPathDebugObjCounterBool;
1900  break;
1901  case XPATH_NUMBER:
1902  if (! isCached)
1903  xmlXPathDebugObjTotalNumber++;
1904  xmlXPathDebugObjCounterNumber++;
1905  if (xmlXPathDebugObjCounterNumber >
1906  xmlXPathDebugObjMaxNumber)
1907  xmlXPathDebugObjMaxNumber =
1908  xmlXPathDebugObjCounterNumber;
1909  break;
1910  case XPATH_STRING:
1911  if (! isCached)
1912  xmlXPathDebugObjTotalString++;
1913  xmlXPathDebugObjCounterString++;
1914  if (xmlXPathDebugObjCounterString >
1915  xmlXPathDebugObjMaxString)
1916  xmlXPathDebugObjMaxString =
1917  xmlXPathDebugObjCounterString;
1918  break;
1919  case XPATH_POINT:
1920  if (! isCached)
1921  xmlXPathDebugObjTotalPoint++;
1922  xmlXPathDebugObjCounterPoint++;
1923  if (xmlXPathDebugObjCounterPoint >
1924  xmlXPathDebugObjMaxPoint)
1925  xmlXPathDebugObjMaxPoint =
1926  xmlXPathDebugObjCounterPoint;
1927  break;
1928  case XPATH_RANGE:
1929  if (! isCached)
1930  xmlXPathDebugObjTotalRange++;
1931  xmlXPathDebugObjCounterRange++;
1932  if (xmlXPathDebugObjCounterRange >
1933  xmlXPathDebugObjMaxRange)
1934  xmlXPathDebugObjMaxRange =
1935  xmlXPathDebugObjCounterRange;
1936  break;
1937  case XPATH_LOCATIONSET:
1938  if (! isCached)
1939  xmlXPathDebugObjTotalLocset++;
1940  xmlXPathDebugObjCounterLocset++;
1941  if (xmlXPathDebugObjCounterLocset >
1942  xmlXPathDebugObjMaxLocset)
1943  xmlXPathDebugObjMaxLocset =
1944  xmlXPathDebugObjCounterLocset;
1945  break;
1946  case XPATH_USERS:
1947  if (! isCached)
1948  xmlXPathDebugObjTotalUsers++;
1949  xmlXPathDebugObjCounterUsers++;
1950  if (xmlXPathDebugObjCounterUsers >
1951  xmlXPathDebugObjMaxUsers)
1952  xmlXPathDebugObjMaxUsers =
1953  xmlXPathDebugObjCounterUsers;
1954  break;
1955  case XPATH_XSLT_TREE:
1956  if (! isCached)
1957  xmlXPathDebugObjTotalXSLTTree++;
1958  xmlXPathDebugObjCounterXSLTTree++;
1959  if (xmlXPathDebugObjCounterXSLTTree >
1960  xmlXPathDebugObjMaxXSLTTree)
1961  xmlXPathDebugObjMaxXSLTTree =
1962  xmlXPathDebugObjCounterXSLTTree;
1963  break;
1964  default:
1965  break;
1966  }
1967  if (! isCached)
1968  xmlXPathDebugObjTotalAll++;
1969  xmlXPathDebugObjCounterAll++;
1970  if (xmlXPathDebugObjCounterAll >
1971  xmlXPathDebugObjMaxAll)
1972  xmlXPathDebugObjMaxAll =
1973  xmlXPathDebugObjCounterAll;
1974 }
1975 
1976 static void
1977 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1978  xmlXPathObjectType objType)
1979 {
1980  int isCached = 0;
1981 
1982  if (ctxt != NULL) {
1983  if (ctxt->cache != NULL) {
1984  xmlXPathContextCachePtr cache =
1985  (xmlXPathContextCachePtr) ctxt->cache;
1986 
1987  isCached = 1;
1988 
1989  cache->dbgCachedAll++;
1990  switch (objType) {
1991  case XPATH_UNDEFINED:
1992  cache->dbgCachedUndefined++;
1993  break;
1994  case XPATH_NODESET:
1995  cache->dbgCachedNodeset++;
1996  break;
1997  case XPATH_BOOLEAN:
1998  cache->dbgCachedBool++;
1999  break;
2000  case XPATH_NUMBER:
2001  cache->dbgCachedNumber++;
2002  break;
2003  case XPATH_STRING:
2004  cache->dbgCachedString++;
2005  break;
2006  case XPATH_POINT:
2007  cache->dbgCachedPoint++;
2008  break;
2009  case XPATH_RANGE:
2010  cache->dbgCachedRange++;
2011  break;
2012  case XPATH_LOCATIONSET:
2013  cache->dbgCachedLocset++;
2014  break;
2015  case XPATH_USERS:
2016  cache->dbgCachedUsers++;
2017  break;
2018  case XPATH_XSLT_TREE:
2019  cache->dbgCachedXSLTTree++;
2020  break;
2021  default:
2022  break;
2023  }
2024 
2025  }
2026  }
2027  switch (objType) {
2028  case XPATH_UNDEFINED:
2029  xmlXPathDebugObjCounterUndefined--;
2030  break;
2031  case XPATH_NODESET:
2032  xmlXPathDebugObjCounterNodeset--;
2033  break;
2034  case XPATH_BOOLEAN:
2035  xmlXPathDebugObjCounterBool--;
2036  break;
2037  case XPATH_NUMBER:
2038  xmlXPathDebugObjCounterNumber--;
2039  break;
2040  case XPATH_STRING:
2041  xmlXPathDebugObjCounterString--;
2042  break;
2043  case XPATH_POINT:
2044  xmlXPathDebugObjCounterPoint--;
2045  break;
2046  case XPATH_RANGE:
2047  xmlXPathDebugObjCounterRange--;
2048  break;
2049  case XPATH_LOCATIONSET:
2050  xmlXPathDebugObjCounterLocset--;
2051  break;
2052  case XPATH_USERS:
2053  xmlXPathDebugObjCounterUsers--;
2054  break;
2055  case XPATH_XSLT_TREE:
2056  xmlXPathDebugObjCounterXSLTTree--;
2057  break;
2058  default:
2059  break;
2060  }
2061  xmlXPathDebugObjCounterAll--;
2062 }
2063 
2064 /* REVISIT TODO: Make this static when committing */
2065 static void
2066 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2067 {
2068  int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2069  reqXSLTTree, reqUndefined;
2070  int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2071  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2072  int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2073  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2074  int leftObjs = xmlXPathDebugObjCounterAll;
2075 
2076  reqAll = xmlXPathDebugObjTotalAll;
2077  reqNodeset = xmlXPathDebugObjTotalNodeset;
2078  reqString = xmlXPathDebugObjTotalString;
2079  reqBool = xmlXPathDebugObjTotalBool;
2080  reqNumber = xmlXPathDebugObjTotalNumber;
2081  reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2082  reqUndefined = xmlXPathDebugObjTotalUndefined;
2083 
2084  printf("# XPath object usage:\n");
2085 
2086  if (ctxt != NULL) {
2087  if (ctxt->cache != NULL) {
2088  xmlXPathContextCachePtr cache =
2089  (xmlXPathContextCachePtr) ctxt->cache;
2090 
2091  reAll = cache->dbgReusedAll;
2092  reqAll += reAll;
2093  reNodeset = cache->dbgReusedNodeset;
2094  reqNodeset += reNodeset;
2095  reString = cache->dbgReusedString;
2096  reqString += reString;
2097  reBool = cache->dbgReusedBool;
2098  reqBool += reBool;
2099  reNumber = cache->dbgReusedNumber;
2100  reqNumber += reNumber;
2101  reXSLTTree = cache->dbgReusedXSLTTree;
2102  reqXSLTTree += reXSLTTree;
2103  reUndefined = cache->dbgReusedUndefined;
2104  reqUndefined += reUndefined;
2105 
2106  caAll = cache->dbgCachedAll;
2107  caBool = cache->dbgCachedBool;
2108  caNodeset = cache->dbgCachedNodeset;
2109  caString = cache->dbgCachedString;
2110  caNumber = cache->dbgCachedNumber;
2111  caXSLTTree = cache->dbgCachedXSLTTree;
2112  caUndefined = cache->dbgCachedUndefined;
2113 
2114  if (cache->nodesetObjs)
2115  leftObjs -= cache->nodesetObjs->number;
2116  if (cache->stringObjs)
2117  leftObjs -= cache->stringObjs->number;
2118  if (cache->booleanObjs)
2119  leftObjs -= cache->booleanObjs->number;
2120  if (cache->numberObjs)
2121  leftObjs -= cache->numberObjs->number;
2122  if (cache->miscObjs)
2123  leftObjs -= cache->miscObjs->number;
2124  }
2125  }
2126 
2127  printf("# all\n");
2128  printf("# total : %d\n", reqAll);
2129  printf("# left : %d\n", leftObjs);
2130  printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2131  printf("# reused : %d\n", reAll);
2132  printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2133 
2134  printf("# node-sets\n");
2135  printf("# total : %d\n", reqNodeset);
2136  printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2137  printf("# reused : %d\n", reNodeset);
2138  printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2139 
2140  printf("# strings\n");
2141  printf("# total : %d\n", reqString);
2142  printf("# created: %d\n", xmlXPathDebugObjTotalString);
2143  printf("# reused : %d\n", reString);
2144  printf("# max : %d\n", xmlXPathDebugObjMaxString);
2145 
2146  printf("# booleans\n");
2147  printf("# total : %d\n", reqBool);
2148  printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2149  printf("# reused : %d\n", reBool);
2150  printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2151 
2152  printf("# numbers\n");
2153  printf("# total : %d\n", reqNumber);
2154  printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2155  printf("# reused : %d\n", reNumber);
2156  printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2157 
2158  printf("# XSLT result tree fragments\n");
2159  printf("# total : %d\n", reqXSLTTree);
2160  printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2161  printf("# reused : %d\n", reXSLTTree);
2162  printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2163 
2164  printf("# undefined\n");
2165  printf("# total : %d\n", reqUndefined);
2166  printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2167  printf("# reused : %d\n", reUndefined);
2168  printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2169 
2170 }
2171 
2172 #endif /* XP_DEBUG_OBJ_USAGE */
2173 
2174 #endif /* LIBXML_DEBUG_ENABLED */
2175 
2176 /************************************************************************
2177  * *
2178  * XPath object caching *
2179  * *
2180  ************************************************************************/
2181 
2189 static xmlXPathContextCachePtr
2190 xmlXPathNewCache(void)
2191 {
2192  xmlXPathContextCachePtr ret;
2193 
2194  ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2195  if (ret == NULL) {
2196  xmlXPathErrMemory(NULL, "creating object cache\n");
2197  return(NULL);
2198  }
2199  memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2200  ret->maxNodeset = 100;
2201  ret->maxString = 100;
2202  ret->maxBoolean = 100;
2203  ret->maxNumber = 100;
2204  ret->maxMisc = 100;
2205  return(ret);
2206 }
2207 
2208 static void
2209 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2210 {
2211  int i;
2212  xmlXPathObjectPtr obj;
2213 
2214  if (list == NULL)
2215  return;
2216 
2217  for (i = 0; i < list->number; i++) {
2218  obj = list->items[i];
2219  /*
2220  * Note that it is already assured that we don't need to
2221  * look out for namespace nodes in the node-set.
2222  */
2223  if (obj->nodesetval != NULL) {
2224  if (obj->nodesetval->nodeTab != NULL)
2225  xmlFree(obj->nodesetval->nodeTab);
2226  xmlFree(obj->nodesetval);
2227  }
2228  xmlFree(obj);
2229 #ifdef XP_DEBUG_OBJ_USAGE
2230  xmlXPathDebugObjCounterAll--;
2231 #endif
2232  }
2233  xmlPointerListFree(list);
2234 }
2235 
2236 static void
2237 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2238 {
2239  if (cache == NULL)
2240  return;
2241  if (cache->nodesetObjs)
2242  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2243  if (cache->stringObjs)
2244  xmlXPathCacheFreeObjectList(cache->stringObjs);
2245  if (cache->booleanObjs)
2246  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2247  if (cache->numberObjs)
2248  xmlXPathCacheFreeObjectList(cache->numberObjs);
2249  if (cache->miscObjs)
2250  xmlXPathCacheFreeObjectList(cache->miscObjs);
2251  xmlFree(cache);
2252 }
2253 
2276 int
2277 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2278  int active,
2279  int value,
2280  int options)
2281 {
2282  if (ctxt == NULL)
2283  return(-1);
2284  if (active) {
2285  xmlXPathContextCachePtr cache;
2286 
2287  if (ctxt->cache == NULL) {
2288  ctxt->cache = xmlXPathNewCache();
2289  if (ctxt->cache == NULL)
2290  return(-1);
2291  }
2292  cache = (xmlXPathContextCachePtr) ctxt->cache;
2293  if (options == 0) {
2294  if (value < 0)
2295  value = 100;
2296  cache->maxNodeset = value;
2297  cache->maxString = value;
2298  cache->maxNumber = value;
2299  cache->maxBoolean = value;
2300  cache->maxMisc = value;
2301  }
2302  } else if (ctxt->cache != NULL) {
2303  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2304  ctxt->cache = NULL;
2305  }
2306  return(0);
2307 }
2308 
2319 static xmlXPathObjectPtr
2320 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2321 {
2322  if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2323  xmlXPathContextCachePtr cache =
2324  (xmlXPathContextCachePtr) ctxt->cache;
2325 
2326  if ((cache->miscObjs != NULL) &&
2327  (cache->miscObjs->number != 0))
2328  {
2329  xmlXPathObjectPtr ret;
2330 
2331  ret = (xmlXPathObjectPtr)
2332  cache->miscObjs->items[--cache->miscObjs->number];
2333  ret->type = XPATH_NODESET;
2334  ret->nodesetval = val;
2335 #ifdef XP_DEBUG_OBJ_USAGE
2336  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2337 #endif
2338  return(ret);
2339  }
2340  }
2341 
2342  return(xmlXPathWrapNodeSet(val));
2343 
2344 }
2345 
2356 static xmlXPathObjectPtr
2357 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2358 {
2359  if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2360  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2361 
2362  if ((cache->stringObjs != NULL) &&
2363  (cache->stringObjs->number != 0))
2364  {
2365 
2366  xmlXPathObjectPtr ret;
2367 
2368  ret = (xmlXPathObjectPtr)
2369  cache->stringObjs->items[--cache->stringObjs->number];
2370  ret->type = XPATH_STRING;
2371  ret->stringval = val;
2372 #ifdef XP_DEBUG_OBJ_USAGE
2373  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2374 #endif
2375  return(ret);
2376  } else if ((cache->miscObjs != NULL) &&
2377  (cache->miscObjs->number != 0))
2378  {
2379  xmlXPathObjectPtr ret;
2380  /*
2381  * Fallback to misc-cache.
2382  */
2383  ret = (xmlXPathObjectPtr)
2384  cache->miscObjs->items[--cache->miscObjs->number];
2385 
2386  ret->type = XPATH_STRING;
2387  ret->stringval = val;
2388 #ifdef XP_DEBUG_OBJ_USAGE
2389  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2390 #endif
2391  return(ret);
2392  }
2393  }
2394  return(xmlXPathWrapString(val));
2395 }
2396 
2408 static xmlXPathObjectPtr
2409 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2410 {
2411  if ((ctxt != NULL) && (ctxt->cache)) {
2412  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2413 
2414  if ((cache->nodesetObjs != NULL) &&
2415  (cache->nodesetObjs->number != 0))
2416  {
2417  xmlXPathObjectPtr ret;
2418  /*
2419  * Use the nodeset-cache.
2420  */
2421  ret = (xmlXPathObjectPtr)
2422  cache->nodesetObjs->items[--cache->nodesetObjs->number];
2423  ret->type = XPATH_NODESET;
2424  ret->boolval = 0;
2425  if (val) {
2426  if ((ret->nodesetval->nodeMax == 0) ||
2427  (val->type == XML_NAMESPACE_DECL))
2428  {
2429  /* TODO: Check memory error. */
2430  xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2431  } else {
2432  ret->nodesetval->nodeTab[0] = val;
2433  ret->nodesetval->nodeNr = 1;
2434  }
2435  }
2436 #ifdef XP_DEBUG_OBJ_USAGE
2437  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2438 #endif
2439  return(ret);
2440  } else if ((cache->miscObjs != NULL) &&
2441  (cache->miscObjs->number != 0))
2442  {
2443  xmlXPathObjectPtr ret;
2444  /*
2445  * Fallback to misc-cache.
2446  */
2447 
2448  ret = (xmlXPathObjectPtr)
2449  cache->miscObjs->items[--cache->miscObjs->number];
2450 
2451  ret->type = XPATH_NODESET;
2452  ret->boolval = 0;
2453  ret->nodesetval = xmlXPathNodeSetCreate(val);
2454  if (ret->nodesetval == NULL) {
2455  ctxt->lastError.domain = XML_FROM_XPATH;
2456  ctxt->lastError.code = XML_ERR_NO_MEMORY;
2457  return(NULL);
2458  }
2459 #ifdef XP_DEBUG_OBJ_USAGE
2460  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2461 #endif
2462  return(ret);
2463  }
2464  }
2465  return(xmlXPathNewNodeSet(val));
2466 }
2467 
2478 static xmlXPathObjectPtr
2479 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2480 {
2481  if ((ctxt != NULL) && (ctxt->cache)) {
2482  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2483 
2484  if ((cache->stringObjs != NULL) &&
2485  (cache->stringObjs->number != 0))
2486  {
2487  xmlXPathObjectPtr ret;
2488 
2489  ret = (xmlXPathObjectPtr)
2490  cache->stringObjs->items[--cache->stringObjs->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  } else if ((cache->miscObjs != NULL) &&
2499  (cache->miscObjs->number != 0))
2500  {
2501  xmlXPathObjectPtr ret;
2502 
2503  ret = (xmlXPathObjectPtr)
2504  cache->miscObjs->items[--cache->miscObjs->number];
2505 
2506  ret->type = XPATH_STRING;
2507  ret->stringval = xmlStrdup(BAD_CAST val);
2508 #ifdef XP_DEBUG_OBJ_USAGE
2509  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2510 #endif
2511  return(ret);
2512  }
2513  }
2514  return(xmlXPathNewCString(val));
2515 }
2516 
2527 static xmlXPathObjectPtr
2528 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2529 {
2530  if ((ctxt != NULL) && (ctxt->cache)) {
2531  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2532 
2533  if ((cache->stringObjs != NULL) &&
2534  (cache->stringObjs->number != 0))
2535  {
2536  xmlXPathObjectPtr ret;
2537 
2538  ret = (xmlXPathObjectPtr)
2539  cache->stringObjs->items[--cache->stringObjs->number];
2540  ret->type = XPATH_STRING;
2541  if (val != NULL)
2542  ret->stringval = xmlStrdup(val);
2543  else
2544  ret->stringval = xmlStrdup((const xmlChar *)"");
2545 #ifdef XP_DEBUG_OBJ_USAGE
2546  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2547 #endif
2548  return(ret);
2549  } else if ((cache->miscObjs != NULL) &&
2550  (cache->miscObjs->number != 0))
2551  {
2552  xmlXPathObjectPtr ret;
2553 
2554  ret = (xmlXPathObjectPtr)
2555  cache->miscObjs->items[--cache->miscObjs->number];
2556 
2557  ret->type = XPATH_STRING;
2558  if (val != NULL)
2559  ret->stringval = xmlStrdup(val);
2560  else
2561  ret->stringval = xmlStrdup((const xmlChar *)"");
2562 #ifdef XP_DEBUG_OBJ_USAGE
2563  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2564 #endif
2565  return(ret);
2566  }
2567  }
2568  return(xmlXPathNewString(val));
2569 }
2570 
2581 static xmlXPathObjectPtr
2582 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2583 {
2584  if ((ctxt != NULL) && (ctxt->cache)) {
2585  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2586 
2587  if ((cache->booleanObjs != NULL) &&
2588  (cache->booleanObjs->number != 0))
2589  {
2590  xmlXPathObjectPtr ret;
2591 
2592  ret = (xmlXPathObjectPtr)
2593  cache->booleanObjs->items[--cache->booleanObjs->number];
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  } else if ((cache->miscObjs != NULL) &&
2601  (cache->miscObjs->number != 0))
2602  {
2603  xmlXPathObjectPtr ret;
2604 
2605  ret = (xmlXPathObjectPtr)
2606  cache->miscObjs->items[--cache->miscObjs->number];
2607 
2608  ret->type = XPATH_BOOLEAN;
2609  ret->boolval = (val != 0);
2610 #ifdef XP_DEBUG_OBJ_USAGE
2611  xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2612 #endif
2613  return(ret);
2614  }
2615  }
2616  return(xmlXPathNewBoolean(val));
2617 }
2618 
2629 static xmlXPathObjectPtr
2630 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2631 {
2632  if ((ctxt != NULL) && (ctxt->cache)) {
2633  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2634 
2635  if ((cache->numberObjs != NULL) &&
2636  (cache->numberObjs->number != 0))
2637  {
2638  xmlXPathObjectPtr ret;
2639 
2640  ret = (xmlXPathObjectPtr)
2641  cache->numberObjs->items[--cache->numberObjs->number];
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  } else if ((cache->miscObjs != NULL) &&
2649  (cache->miscObjs->number != 0))
2650  {
2651  xmlXPathObjectPtr ret;
2652 
2653  ret = (xmlXPathObjectPtr)
2654  cache->miscObjs->items[--cache->miscObjs->number];
2655 
2656  ret->type = XPATH_NUMBER;
2657  ret->floatval = val;
2658 #ifdef XP_DEBUG_OBJ_USAGE
2659  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2660 #endif
2661  return(ret);
2662  }
2663  }
2664  return(xmlXPathNewFloat(val));
2665 }
2666 
2679 static xmlXPathObjectPtr
2680 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2681  xmlChar *res = NULL;
2682 
2683  if (val == NULL)
2684  return(xmlXPathCacheNewCString(ctxt, ""));
2685 
2686  switch (val->type) {
2687  case XPATH_UNDEFINED:
2688 #ifdef DEBUG_EXPR
2689  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2690 #endif
2691  break;
2692  case XPATH_NODESET:
2693  case XPATH_XSLT_TREE:
2694  res = xmlXPathCastNodeSetToString(val->nodesetval);
2695  break;
2696  case XPATH_STRING:
2697  return(val);
2698  case XPATH_BOOLEAN:
2699  res = xmlXPathCastBooleanToString(val->boolval);
2700  break;
2701  case XPATH_NUMBER:
2702  res = xmlXPathCastNumberToString(val->floatval);
2703  break;
2704  case XPATH_USERS:
2705  case XPATH_POINT:
2706  case XPATH_RANGE:
2707  case XPATH_LOCATIONSET:
2708  TODO;
2709  break;
2710  }
2711  xmlXPathReleaseObject(ctxt, val);
2712  if (res == NULL)
2713  return(xmlXPathCacheNewCString(ctxt, ""));
2714  return(xmlXPathCacheWrapString(ctxt, res));
2715 }
2716 
2727 static xmlXPathObjectPtr
2728 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2729 {
2730  if (val == NULL)
2731  return(NULL);
2732 
2733  if (XP_HAS_CACHE(ctxt)) {
2734  switch (val->type) {
2735  case XPATH_NODESET:
2736  return(xmlXPathCacheWrapNodeSet(ctxt,
2737  xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2738  case XPATH_STRING:
2739  return(xmlXPathCacheNewString(ctxt, val->stringval));
2740  case XPATH_BOOLEAN:
2741  return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2742  case XPATH_NUMBER:
2743  return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2744  default:
2745  break;
2746  }
2747  }
2748  return(xmlXPathObjectCopy(val));
2749 }
2750 
2762 static xmlXPathObjectPtr
2763 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2764  xmlXPathObjectPtr ret;
2765 
2766  if (val == NULL)
2767  return(xmlXPathCacheNewBoolean(ctxt, 0));
2768  if (val->type == XPATH_BOOLEAN)
2769  return(val);
2770  ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2771  xmlXPathReleaseObject(ctxt, val);
2772  return(ret);
2773 }
2774 
2786 static xmlXPathObjectPtr
2787 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2788  xmlXPathObjectPtr ret;
2789 
2790  if (val == NULL)
2791  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2792  if (val->type == XPATH_NUMBER)
2793  return(val);
2794  ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2795  xmlXPathReleaseObject(ctxt, val);
2796  return(ret);
2797 }
2798 
2799 /************************************************************************
2800  * *
2801  * Parser stacks related functions and macros *
2802  * *
2803  ************************************************************************/
2804 
2813 static int
2814 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2815  int ret;
2816 
2817  if (ctxt == NULL)
2818  return(0);
2819  ret = ctxt->valueFrame;
2820  ctxt->valueFrame = ctxt->valueNr;
2821  return(ret);
2822 }
2823 
2831 static void
2832 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2833  if (ctxt == NULL)
2834  return;
2835  if (ctxt->valueNr < ctxt->valueFrame) {
2836  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2837  }
2838  ctxt->valueFrame = frame;
2839 }
2840 
2849 xmlXPathObjectPtr
2850 valuePop(xmlXPathParserContextPtr ctxt)
2851 {
2852  xmlXPathObjectPtr ret;
2853 
2854  if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2855  return (NULL);
2856 
2857  if (ctxt->valueNr <= ctxt->valueFrame) {
2858  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2859  return (NULL);
2860  }
2861 
2862  ctxt->valueNr--;
2863  if (ctxt->valueNr > 0)
2864  ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2865  else
2866  ctxt->value = NULL;
2867  ret = ctxt->valueTab[ctxt->valueNr];
2868  ctxt->valueTab[ctxt->valueNr] = NULL;
2869  return (ret);
2870 }
2881 int
2882 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2883 {
2884  if (ctxt == NULL) return(-1);
2885  if (value == NULL) {
2886  /*
2887  * A NULL value typically indicates that a memory allocation failed,
2888  * so we set ctxt->error here to propagate the error.
2889  */
2890  ctxt->error = XPATH_MEMORY_ERROR;
2891  return(-1);
2892  }
2893  if (ctxt->valueNr >= ctxt->valueMax) {
2894  xmlXPathObjectPtr *tmp;
2895 
2896  if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2897  xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2898  return (-1);
2899  }
2900  tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2901  2 * ctxt->valueMax *
2902  sizeof(ctxt->valueTab[0]));
2903  if (tmp == NULL) {
2904  xmlXPathPErrMemory(ctxt, "pushing value\n");
2905  return (-1);
2906  }
2907  ctxt->valueMax *= 2;
2908  ctxt->valueTab = tmp;
2909  }
2910  ctxt->valueTab[ctxt->valueNr] = value;
2911  ctxt->value = value;
2912  return (ctxt->valueNr++);
2913 }
2914 
2924 int
2925 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2926  xmlXPathObjectPtr obj;
2927  int ret;
2928 
2929  obj = valuePop(ctxt);
2930  if (obj == NULL) {
2931  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2932  return(0);
2933  }
2934  if (obj->type != XPATH_BOOLEAN)
2935  ret = xmlXPathCastToBoolean(obj);
2936  else
2937  ret = obj->boolval;
2938  xmlXPathReleaseObject(ctxt->context, obj);
2939  return(ret);
2940 }
2941 
2951 double
2952 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2953  xmlXPathObjectPtr obj;
2954  double ret;
2955 
2956  obj = valuePop(ctxt);
2957  if (obj == NULL) {
2958  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959  return(0);
2960  }
2961  if (obj->type != XPATH_NUMBER)
2962  ret = xmlXPathCastToNumber(obj);
2963  else
2964  ret = obj->floatval;
2965  xmlXPathReleaseObject(ctxt->context, obj);
2966  return(ret);
2967 }
2968 
2978 xmlChar *
2979 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2980  xmlXPathObjectPtr obj;
2981  xmlChar * ret;
2982 
2983  obj = valuePop(ctxt);
2984  if (obj == NULL) {
2985  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986  return(NULL);
2987  }
2988  ret = xmlXPathCastToString(obj); /* this does required strdup */
2989  /* TODO: needs refactoring somewhere else */
2990  if (obj->stringval == ret)
2991  obj->stringval = NULL;
2992  xmlXPathReleaseObject(ctxt->context, obj);
2993  return(ret);
2994 }
2995 
3005 xmlNodeSetPtr
3006 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3007  xmlXPathObjectPtr obj;
3008  xmlNodeSetPtr ret;
3009 
3010  if (ctxt == NULL) return(NULL);
3011  if (ctxt->value == NULL) {
3012  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3013  return(NULL);
3014  }
3015  if (!xmlXPathStackIsNodeSet(ctxt)) {
3016  xmlXPathSetTypeError(ctxt);
3017  return(NULL);
3018  }
3019  obj = valuePop(ctxt);
3020  ret = obj->nodesetval;
3021 #if 0
3022  /* to fix memory leak of not clearing obj->user */
3023  if (obj->boolval && obj->user != NULL)
3024  xmlFreeNodeList((xmlNodePtr) obj->user);
3025 #endif
3026  obj->nodesetval = NULL;
3027  xmlXPathReleaseObject(ctxt->context, obj);
3028  return(ret);
3029 }
3030 
3040 void *
3041 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3042  xmlXPathObjectPtr obj;
3043  void * ret;
3044 
3045  if ((ctxt == NULL) || (ctxt->value == NULL)) {
3046  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3047  return(NULL);
3048  }
3049  if (ctxt->value->type != XPATH_USERS) {
3050  xmlXPathSetTypeError(ctxt);
3051  return(NULL);
3052  }
3053  obj = valuePop(ctxt);
3054  ret = obj->user;
3055  obj->user = NULL;
3056  xmlXPathReleaseObject(ctxt->context, obj);
3057  return(ret);
3058 }
3059 
3060 /*
3061  * Macros for accessing the content. Those should be used only by the parser,
3062  * and not exported.
3063  *
3064  * Dirty macros, i.e. one need to make assumption on the context to use them
3065  *
3066  * CUR_PTR return the current pointer to the xmlChar to be parsed.
3067  * CUR returns the current xmlChar value, i.e. a 8 bit value
3068  * in ISO-Latin or UTF-8.
3069  * This should be used internally by the parser
3070  * only to compare to ASCII values otherwise it would break when
3071  * running with UTF-8 encoding.
3072  * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3073  * to compare on ASCII based substring.
3074  * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3075  * strings within the parser.
3076  * CURRENT Returns the current char value, with the full decoding of
3077  * UTF-8 if we are using this mode. It returns an int.
3078  * NEXT Skip to the next character, this does the proper decoding
3079  * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3080  * It returns the pointer to the current xmlChar.
3081  */
3082 
3083 #define CUR (*ctxt->cur)
3084 #define SKIP(val) ctxt->cur += (val)
3085 #define NXT(val) ctxt->cur[(val)]
3086 #define CUR_PTR ctxt->cur
3087 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3088 
3089 #define COPY_BUF(l,b,i,v) \
3090  if (l == 1) b[i++] = (xmlChar) v; \
3091  else i += xmlCopyChar(l,&b[i],v)
3092 
3093 #define NEXTL(l) ctxt->cur += l
3094 
3095 #define SKIP_BLANKS \
3096  while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3097 
3098 #define CURRENT (*ctxt->cur)
3099 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3100 
3101 
3102 #ifndef DBL_DIG
3103 #define DBL_DIG 16
3104 #endif
3105 #ifndef DBL_EPSILON
3106 #define DBL_EPSILON 1E-9
3107 #endif
3108 
3109 #define UPPER_DOUBLE 1E9
3110 #define LOWER_DOUBLE 1E-5
3111 #define LOWER_DOUBLE_EXP 5
3112 
3113 #define INTEGER_DIGITS DBL_DIG
3114 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3115 #define EXPONENT_DIGITS (3 + 2)
3116 
3125 static void
3126 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3127 {
3128  switch (xmlXPathIsInf(number)) {
3129  case 1:
3130  if (buffersize > (int)sizeof("Infinity"))
3131  snprintf(buffer, buffersize, "Infinity");
3132  break;
3133  case -1:
3134  if (buffersize > (int)sizeof("-Infinity"))
3135  snprintf(buffer, buffersize, "-Infinity");
3136  break;
3137  default:
3138  if (xmlXPathIsNaN(number)) {
3139  if (buffersize > (int)sizeof("NaN"))
3140  snprintf(buffer, buffersize, "NaN");
3141  } else if (number == 0) {
3142  /* Omit sign for negative zero. */
3143  snprintf(buffer, buffersize, "0");
3144  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3145  (number == (int) number)) {
3146  char work[30];
3147  char *ptr, *cur;
3148  int value = (int) number;
3149 
3150  ptr = &buffer[0];
3151  if (value == 0) {
3152  *ptr++ = '0';
3153  } else {
3154  snprintf(work, 29, "%d", value);
3155  cur = &work[0];
3156  while ((*cur) && (ptr - buffer < buffersize)) {
3157  *ptr++ = *cur++;
3158  }
3159  }
3160  if (ptr - buffer < buffersize) {
3161  *ptr = 0;
3162  } else if (buffersize > 0) {
3163  ptr--;
3164  *ptr = 0;
3165  }
3166  } else {
3167  /*
3168  For the dimension of work,
3169  DBL_DIG is number of significant digits
3170  EXPONENT is only needed for "scientific notation"
3171  3 is sign, decimal point, and terminating zero
3172  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3173  Note that this dimension is slightly (a few characters)
3174  larger than actually necessary.
3175  */
3176  char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3177  int integer_place, fraction_place;
3178  char *ptr;
3179  char *after_fraction;
3180  double absolute_value;
3181  int size;
3182 
3183  absolute_value = fabs(number);
3184 
3185  /*
3186  * First choose format - scientific or regular floating point.
3187  * In either case, result is in work, and after_fraction points
3188  * just past the fractional part.
3189  */
3190  if ( ((absolute_value > UPPER_DOUBLE) ||
3191  (absolute_value < LOWER_DOUBLE)) &&
3192  (absolute_value != 0.0) ) {
3193  /* Use scientific notation */
3194  integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3195  fraction_place = DBL_DIG - 1;
3196  size = snprintf(work, sizeof(work),"%*.*e",
3197  integer_place, fraction_place, number);
3198  while ((size > 0) && (work[size] != 'e')) size--;
3199 
3200  }
3201  else {
3202  /* Use regular notation */
3203  if (absolute_value > 0.0) {
3204  integer_place = (int)log10(absolute_value);
3205  if (integer_place > 0)
3206  fraction_place = DBL_DIG - integer_place - 1;
3207  else
3208  fraction_place = DBL_DIG - integer_place;
3209  } else {
3210  fraction_place = 1;
3211  }
3212  size = snprintf(work, sizeof(work), "%0.*f",
3213  fraction_place, number);
3214  }
3215 
3216  /* Remove leading spaces sometimes inserted by snprintf */
3217  while (work[0] == ' ') {
3218  for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3219  size--;
3220  }
3221 
3222  /* Remove fractional trailing zeroes */
3223  after_fraction = work + size;
3224  ptr = after_fraction;
3225  while (*(--ptr) == '0')
3226  ;
3227  if (*ptr != '.')
3228  ptr++;
3229  while ((*ptr++ = *after_fraction++) != 0);
3230 
3231  /* Finally copy result back to caller */
3232  size = strlen(work) + 1;
3233  if (size > buffersize) {
3234  work[buffersize - 1] = 0;
3235  size = buffersize;
3236  }
3237  memmove(buffer, work, size);
3238  }
3239  break;
3240  }
3241 }
3242 
3243 
3244 /************************************************************************
3245  * *
3246  * Routines to handle NodeSets *
3247  * *
3248  ************************************************************************/
3249 
3263 long
3264 xmlXPathOrderDocElems(xmlDocPtr doc) {
3265  ptrdiff_t count = 0;
3266  xmlNodePtr cur;
3267 
3268  if (doc == NULL)
3269  return(-1);
3270  cur = doc->children;
3271  while (cur != NULL) {
3272  if (cur->type == XML_ELEMENT_NODE) {
3273  cur->content = (void *) (-(++count));
3274  if (cur->children != NULL) {
3275  cur = cur->children;
3276  continue;
3277  }
3278  }
3279  if (cur->next != NULL) {
3280  cur = cur->next;
3281  continue;
3282  }
3283  do {
3284  cur = cur->parent;
3285  if (cur == NULL)
3286  break;
3287  if (cur == (xmlNodePtr) doc) {
3288  cur = NULL;
3289  break;
3290  }
3291  if (cur->next != NULL) {
3292  cur = cur->next;
3293  break;
3294  }
3295  } while (cur != NULL);
3296  }
3297  return((long) count);
3298 }
3299 
3310 int
3311 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3312  int depth1, depth2;
3313  int attr1 = 0, attr2 = 0;
3314  xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3315  xmlNodePtr cur, root;
3316 
3317  if ((node1 == NULL) || (node2 == NULL))
3318  return(-2);
3319  /*
3320  * a couple of optimizations which will avoid computations in most cases
3321  */
3322  if (node1 == node2) /* trivial case */
3323  return(0);
3324  if (node1->type == XML_ATTRIBUTE_NODE) {
3325  attr1 = 1;
3326  attrNode1 = node1;
3327  node1 = node1->parent;
3328  }
3329  if (node2->type == XML_ATTRIBUTE_NODE) {
3330  attr2 = 1;
3331  attrNode2 = node2;
3332  node2 = node2->parent;
3333  }
3334  if (node1 == node2) {
3335  if (attr1 == attr2) {
3336  /* not required, but we keep attributes in order */
3337  if (attr1 != 0) {
3338  cur = attrNode2->prev;
3339  while (cur != NULL) {
3340  if (cur == attrNode1)
3341  return (1);
3342  cur = cur->prev;
3343  }
3344  return (-1);
3345  }
3346  return(0);
3347  }
3348  if (attr2 == 1)
3349  return(1);
3350  return(-1);
3351  }
3352  if ((node1->type == XML_NAMESPACE_DECL) ||
3353  (node2->type == XML_NAMESPACE_DECL))
3354  return(1);
3355  if (node1 == node2->prev)
3356  return(1);
3357  if (node1 == node2->next)
3358  return(-1);
3359 
3360  /*
3361  * Speedup using document order if available.
3362  */
3363  if ((node1->type == XML_ELEMENT_NODE) &&
3364  (node2->type == XML_ELEMENT_NODE) &&
3365  (0 > (ptrdiff_t) node1->content) &&
3366  (0 > (ptrdiff_t) node2->content) &&
3367  (node1->doc == node2->doc)) {
3368  ptrdiff_t l1, l2;
3369 
3370  l1 = -((ptrdiff_t) node1->content);
3371  l2 = -((ptrdiff_t) node2->content);
3372  if (l1 < l2)
3373  return(1);
3374  if (l1 > l2)
3375  return(-1);
3376  }
3377 
3378  /*
3379  * compute depth to root
3380  */
3381  for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3382  if (cur->parent == node1)
3383  return(1);
3384  depth2++;
3385  }
3386  root = cur;
3387  for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3388  if (cur->parent == node2)
3389  return(-1);
3390  depth1++;
3391  }
3392  /*
3393  * Distinct document (or distinct entities :-( ) case.
3394  */
3395  if (root != cur) {
3396  return(-2);
3397  }
3398  /*
3399  * get the nearest common ancestor.
3400  */
3401  while (depth1 > depth2) {
3402  depth1--;
3403  node1 = node1->parent;
3404  }
3405  while (depth2 > depth1) {
3406  depth2--;
3407  node2 = node2->parent;
3408  }
3409  while (node1->parent != node2->parent) {
3410  node1 = node1->parent;
3411  node2 = node2->parent;
3412  /* should not happen but just in case ... */
3413  if ((node1 == NULL) || (node2 == NULL))
3414  return(-2);
3415  }
3416  /*
3417  * Find who's first.
3418  */
3419  if (node1 == node2->prev)
3420  return(1);
3421  if (node1 == node2->next)
3422  return(-1);
3423  /*
3424  * Speedup using document order if available.
3425  */
3426  if ((node1->type == XML_ELEMENT_NODE) &&
3427  (node2->type == XML_ELEMENT_NODE) &&
3428  (0 > (ptrdiff_t) node1->content) &&
3429  (0 > (ptrdiff_t) node2->content) &&
3430  (node1->doc == node2->doc)) {
3431  ptrdiff_t l1, l2;
3432 
3433  l1 = -((ptrdiff_t) node1->content);
3434  l2 = -((ptrdiff_t) node2->content);
3435  if (l1 < l2)
3436  return(1);
3437  if (l1 > l2)
3438  return(-1);
3439  }
3440 
3441  for (cur = node1->next;cur != NULL;cur = cur->next)
3442  if (cur == node2)
3443  return(1);
3444  return(-1); /* assume there is no sibling list corruption */
3445 }
3446 
3453 void
3454 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3455 #ifndef WITH_TIM_SORT
3456  int i, j, incr, len;
3457  xmlNodePtr tmp;
3458 #endif
3459 
3460  if (set == NULL)
3461  return;
3462 
3463 #ifndef WITH_TIM_SORT
3464  /*
3465  * Use the old Shell's sort implementation to sort the node-set
3466  * Timsort ought to be quite faster
3467  */
3468  len = set->nodeNr;
3469  for (incr = len / 2; incr > 0; incr /= 2) {
3470  for (i = incr; i < len; i++) {
3471  j = i - incr;
3472  while (j >= 0) {
3473 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3474  if (xmlXPathCmpNodesExt(set->nodeTab[j],
3475  set->nodeTab[j + incr]) == -1)
3476 #else
3477  if (xmlXPathCmpNodes(set->nodeTab[j],
3478  set->nodeTab[j + incr]) == -1)
3479 #endif
3480  {
3481  tmp = set->nodeTab[j];
3482  set->nodeTab[j] = set->nodeTab[j + incr];
3483  set->nodeTab[j + incr] = tmp;
3484  j -= incr;
3485  } else
3486  break;
3487  }
3488  }
3489  }
3490 #else /* WITH_TIM_SORT */
3491  libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3492 #endif /* WITH_TIM_SORT */
3493 }
3494 
3495 #define XML_NODESET_DEFAULT 10
3496 
3507 static xmlNodePtr
3508 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3509  xmlNsPtr cur;
3510 
3511  if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3512  return(NULL);
3513  if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3514  return((xmlNodePtr) ns);
3515 
3516  /*
3517  * Allocate a new Namespace and fill the fields.
3518  */
3519  cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3520  if (cur == NULL) {
3521  xmlXPathErrMemory(NULL, "duplicating namespace\n");
3522  return(NULL);
3523  }
3524  memset(cur, 0, sizeof(xmlNs));
3525  cur->type = XML_NAMESPACE_DECL;
3526  if (ns->href != NULL)
3527  cur->href = xmlStrdup(ns->href);
3528  if (ns->prefix != NULL)
3529  cur->prefix = xmlStrdup(ns->prefix);
3530  cur->next = (xmlNsPtr) node;
3531  return((xmlNodePtr) cur);
3532 }
3533 
3542 void
3543 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3544  if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3545  return;
3546 
3547  if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3548  if (ns->href != NULL)
3549  xmlFree((xmlChar *)ns->href);
3550  if (ns->prefix != NULL)
3551  xmlFree((xmlChar *)ns->prefix);
3552  xmlFree(ns);
3553  }
3554 }
3555 
3564 xmlNodeSetPtr
3565 xmlXPathNodeSetCreate(xmlNodePtr val) {
3566  xmlNodeSetPtr ret;
3567 
3568  ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3569  if (ret == NULL) {
3570  xmlXPathErrMemory(NULL, "creating nodeset\n");
3571  return(NULL);
3572  }
3573  memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3574  if (val != NULL) {
3575  ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3576  sizeof(xmlNodePtr));
3577  if (ret->nodeTab == NULL) {
3578  xmlXPathErrMemory(NULL, "creating nodeset\n");
3579  xmlFree(ret);
3580  return(NULL);
3581  }
3582  memset(ret->nodeTab, 0 ,
3583  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3584  ret->nodeMax = XML_NODESET_DEFAULT;
3585  if (val->type == XML_NAMESPACE_DECL) {
3586  xmlNsPtr ns = (xmlNsPtr) val;
3587 
3588  /* TODO: Check memory error. */
3589  ret->nodeTab[ret->nodeNr++] =
3590  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3591  } else
3592  ret->nodeTab[ret->nodeNr++] = val;
3593  }
3594  return(ret);
3595 }
3596 
3606 int
3607 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3608  int i;
3609 
3610  if ((cur == NULL) || (val == NULL)) return(0);
3611  if (val->type == XML_NAMESPACE_DECL) {
3612  for (i = 0; i < cur->nodeNr; i++) {
3613  if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3614  xmlNsPtr ns1, ns2;
3615 
3616  ns1 = (xmlNsPtr) val;
3617  ns2 = (xmlNsPtr) cur->nodeTab[i];
3618  if (ns1 == ns2)
3619  return(1);
3620  if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3621  (xmlStrEqual(ns1->prefix, ns2->prefix)))
3622  return(1);
3623  }
3624  }
3625  } else {
3626  for (i = 0; i < cur->nodeNr; i++) {
3627  if (cur->nodeTab[i] == val)
3628  return(1);
3629  }
3630  }
3631  return(0);
3632 }
3633 
3644 int
3645 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3646  int i;
3647 
3648 
3649  if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3650  (ns->type != XML_NAMESPACE_DECL) ||
3651  (node->type != XML_ELEMENT_NODE))
3652  return(-1);
3653 
3654  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3655  /*
3656  * prevent duplicates
3657  */
3658  for (i = 0;i < cur->nodeNr;i++) {
3659  if ((cur->nodeTab[i] != NULL) &&
3660  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3661  (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3662  (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3663  return(0);
3664  }
3665 
3666  /*
3667  * grow the nodeTab if needed
3668  */
3669  if (cur->nodeMax == 0) {
3670  cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3671  sizeof(xmlNodePtr));
3672  if (cur->nodeTab == NULL) {
3673  xmlXPathErrMemory(NULL, "growing nodeset\n");
3674  return(-1);
3675  }
3676  memset(cur->nodeTab, 0 ,
3677  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3678  cur->nodeMax = XML_NODESET_DEFAULT;
3679  } else if (cur->nodeNr == cur->nodeMax) {
3680  xmlNodePtr *temp;
3681 
3682  if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3683  xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3684  return(-1);
3685  }
3686  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3687  sizeof(xmlNodePtr));
3688  if (temp == NULL) {
3689  xmlXPathErrMemory(NULL, "growing nodeset\n");
3690  return(-1);
3691  }
3692  cur->nodeMax *= 2;
3693  cur->nodeTab = temp;
3694  }
3695  /* TODO: Check memory error. */
3696  cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3697  return(0);
3698 }
3699 
3709 int
3710 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3711  int i;
3712 
3713  if ((cur == NULL) || (val == NULL)) return(-1);
3714 
3715  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3716  /*
3717  * prevent duplicates
3718  */
3719  for (i = 0;i < cur->nodeNr;i++)
3720  if (cur->nodeTab[i] == val) return(0);
3721 
3722  /*
3723  * grow the nodeTab if needed
3724  */
3725  if (cur->nodeMax == 0) {
3726  cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3727  sizeof(xmlNodePtr));
3728  if (cur->nodeTab == NULL) {
3729  xmlXPathErrMemory(NULL, "growing nodeset\n");
3730  return(-1);
3731  }
3732  memset(cur->nodeTab, 0 ,
3733  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3734  cur->nodeMax = XML_NODESET_DEFAULT;
3735  } else if (cur->nodeNr == cur->nodeMax) {
3736  xmlNodePtr *temp;
3737 
3738  if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3739  xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3740  return(-1);
3741  }
3742  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3743  sizeof(xmlNodePtr));
3744  if (temp == NULL) {
3745  xmlXPathErrMemory(NULL, "growing nodeset\n");
3746  return(-1);
3747  }
3748  cur->nodeMax *= 2;
3749  cur->nodeTab = temp;
3750  }
3751  if (val->type == XML_NAMESPACE_DECL) {
3752  xmlNsPtr ns = (xmlNsPtr) val;
3753 
3754  /* TODO: Check memory error. */
3755  cur->nodeTab[cur->nodeNr++] =
3756  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3757  } else
3758  cur->nodeTab[cur->nodeNr++] = val;
3759  return(0);
3760 }
3761 
3772 int
3773 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3774  if ((cur == NULL) || (val == NULL)) return(-1);
3775 
3776  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3777  /*
3778  * grow the nodeTab if needed
3779  */
3780  if (cur->nodeMax == 0) {
3781  cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3782  sizeof(xmlNodePtr));
3783  if (cur->nodeTab == NULL) {
3784  xmlXPathErrMemory(NULL, "growing nodeset\n");
3785  return(-1);
3786  }
3787  memset(cur->nodeTab, 0 ,
3788  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3789  cur->nodeMax = XML_NODESET_DEFAULT;
3790  } else if (cur->nodeNr == cur->nodeMax) {
3791  xmlNodePtr *temp;
3792 
3793  if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3794  xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3795  return(-1);
3796  }
3797  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3798  sizeof(xmlNodePtr));
3799  if (temp == NULL) {
3800  xmlXPathErrMemory(NULL, "growing nodeset\n");
3801  return(-1);
3802  }
3803  cur->nodeTab = temp;
3804  cur->nodeMax *= 2;
3805  }
3806  if (val->type == XML_NAMESPACE_DECL) {
3807  xmlNsPtr ns = (xmlNsPtr) val;
3808 
3809  /* TODO: Check memory error. */
3810  cur->nodeTab[cur->nodeNr++] =
3811  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3812  } else
3813  cur->nodeTab[cur->nodeNr++] = val;
3814  return(0);
3815 }
3816 
3827 xmlNodeSetPtr
3828 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3829  int i, j, initNr, skip;
3830  xmlNodePtr n1, n2;
3831 
3832  if (val2 == NULL) return(val1);
3833  if (val1 == NULL) {
3834  val1 = xmlXPathNodeSetCreate(NULL);
3835  if (val1 == NULL)
3836  return (NULL);
3837 #if 0
3838  /*
3839  * TODO: The optimization won't work in every case, since
3840  * those nasty namespace nodes need to be added with
3841  * xmlXPathNodeSetDupNs() to the set; thus a pure
3842  * memcpy is not possible.
3843  * If there was a flag on the nodesetval, indicating that
3844  * some temporary nodes are in, that would be helpful.
3845  */
3846  /*
3847  * Optimization: Create an equally sized node-set
3848  * and memcpy the content.
3849  */
3850  val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3851  if (val1 == NULL)
3852  return(NULL);
3853  if (val2->nodeNr != 0) {
3854  if (val2->nodeNr == 1)
3855  *(val1->nodeTab) = *(val2->nodeTab);
3856  else {
3857  memcpy(val1->nodeTab, val2->nodeTab,
3858  val2->nodeNr * sizeof(xmlNodePtr));
3859  }
3860  val1->nodeNr = val2->nodeNr;
3861  }
3862  return(val1);
3863 #endif
3864  }
3865 
3866  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3867  initNr = val1->nodeNr;
3868 
3869  for (i = 0;i < val2->nodeNr;i++) {
3870  n2 = val2->nodeTab[i];
3871  /*
3872  * check against duplicates
3873  */
3874  skip = 0;
3875  for (j = 0; j < initNr; j++) {
3876  n1 = val1->nodeTab[j];
3877  if (n1 == n2) {
3878  skip = 1;
3879  break;
3880  } else if ((n1->type == XML_NAMESPACE_DECL) &&
3881  (n2->type == XML_NAMESPACE_DECL)) {
3882  if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3883  (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3884  ((xmlNsPtr) n2)->prefix)))
3885  {
3886  skip = 1;
3887  break;
3888  }
3889  }
3890  }
3891  if (skip)
3892  continue;
3893 
3894  /*
3895  * grow the nodeTab if needed
3896  */
3897  if (val1->nodeMax == 0) {
3898  val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3899  sizeof(xmlNodePtr));
3900  if (val1->nodeTab == NULL) {
3901  xmlXPathErrMemory(NULL, "merging nodeset\n");
3902  return(NULL);
3903  }
3904  memset(val1->nodeTab, 0 ,
3905  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3906  val1->nodeMax = XML_NODESET_DEFAULT;
3907  } else if (val1->nodeNr == val1->nodeMax) {
3908  xmlNodePtr *temp;
3909 
3910  if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3911  xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3912  return(NULL);
3913  }
3914  temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3915  sizeof(xmlNodePtr));
3916  if (temp == NULL) {
3917  xmlXPathErrMemory(NULL, "merging nodeset\n");
3918  return(NULL);
3919  }
3920  val1->nodeTab = temp;
3921  val1->nodeMax *= 2;
3922  }
3923  if (n2->type == XML_NAMESPACE_DECL) {
3924  xmlNsPtr ns = (xmlNsPtr) n2;
3925 
3926  /* TODO: Check memory error. */
3927  val1->nodeTab[val1->nodeNr++] =
3928  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3929  } else
3930  val1->nodeTab[val1->nodeNr++] = n2;
3931  }
3932 
3933  return(val1);
3934 }
3935 
3936 
3947 static xmlNodeSetPtr
3948 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3949 {
3950  {
3951  int i, j, initNbSet1;
3952  xmlNodePtr n1, n2;
3953 
3954  initNbSet1 = set1->nodeNr;
3955  for (i = 0;i < set2->nodeNr;i++) {
3956  n2 = set2->nodeTab[i];
3957  /*
3958  * Skip duplicates.
3959  */
3960  for (j = 0; j < initNbSet1; j++) {
3961  n1 = set1->nodeTab[j];
3962  if (n1 == n2) {
3963  goto skip_node;
3964  } else if ((n1->type == XML_NAMESPACE_DECL) &&
3965  (n2->type == XML_NAMESPACE_DECL))
3966  {
3967  if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3968  (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3969  ((xmlNsPtr) n2)->prefix)))
3970  {
3971  /*
3972  * Free the namespace node.
3973  */
3974  set2->nodeTab[i] = NULL;
3975  xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3976  goto skip_node;
3977  }
3978  }
3979  }
3980  /*
3981  * grow the nodeTab if needed
3982  */
3983  if (set1->nodeMax == 0) {
3984  set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3985  XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3986  if (set1->nodeTab == NULL) {
3987  xmlXPathErrMemory(NULL, "merging nodeset\n");
3988  return(NULL);
3989  }
3990  memset(set1->nodeTab, 0,
3991  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3992  set1->nodeMax = XML_NODESET_DEFAULT;
3993  } else if (set1->nodeNr >= set1->nodeMax) {
3994  xmlNodePtr *temp;
3995 
3996  if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3997  xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3998  return(NULL);
3999  }
4000  temp = (xmlNodePtr *) xmlRealloc(
4001  set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4002  if (temp == NULL) {
4003  xmlXPathErrMemory(NULL, "merging nodeset\n");
4004  return(NULL);
4005  }
4006  set1->nodeTab = temp;
4007  set1->nodeMax *= 2;
4008  }
4009  set1->nodeTab[set1->nodeNr++] = n2;
4010 skip_node:
4011  {}
4012  }
4013  }
4014  set2->nodeNr = 0;
4015  return(set1);
4016 }
4017 
4028 static xmlNodeSetPtr
4029 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4030 {
4031  {
4032  int i;
4033  xmlNodePtr n2;
4034 
4035  for (i = 0;i < set2->nodeNr;i++) {
4036  n2 = set2->nodeTab[i];
4037  if (set1->nodeMax == 0) {
4038  set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4039  XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4040  if (set1->nodeTab == NULL) {
4041  xmlXPathErrMemory(NULL, "merging nodeset\n");
4042  return(NULL);
4043  }
4044  memset(set1->nodeTab, 0,
4045  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4046  set1->nodeMax = XML_NODESET_DEFAULT;
4047  } else if (set1->nodeNr >= set1->nodeMax) {
4048  xmlNodePtr *temp;
4049 
4050  if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4051  xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4052  return(NULL);
4053  }
4054  temp = (xmlNodePtr *) xmlRealloc(
4055  set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4056  if (temp == NULL) {
4057  xmlXPathErrMemory(NULL, "merging nodeset\n");
4058  return(NULL);
4059  }
4060  set1->nodeTab = temp;
4061  set1->nodeMax *= 2;
4062  }
4063  set1->nodeTab[set1->nodeNr++] = n2;
4064  }
4065  }
4066  set2->nodeNr = 0;
4067  return(set1);
4068 }
4069 
4077 void
4078 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4079  int i;
4080 
4081  if (cur == NULL) return;
4082  if (val == NULL) return;
4083 
4084  /*
4085  * find node in nodeTab
4086  */
4087  for (i = 0;i < cur->nodeNr;i++)
4088  if (cur->nodeTab[i] == val) break;
4089 
4090  if (i >= cur->nodeNr) { /* not found */
4091 #ifdef DEBUG
4093  "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4094  val->name);
4095 #endif
4096  return;
4097  }
4098  if ((cur->nodeTab[i] != NULL) &&
4099  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4100  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4101  cur->nodeNr--;
4102  for (;i < cur->nodeNr;i++)
4103  cur->nodeTab[i] = cur->nodeTab[i + 1];
4104  cur->nodeTab[cur->nodeNr] = NULL;
4105 }
4106 
4114 void
4115 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4116  if (cur == NULL) return;
4117  if (val >= cur->nodeNr) return;
4118  if ((cur->nodeTab[val] != NULL) &&
4119  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4120  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4121  cur->nodeNr--;
4122  for (;val < cur->nodeNr;val++)
4123  cur->nodeTab[val] = cur->nodeTab[val + 1];
4124  cur->nodeTab[cur->nodeNr] = NULL;
4125 }
4126 
4133 void
4134 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4135  if (obj == NULL) return;
4136  if (obj->nodeTab != NULL) {
4137  int i;
4138 
4139  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4140  for (i = 0;i < obj->nodeNr;i++)
4141  if ((obj->nodeTab[i] != NULL) &&
4142  (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4143  xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4144  xmlFree(obj->nodeTab);
4145  }
4146  xmlFree(obj);
4147 }
4148 
4158 static void
4159 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4160 {
4161  if ((set == NULL) || (pos >= set->nodeNr))
4162  return;
4163  else if ((hasNsNodes)) {
4164  int i;
4165  xmlNodePtr node;
4166 
4167  for (i = pos; i < set->nodeNr; i++) {
4168  node = set->nodeTab[i];
4169  if ((node != NULL) &&
4170  (node->type == XML_NAMESPACE_DECL))
4171  xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4172  }
4173  }
4174  set->nodeNr = pos;
4175 }
4176 
4185 static void
4186 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4187 {
4188  xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4189 }
4190 
4199 static void
4200 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4201 {
4202  int i;
4203  xmlNodePtr node;
4204 
4205  if ((set == NULL) || (set->nodeNr <= 1))
4206  return;
4207  for (i = 0; i < set->nodeNr - 1; i++) {
4208  node = set->nodeTab[i];
4209  if ((node != NULL) &&
4210  (node->type == XML_NAMESPACE_DECL))
4211  xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4212  }
4213  set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4214  set->nodeNr = 1;
4215 }
4216 
4224 static void
4225 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4226  int i;
4227 
4228  if (obj == NULL) return;
4229 
4230  if (obj->nodeTab != NULL) {
4231  for (i = 0;i < obj->nodeNr;i++) {
4232  if (obj->nodeTab[i] != NULL) {
4233  if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4234  xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4235  } else {
4236  xmlFreeNodeList(obj->nodeTab[i]);
4237  }
4238  }
4239  }
4240  xmlFree(obj->nodeTab);
4241  }
4242  xmlFree(obj);
4243 }
4244 
4245 #if defined(DEBUG) || defined(DEBUG_STEP)
4246 
4253 void
4254 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4255  int i;
4256 
4258  if (obj == NULL) {
4259  fprintf(output, "NodeSet == NULL !\n");
4260  return;
4261  }
4262  if (obj->nodeNr == 0) {
4263  fprintf(output, "NodeSet is empty\n");
4264  return;
4265  }
4266  if (obj->nodeTab == NULL) {
4267  fprintf(output, " nodeTab == NULL !\n");
4268  return;
4269  }
4270  for (i = 0; i < obj->nodeNr; i++) {
4271  if (obj->nodeTab[i] == NULL) {
4272  fprintf(output, " NULL !\n");
4273  return;
4274  }
4275  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4276  (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4277  fprintf(output, " /");
4278  else if (obj->nodeTab[i]->name == NULL)
4279  fprintf(output, " noname!");
4280  else fprintf(output, " %s", obj->nodeTab[i]->name);
4281  }
4282  fprintf(output, "\n");
4283 }
4284 #endif
4285 
4295 xmlXPathObjectPtr
4296 xmlXPathNewNodeSet(xmlNodePtr val) {
4297  xmlXPathObjectPtr ret;
4298 
4299  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4300  if (ret == NULL) {
4301  xmlXPathErrMemory(NULL, "creating nodeset\n");
4302  return(NULL);
4303  }
4304  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4305  ret->type = XPATH_NODESET;
4306  ret->boolval = 0;
4307  /* TODO: Check memory error. */
4308  ret->nodesetval = xmlXPathNodeSetCreate(val);
4309  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4310 #ifdef XP_DEBUG_OBJ_USAGE
4311  xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4312 #endif
4313  return(ret);
4314 }
4315 
4325 xmlXPathObjectPtr
4326 xmlXPathNewValueTree(xmlNodePtr val) {
4327  xmlXPathObjectPtr ret;
4328 
4329  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4330  if (ret == NULL) {
4331  xmlXPathErrMemory(NULL, "creating result value tree\n");
4332  return(NULL);
4333  }
4334  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4335  ret->type = XPATH_XSLT_TREE;
4336  ret->boolval = 1;
4337  ret->user = (void *) val;
4338  ret->nodesetval = xmlXPathNodeSetCreate(val);
4339 #ifdef XP_DEBUG_OBJ_USAGE
4340  xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4341 #endif
4342  return(ret);
4343 }
4344 
4354 xmlXPathObjectPtr
4355 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4356 {
4357  xmlXPathObjectPtr ret;
4358  int i;
4359 
4360  if (val == NULL)
4361  ret = NULL;
4362  else if (val->nodeTab == NULL)
4363  ret = xmlXPathNewNodeSet(NULL);
4364  else {
4365  ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4366  if (ret) {
4367  for (i = 1; i < val->nodeNr; ++i) {
4368  /* TODO: Propagate memory error. */
4369  if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4370  < 0) break;
4371  }
4372  }
4373  }
4374 
4375  return (ret);
4376 }
4377 
4386 xmlXPathObjectPtr
4387 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4388  xmlXPathObjectPtr ret;
4389 
4390  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4391  if (ret == NULL) {
4392  xmlXPathErrMemory(NULL, "creating node set object\n");
4393  return(NULL);
4394  }
4395  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4396  ret->type = XPATH_NODESET;
4397  ret->nodesetval = val;
4398 #ifdef XP_DEBUG_OBJ_USAGE
4399  xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4400 #endif
4401  return(ret);
4402 }
4403 
4411 void
4412 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4413  if (obj == NULL) return;
4414 #ifdef XP_DEBUG_OBJ_USAGE
4415  xmlXPathDebugObjUsageReleased(NULL, obj->type);
4416 #endif
4417  xmlFree(obj);
4418 }
4419 
4431 xmlNodeSetPtr
4432 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4433  xmlNodeSetPtr ret;
4434  int i, l1;
4435  xmlNodePtr cur;
4436 
4437  if (xmlXPathNodeSetIsEmpty(nodes2))
4438  return(nodes1);
4439 
4440  /* TODO: Check memory error. */
4441  ret = xmlXPathNodeSetCreate(NULL);
4442  if (xmlXPathNodeSetIsEmpty(nodes1))
4443  return(ret);
4444 
4445  l1 = xmlXPathNodeSetGetLength(nodes1);
4446 
4447  for (i = 0; i < l1; i++) {
4448  cur = xmlXPathNodeSetItem(nodes1, i);
4449  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4450  /* TODO: Propagate memory error. */
4451  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4452  break;
4453  }
4454  }
4455  return(ret);
4456 }
4457 
4469 xmlNodeSetPtr
4470 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4471  xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4472  int i, l1;
4473  xmlNodePtr cur;
4474 
4475  if (ret == NULL)
4476  return(ret);
4477  if (xmlXPathNodeSetIsEmpty(nodes1))
4478  return(ret);
4479  if (xmlXPathNodeSetIsEmpty(nodes2))
4480  return(ret);
4481 
4482  l1 = xmlXPathNodeSetGetLength(nodes1);
4483 
4484  for (i = 0; i < l1; i++) {
4485  cur = xmlXPathNodeSetItem(nodes1, i);
4486  if (xmlXPathNodeSetContains(nodes2, cur)) {
4487  /* TODO: Propagate memory error. */
4488  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4489  break;
4490  }
4491  }
4492  return(ret);
4493 }
4494 
4505 xmlNodeSetPtr
4506 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4507  xmlNodeSetPtr ret;
4509  int i, l;
4510  xmlChar * strval;
4511  xmlNodePtr cur;
4512 
4513  if (xmlXPathNodeSetIsEmpty(nodes))
4514  return(nodes);
4515 
4516  ret = xmlXPathNodeSetCreate(NULL);
4517  if (ret == NULL)
4518  return(ret);
4519  l = xmlXPathNodeSetGetLength(nodes);
4520  hash = xmlHashCreate (l);
4521  for (i = 0; i < l; i++) {
4522  cur = xmlXPathNodeSetItem(nodes, i);
4523  strval = xmlXPathCastNodeToString(cur);
4524  if (xmlHashLookup(hash, strval) == NULL) {
4526  /* TODO: Propagate memory error. */
4527  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4528  break;
4529  } else {
4530  xmlFree(strval);
4531  }
4532  }
4534  return(ret);
4535 }
4536 
4549 xmlNodeSetPtr
4550 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4551  if (xmlXPathNodeSetIsEmpty(nodes))
4552  return(nodes);
4553 
4554  xmlXPathNodeSetSort(nodes);
4555  return(xmlXPathDistinctSorted(nodes));
4556 }
4557 
4569 int
4570 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4571  int i, l;
4572  xmlNodePtr cur;
4573 
4574  if (xmlXPathNodeSetIsEmpty(nodes1) ||
4575  xmlXPathNodeSetIsEmpty(nodes2))
4576  return(0);
4577 
4578  l = xmlXPathNodeSetGetLength(nodes1);
4579  for (i = 0; i < l; i++) {
4580  cur = xmlXPathNodeSetItem(nodes1, i);
4581  if (xmlXPathNodeSetContains(nodes2, cur))
4582  return(1);
4583  }
4584  return(0);
4585 }
4586 
4599 xmlNodeSetPtr
4600 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4601  int i, l;
4602  xmlNodePtr cur;
4603  xmlNodeSetPtr ret;
4604 
4605  if (node == NULL)
4606  return(nodes);
4607 
4608  ret = xmlXPathNodeSetCreate(NULL);
4609  if (ret == NULL)
4610  return(ret);
4611  if (xmlXPathNodeSetIsEmpty(nodes) ||
4612  (!xmlXPathNodeSetContains(nodes, node)))
4613  return(ret);
4614 
4615  l = xmlXPathNodeSetGetLength(nodes);
4616  for (i = 0; i < l; i++) {
4617  cur = xmlXPathNodeSetItem(nodes, i);
4618  if (cur == node)
4619  break;
4620  /* TODO: Propagate memory error. */
4621  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4622  break;
4623  }
4624  return(ret);
4625 }
4626 
4641 xmlNodeSetPtr
4642 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4643  xmlXPathNodeSetSort(nodes);
4644  return(xmlXPathNodeLeadingSorted(nodes, node));
4645 }
4646 
4659 xmlNodeSetPtr
4660 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4661  if (xmlXPathNodeSetIsEmpty(nodes2))
4662  return(nodes1);
4663  return(xmlXPathNodeLeadingSorted(nodes1,
4664  xmlXPathNodeSetItem(nodes2, 1)));
4665 }
4666 
4681 xmlNodeSetPtr
4682 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4683  if (xmlXPathNodeSetIsEmpty(nodes2))
4684  return(nodes1);
4685  if (xmlXPathNodeSetIsEmpty(nodes1))
4686  return(xmlXPathNodeSetCreate(NULL));
4687  xmlXPathNodeSetSort(nodes1);
4688  xmlXPathNodeSetSort(nodes2);
4689  return(xmlXPathNodeLeadingSorted(nodes1,
4690  xmlXPathNodeSetItem(nodes2, 1)));
4691 }
4692 
4705 xmlNodeSetPtr
4706 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4707  int i, l;
4708  xmlNodePtr cur;
4709  xmlNodeSetPtr ret;
4710 
4711  if (node == NULL)
4712  return(nodes);
4713 
4714  ret = xmlXPathNodeSetCreate(NULL);
4715  if (ret == NULL)
4716  return(ret);
4717  if (xmlXPathNodeSetIsEmpty(nodes) ||
4718  (!xmlXPathNodeSetContains(nodes, node)))
4719  return(ret);
4720 
4721  l = xmlXPathNodeSetGetLength(nodes);
4722  for (i = l - 1; i >= 0; i--) {
4723  cur = xmlXPathNodeSetItem(nodes, i);
4724  if (cur == node)
4725  break;
4726  /* TODO: Propagate memory error. */
4727  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4728  break;
4729  }
4730  xmlXPathNodeSetSort(ret); /* bug 413451 */
4731  return(ret);
4732 }
4733 
4748 xmlNodeSetPtr
4749 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4750  xmlXPathNodeSetSort(nodes);
4751  return(xmlXPathNodeTrailingSorted(nodes, node));
4752 }
4753 
4766 xmlNodeSetPtr
4767 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4768  if (xmlXPathNodeSetIsEmpty(nodes2))
4769  return(nodes1);
4770  return(xmlXPathNodeTrailingSorted(nodes1,
4771  xmlXPathNodeSetItem(nodes2, 0)));
4772 }
4773 
4788 xmlNodeSetPtr
4789 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4790  if (xmlXPathNodeSetIsEmpty(nodes2))
4791  return(nodes1);
4792  if (xmlXPathNodeSetIsEmpty(nodes1))
4793  return(xmlXPathNodeSetCreate(NULL));
4794  xmlXPathNodeSetSort(nodes1);
4795  xmlXPathNodeSetSort(nodes2);
4796  return(xmlXPathNodeTrailingSorted(nodes1,
4797  xmlXPathNodeSetItem(nodes2, 0)));
4798 }
4799 
4800 /************************************************************************
4801  * *
4802  * Routines to handle extra functions *
4803  * *
4804  ************************************************************************/
4805 
4816 int
4817 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4818  xmlXPathFunction f) {
4819  return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4820 }
4821 
4833 int
4834 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4835  const xmlChar *ns_uri, xmlXPathFunction f) {
4836  if (ctxt == NULL)
4837  return(-1);
4838  if (name == NULL)
4839  return(-1);
4840 
4841  if (ctxt->funcHash == NULL)
4842  ctxt->funcHash = xmlHashCreate(0);
4843  if (ctxt->funcHash == NULL)
4844  return(-1);
4845  if (f == NULL)
4846  return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4848  return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4850 }
4851 
4860 void
4861 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4862  xmlXPathFuncLookupFunc f,
4863  void *funcCtxt) {
4864  if (ctxt == NULL)
4865  return;
4866  ctxt->funcLookupFunc = f;
4867  ctxt->funcLookupData = funcCtxt;
4868 }
4869 
4880 xmlXPathFunction
4881 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4882  if (ctxt == NULL)
4883  return (NULL);
4884 
4885  if (ctxt->funcLookupFunc != NULL) {
4886  xmlXPathFunction ret;
4887  xmlXPathFuncLookupFunc f;
4888 
4889  f = ctxt->funcLookupFunc;
4890  ret = f(ctxt->funcLookupData, name, NULL);
4891  if (ret != NULL)
4892  return(ret);
4893  }
4894  return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4895 }
4896 
4908 xmlXPathFunction
4909 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4910  const xmlChar *ns_uri) {
4911  xmlXPathFunction ret;
4912 
4913  if (ctxt == NULL)
4914  return(NULL);
4915  if (name == NULL)
4916  return(NULL);
4917 
4918  if (ctxt->funcLookupFunc != NULL) {
4919  xmlXPathFuncLookupFunc f;
4920 
4921  f = ctxt->funcLookupFunc;
4922  ret = f(ctxt->funcLookupData, name, ns_uri);
4923  if (ret != NULL)
4924  return(ret);
4925  }
4926 
4927  if (ctxt->funcHash == NULL)
4928  return(NULL);
4929 
4931  ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4933  return(ret);
4934 }
4935 
4942 void
4943 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4944  if (ctxt == NULL)
4945  return;
4946 
4947  xmlHashFree(ctxt->funcHash, NULL);
4948  ctxt->funcHash = NULL;
4949 }
4950 
4951 /************************************************************************
4952  * *
4953  * Routines to handle Variables *
4954  * *
4955  ************************************************************************/
4956 
4968 int
4969 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4970  xmlXPathObjectPtr value) {
4971  return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4972 }
4973 
4986 int
4987 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4988  const xmlChar *ns_uri,
4989  xmlXPathObjectPtr value) {
4990  if (ctxt == NULL)
4991  return(-1);
4992  if (name == NULL)
4993  return(-1);
4994 
4995  if (ctxt->varHash == NULL)
4996  ctxt->varHash = xmlHashCreate(0);
4997  if (ctxt->varHash == NULL)
4998  return(-1);
4999  if (value == NULL)
5000  return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5001  xmlXPathFreeObjectEntry));
5002  return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5003  (void *) value, xmlXPathFreeObjectEntry));
5004 }
5005 
5014 void
5015 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5016  xmlXPathVariableLookupFunc f, void *data) {
5017  if (ctxt == NULL)
5018  return;
5019  ctxt->varLookupFunc = f;
5020  ctxt->varLookupData = data;
5021 }
5022 
5033 xmlXPathObjectPtr
5034 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5035  if (ctxt == NULL)
5036  return(NULL);
5037 
5038  if (ctxt->varLookupFunc != NULL) {
5039  xmlXPathObjectPtr ret;
5040 
5041  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5042  (ctxt->varLookupData, name, NULL);
5043  return(ret);
5044  }
5045  return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5046 }
5047 
5059 xmlXPathObjectPtr
5060 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5061  const xmlChar *ns_uri) {
5062  if (ctxt == NULL)
5063  return(NULL);
5064 
5065  if (ctxt->varLookupFunc != NULL) {
5066  xmlXPathObjectPtr ret;
5067 
5068  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5069  (ctxt->varLookupData, name, ns_uri);
5070  if (ret != NULL) return(ret);
5071  }
5072 
5073  if (ctxt->varHash == NULL)
5074  return(NULL);
5075  if (name == NULL)
5076  return(NULL);
5077 
5078  return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5079  xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5080 }
5081 
5088 void
5089 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5090  if (ctxt == NULL)
5091  return;
5092 
5093  xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5094  ctxt->varHash = NULL;
5095 }
5096 
5108 int
5109 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5110  const xmlChar *ns_uri) {
5111  if (ctxt == NULL)
5112  return(-1);
5113  if (prefix == NULL)
5114  return(-1);
5115  if (prefix[0] == 0)
5116  return(-1);
5117 
5118  if (ctxt->nsHash == NULL)
5119  ctxt->nsHash = xmlHashCreate(10);
5120  if (ctxt->nsHash == NULL)
5121  return(-1);
5122  if (ns_uri == NULL)
5123  return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5125  return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5127 }
5128 
5139 const xmlChar *
5140 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5141  if (ctxt == NULL)
5142  return(NULL);
5143  if (prefix == NULL)
5144  return(NULL);
5145 
5146 #ifdef XML_XML_NAMESPACE
5147  if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5148  return(XML_XML_NAMESPACE);
5149 #endif
5150 
5151  if (ctxt->namespaces != NULL) {
5152  int i;
5153 
5154  for (i = 0;i < ctxt->nsNr;i++) {
5155  if ((ctxt->namespaces[i] != NULL) &&
5156  (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5157  return(ctxt->namespaces[i]->href);
5158  }
5159  }
5160 
5161  return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5162 }
5163 
5170 void
5171 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5172  if (ctxt == NULL)
5173  return;
5174 
5175  xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5176  ctxt->nsHash = NULL;
5177 }
5178 
5179 /************************************************************************
5180  * *
5181  * Routines to handle Values *
5182  * *
5183  ************************************************************************/
5184 
5185 /* Allocations are terrible, one needs to optimize all this !!! */
5186 
5195 xmlXPathObjectPtr
5196 xmlXPathNewFloat(double val) {
5197  xmlXPathObjectPtr ret;
5198 
5199  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5200  if (ret == NULL) {
5201  xmlXPathErrMemory(NULL, "creating float object\n");
5202  return(NULL);
5203  }
5204  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5205  ret->type = XPATH_NUMBER;
5206  ret->floatval = val;
5207 #ifdef XP_DEBUG_OBJ_USAGE
5208  xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5209 #endif
5210  return(ret);
5211 }
5212 
5221 xmlXPathObjectPtr
5222 xmlXPathNewBoolean(int val) {
5223  xmlXPathObjectPtr ret;
5224 
5225  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5226  if (ret == NULL) {
5227  xmlXPathErrMemory(NULL, "creating boolean object\n");
5228  return(NULL);
5229  }
5230  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5231  ret->type = XPATH_BOOLEAN;
5232  ret->boolval = (val != 0);
5233 #ifdef XP_DEBUG_OBJ_USAGE
5234  xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5235 #endif
5236  return(ret);
5237 }
5238 
5247 xmlXPathObjectPtr
5248 xmlXPathNewString(const xmlChar *val) {
5249  xmlXPathObjectPtr ret;
5250 
5251  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5252  if (ret == NULL) {
5253  xmlXPathErrMemory(NULL, "creating string object\n");
5254  return(NULL);
5255  }
5256  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5257  ret->type = XPATH_STRING;
5258  if (val != NULL)
5259  ret->stringval = xmlStrdup(val);
5260  else
5261  ret->stringval = xmlStrdup((const xmlChar *)"");
5262 #ifdef XP_DEBUG_OBJ_USAGE
5263  xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5264 #endif
5265  return(ret);
5266 }
5267 
5276 xmlXPathObjectPtr
5277 xmlXPathWrapString (xmlChar *val) {
5278  xmlXPathObjectPtr ret;
5279 
5280  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281  if (ret == NULL) {
5282  xmlXPathErrMemory(NULL, "creating string object\n");
5283  return(NULL);
5284  }
5285  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5286  ret->type = XPATH_STRING;
5287  ret->stringval = val;
5288 #ifdef XP_DEBUG_OBJ_USAGE
5289  xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5290 #endif
5291  return(ret);
5292 }
5293 
5302 xmlXPathObjectPtr
5303 xmlXPathNewCString(const char *val) {
5304  xmlXPathObjectPtr ret;
5305 
5306  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5307  if (ret == NULL) {
5308  xmlXPathErrMemory(NULL, "creating string object\n");
5309  return(NULL);
5310  }
5311  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5312  ret->type = XPATH_STRING;
5313  ret->stringval = xmlStrdup(BAD_CAST val);
5314 #ifdef XP_DEBUG_OBJ_USAGE
5315  xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5316 #endif
5317  return(ret);
5318 }
5319 
5328 xmlXPathObjectPtr
5329 xmlXPathWrapCString (char * val) {
5330  return(xmlXPathWrapString((xmlChar *)(val)));
5331 }
5332 
5341 xmlXPathObjectPtr
5342 xmlXPathWrapExternal (void *val) {
5343  xmlXPathObjectPtr ret;
5344 
5345  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5346  if (ret == NULL) {
5347  xmlXPathErrMemory(NULL, "creating user object\n");
5348  return(NULL);
5349  }
5350  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5351  ret->type = XPATH_USERS;
5352  ret->user = val;
5353 #ifdef XP_DEBUG_OBJ_USAGE
5354  xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5355 #endif
5356  return(ret);
5357 }
5358 
5367 xmlXPathObjectPtr
5368 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5369  xmlXPathObjectPtr ret;
5370 
5371  if (val == NULL)
5372  return(NULL);
5373 
5374  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5375  if (ret == NULL) {
5376  xmlXPathErrMemory(NULL, "copying object\n");
5377  return(NULL);
5378  }
5379  memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5380 #ifdef XP_DEBUG_OBJ_USAGE
5381  xmlXPathDebugObjUsageRequested(NULL, val->type);
5382 #endif
5383  switch (val->type) {
5384  case XPATH_BOOLEAN:
5385  case XPATH_NUMBER:
5386  case XPATH_POINT:
5387  case XPATH_RANGE:
5388  break;
5389  case XPATH_STRING:
5390  ret->stringval = xmlStrdup(val->stringval);
5391  break;
5392  case XPATH_XSLT_TREE:
5393 #if 0
5394 /*
5395  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5396  this previous handling is no longer correct, and can cause some serious
5397  problems (ref. bug 145547)
5398 */
5399  if ((val->nodesetval != NULL) &&
5400  (val->nodesetval->nodeTab != NULL)) {
5401  xmlNodePtr cur, tmp;
5402  xmlDocPtr top;
5403 
5404  ret->boolval = 1;
5405  top = xmlNewDoc(NULL);
5406  top->name = (char *)
5407  xmlStrdup(val->nodesetval->nodeTab[0]->name);
5408  ret->user = top;
5409  if (top != NULL) {
5410  top->doc = top;
5411  cur = val->nodesetval->nodeTab[0]->children;
5412  while (cur != NULL) {
5413  tmp = xmlDocCopyNode(cur, top, 1);
5414  xmlAddChild((xmlNodePtr) top, tmp);
5415  cur = cur->next;
5416  }
5417  }
5418 
5419  ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5420  } else
5421  ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5422  /* Deallocate the copied tree value */
5423  break;
5424 #endif
5425  case XPATH_NODESET:
5426  /* TODO: Check memory error. */
5427  ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5428  /* Do not deallocate the copied tree value */
5429  ret->boolval = 0;
5430  break;
5431  case XPATH_LOCATIONSET:
5432 #ifdef LIBXML_XPTR_ENABLED
5433  {
5434  xmlLocationSetPtr loc = val->user;
5435  ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5436  break;
5437  }
5438 #endif
5439  case XPATH_USERS:
5440  ret->user = val->user;
5441  break;
5442  case XPATH_UNDEFINED:
5444  "xmlXPathObjectCopy: unsupported type %d\n",
5445  val->type);
5446  break;
5447  }
5448  return(ret);
5449 }
5450 
5457 void
5458 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5459  if (obj == NULL) return;
5460  if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5461  if (obj->boolval) {
5462 #if 0
5463  if (obj->user != NULL) {
5464  xmlXPathFreeNodeSet(obj->nodesetval);
5465  xmlFreeNodeList((xmlNodePtr) obj->user);
5466  } else
5467 #endif
5468  obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5469  if (obj->nodesetval != NULL)
5470  xmlXPathFreeValueTree(obj->nodesetval);
5471  } else {
5472  if (obj->nodesetval != NULL)
5473  xmlXPathFreeNodeSet(obj->nodesetval);
5474  }
5475 #ifdef LIBXML_XPTR_ENABLED
5476  } else if (obj->type == XPATH_LOCATIONSET) {
5477  if (obj->user != NULL)
5478  xmlXPtrFreeLocationSet(obj->user);
5479 #endif
5480  } else if (obj->type == XPATH_STRING) {
5481  if (obj->stringval != NULL)
5482  xmlFree(obj->stringval);
5483  }
5484 #ifdef XP_DEBUG_OBJ_USAGE
5485  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5486 #endif
5487  xmlFree(obj);
5488 }
5489 
5490 static void
5491 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5492  xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5493 }
5494 
5502 static void
5503 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5504 {
5505 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5506  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5507  if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5508 
5509 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5510 
5511  if (obj == NULL)
5512  return;
5513  if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5514  xmlXPathFreeObject(obj);
5515  } else {
5516  xmlXPathContextCachePtr cache =
5517  (xmlXPathContextCachePtr) ctxt->cache;
5518 
5519  switch (obj->type) {
5520  case XPATH_NODESET:
5521  case XPATH_XSLT_TREE:
5522  if (obj->nodesetval != NULL) {
5523  if (obj->boolval) {
5524  /*
5525  * It looks like the @boolval is used for
5526  * evaluation if this an XSLT Result Tree Fragment.
5527  * TODO: Check if this assumption is correct.
5528  */
5529  obj->type = XPATH_XSLT_TREE; /* just for debugging */
5530  xmlXPathFreeValueTree(obj->nodesetval);
5531  obj->nodesetval = NULL;
5532  } else if ((obj->nodesetval->nodeMax <= 40) &&
5533  (XP_CACHE_WANTS(cache->nodesetObjs,
5534  cache->maxNodeset)))
5535  {
5536  XP_CACHE_ADD(cache->nodesetObjs, obj);
5537  goto obj_cached;
5538  } else {
5539  xmlXPathFreeNodeSet(obj->nodesetval);
5540  obj->nodesetval = NULL;
5541  }
5542  }
5543  break;
5544  case XPATH_STRING:
5545  if (obj->stringval != NULL)
5546  xmlFree(obj->stringval);
5547 
5548  if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5549  XP_CACHE_ADD(cache->stringObjs, obj);
5550  goto obj_cached;
5551  }
5552  break;
5553  case XPATH_BOOLEAN:
5554  if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5555  XP_CACHE_ADD(cache->booleanObjs, obj);
5556  goto obj_cached;
5557  }
5558  break;
5559  case XPATH_NUMBER:
5560  if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5561  XP_CACHE_ADD(cache->numberObjs, obj);
5562  goto obj_cached;
5563  }
5564  break;
5565 #ifdef LIBXML_XPTR_ENABLED
5566  case XPATH_LOCATIONSET:
5567  if (obj->user != NULL) {
5568  xmlXPtrFreeLocationSet(obj->user);
5569  }
5570  goto free_obj;
5571 #endif
5572  default:
5573  goto free_obj;
5574  }
5575 
5576  /*
5577  * Fallback to adding to the misc-objects slot.
5578  */
5579  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5580  XP_CACHE_ADD(cache->miscObjs, obj);
5581  } else
5582  goto free_obj;
5583 
5584 obj_cached:
5585 
5586 #ifdef XP_DEBUG_OBJ_USAGE
5587  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5588 #endif
5589 
5590  if (obj->nodesetval != NULL) {
5591  xmlNodeSetPtr tmpset = obj->nodesetval;
5592 
5593  /*
5594  * TODO: Due to those nasty ns-nodes, we need to traverse
5595  * the list and free the ns-nodes.
5596  * URGENT TODO: Check if it's actually slowing things down.
5597  * Maybe we shouldn't try to preserve the list.
5598  */
5599  if (tmpset->nodeNr > 1) {
5600  int i;
5601  xmlNodePtr node;
5602 
5603  for (i = 0; i < tmpset->nodeNr; i++) {
5604  node = tmpset->nodeTab[i];
5605  if ((node != NULL) &&
5606  (node->type == XML_NAMESPACE_DECL))
5607  {
5608  xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5609  }
5610  }
5611  } else if (tmpset->nodeNr == 1) {
5612  if ((tmpset->nodeTab[0] != NULL) &&
5613  (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5614  xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5615  }
5616  tmpset->nodeNr = 0;
5617  memset(obj, 0, sizeof(xmlXPathObject));
5618  obj->nodesetval = tmpset;
5619  } else
5620  memset(obj, 0, sizeof(xmlXPathObject));
5621 
5622  return;
5623 
5624 free_obj:
5625  /*
5626  * Cache is full; free the object.
5627  */
5628  if (obj->nodesetval != NULL)
5629  xmlXPathFreeNodeSet(obj->nodesetval);
5630 #ifdef XP_DEBUG_OBJ_USAGE
5631  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5632 #endif
5633  xmlFree(obj);
5634  }
5635  return;
5636 }
5637 
5638 
5639 /************************************************************************
5640  * *
5641  * Type Casting Routines *
5642  * *
5643  ************************************************************************/
5644 
5653 xmlChar *
5654 xmlXPathCastBooleanToString (int val) {
5655  xmlChar *ret;
5656  if (val)
5657  ret = xmlStrdup((const xmlChar *) "true");
5658  else
5659  ret = xmlStrdup((const xmlChar *) "false");
5660  return(ret);
5661 }
5662 
5671 xmlChar *
5672 xmlXPathCastNumberToString (double val) {
5673  xmlChar *ret;
5674  switch (xmlXPathIsInf(val)) {
5675  case 1:
5676  ret = xmlStrdup((const xmlChar *) "Infinity");
5677  break;
5678  case -1:
5679  ret = xmlStrdup((const xmlChar *) "-Infinity");
5680  break;
5681  default:
5682  if (xmlXPathIsNaN(val)) {
5683  ret = xmlStrdup((const xmlChar *) "NaN");
5684  } else if (val == 0) {
5685  /* Omit sign for negative zero. */
5686  ret = xmlStrdup((const xmlChar *) "0");
5687  } else {
5688  /* could be improved */
5689  char buf[100];
5690  xmlXPathFormatNumber(val, buf, 99);
5691  buf[99] = 0;
5692  ret = xmlStrdup((const xmlChar *) buf);
5693  }
5694  }
5695  return(ret);
5696 }
5697 
5706 xmlChar *
5707 xmlXPathCastNodeToString (xmlNodePtr node) {
5708 xmlChar *ret;
5709  if ((ret = xmlNodeGetContent(node)) == NULL)
5710  ret = xmlStrdup((const xmlChar *) "");
5711  return(ret);
5712 }
5713 
5722 xmlChar *
5723 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5724  if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5725  return(xmlStrdup((const xmlChar *) ""));
5726 
5727  if (ns->nodeNr > 1)
5728  xmlXPathNodeSetSort(ns);
5729  return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5730 }
5731 
5741 xmlChar *
5742 xmlXPathCastToString(xmlXPathObjectPtr val) {
5743  xmlChar *ret = NULL;
5744 
5745  if (val == NULL)
5746  return(xmlStrdup((const xmlChar *) ""));
5747  switch (val->type) {
5748  case XPATH_UNDEFINED:
5749 #ifdef DEBUG_EXPR
5750  xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5751 #endif
5752  ret = xmlStrdup((const xmlChar *) "");
5753  break;
5754  case XPATH_NODESET:
5755  case XPATH_XSLT_TREE:
5756  ret = xmlXPathCastNodeSetToString(val->nodesetval);
5757  break;
5758  case XPATH_STRING:
5759  return(xmlStrdup(val->stringval));
5760  case XPATH_BOOLEAN:
5761  ret = xmlXPathCastBooleanToString(val->boolval);
5762  break;
5763  case XPATH_NUMBER: {
5764  ret = xmlXPathCastNumberToString(val->floatval);
5765  break;
5766  }
5767  case XPATH_USERS:
5768  case XPATH_POINT:
5769  case XPATH_RANGE:
5770  case XPATH_LOCATIONSET:
5771  TODO
5772  ret = xmlStrdup((const xmlChar *) "");
5773  break;
5774  }
5775  return(ret);
5776 }
5777 
5787 xmlXPathObjectPtr
5788 xmlXPathConvertString(xmlXPathObjectPtr val) {
5789  xmlChar *res = NULL;
5790 
5791  if (val == NULL)
5792  return(xmlXPathNewCString(""));
5793 
5794  switch (val->type) {
5795  case XPATH_UNDEFINED:
5796 #ifdef DEBUG_EXPR
5797  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5798 #endif
5799  break;
5800  case XPATH_NODESET:
5801  case XPATH_XSLT_TREE:
5802  res = xmlXPathCastNodeSetToString(val->nodesetval);
5803  break;
5804  case XPATH_STRING:
5805  return(val);
5806  case XPATH_BOOLEAN:
5807  res = xmlXPathCastBooleanToString(val->boolval);
5808  break;
5809  case XPATH_NUMBER:
5810  res = xmlXPathCastNumberToString(val->floatval);
5811  break;
5812  case XPATH_USERS:
5813  case XPATH_POINT:
5814  case XPATH_RANGE:
5815  case XPATH_LOCATIONSET:
5816  TODO;
5817  break;
5818  }
5819  xmlXPathFreeObject(val);
5820  if (res == NULL)
5821  return(xmlXPathNewCString(""));
5822  return(xmlXPathWrapString(res));
5823 }
5824 
5833 double
5834 xmlXPathCastBooleanToNumber(int val) {
5835  if (val)
5836  return(1.0);
5837  return(0.0);
5838 }
5839 
5848 double
5849 xmlXPathCastStringToNumber(const xmlChar * val) {
5850  return(xmlXPathStringEvalNumber(val));
5851 }
5852 
5861 double
5862 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5863  xmlChar *strval;
5864  double ret;
5865 
5866  if (node == NULL)
5867  return(NAN);
5868  strval = xmlXPathCastNodeToString(node);
5869  if (strval == NULL)
5870  return(NAN);
5871  ret = xmlXPathCastStringToNumber(strval);
5872  xmlFree(strval);
5873 
5874  return(ret);
5875 }
5876 
5885 double
5886 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5887  xmlChar *str;
5888  double ret;
5889 
5890  if (ns == NULL)
5891  return(NAN);
5892  str = xmlXPathCastNodeSetToString(ns);
5893  ret = xmlXPathCastStringToNumber(str);
5894  xmlFree(str);
5895  return(ret);
5896 }
5897 
5906 double
5907 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5908  double ret = 0.0;
5909 
5910  if (val == NULL)
5911  return(NAN);
5912  switch (val->type) {
5913  case XPATH_UNDEFINED:
5914 #ifdef DEBUG_EXPR
5915  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5916 #endif
5917  ret = NAN;
5918  break;
5919  case XPATH_NODESET:
5920  case XPATH_XSLT_TREE:
5921  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5922  break;
5923  case XPATH_STRING:
5924  ret = xmlXPathCastStringToNumber(val->stringval);
5925  break;
5926  case XPATH_NUMBER:
5927  ret = val->floatval;
5928  break;
5929  case XPATH_BOOLEAN:
5930  ret = xmlXPathCastBooleanToNumber(val->boolval);
5931  break;
5932  case XPATH_USERS:
5933  case XPATH_POINT:
5934  case XPATH_RANGE:
5935  case XPATH_LOCATIONSET:
5936  TODO;
5937  ret = NAN;
5938  break;
5939  }
5940  return(ret);
5941 }
5942 
5952 xmlXPathObjectPtr
5953 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5954  xmlXPathObjectPtr ret;
5955 
5956  if (val == NULL)
5957  return(xmlXPathNewFloat(0.0));
5958  if (val->type == XPATH_NUMBER)
5959  return(val);
5960  ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5961  xmlXPathFreeObject(val);
5962  return(ret);
5963 }
5964 
5973 int
5974 xmlXPathCastNumberToBoolean (double val) {
5975  if (xmlXPathIsNaN(val) || (val == 0.0))
5976  return(0);
5977  return(1);
5978 }
5979 
5988 int
5989 xmlXPathCastStringToBoolean (const xmlChar *val) {
5990  if ((val == NULL) || (xmlStrlen(val) == 0))
5991  return(0);
5992  return(1);
5993 }
5994 
6003 int
6004 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6005  if ((ns == NULL) || (ns->nodeNr == 0))
6006  return(0);
6007  return(1);
6008 }
6009 
6018 int
6019 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6020  int ret = 0;
6021 
6022  if (val == NULL)
6023  return(0);
6024  switch (val->type) {
6025  case XPATH_UNDEFINED:
6026 #ifdef DEBUG_EXPR
6027  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6028 #endif
6029  ret = 0;
6030  break;
6031  case XPATH_NODESET:
6032  case XPATH_XSLT_TREE:
6033  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6034  break;
6035  case XPATH_STRING:
6036  ret = xmlXPathCastStringToBoolean(val->stringval);
6037  break;
6038  case XPATH_NUMBER:
6039  ret = xmlXPathCastNumberToBoolean(val->floatval);
6040  break;
6041  case XPATH_BOOLEAN:
6042  ret = val->boolval;
6043  break;
6044  case XPATH_USERS:
6045  case XPATH_POINT:
6046  case XPATH_RANGE:
6047  case XPATH_LOCATIONSET:
6048  TODO;
6049  ret = 0;
6050  break;
6051  }
6052  return(ret);
6053 }
6054 
6055 
6065 xmlXPathObjectPtr
6066 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6067  xmlXPathObjectPtr ret;
6068 
6069  if (val == NULL)
6070  return(xmlXPathNewBoolean(0));
6071  if (val->type == XPATH_BOOLEAN)
6072  return(val);
6073  ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6074  xmlXPathFreeObject(val);
6075  return(ret);
6076 }
6077 
6078 /************************************************************************
6079  * *
6080  * Routines to handle XPath contexts *
6081  * *
6082  ************************************************************************/
6083 
6092 xmlXPathContextPtr
6093 xmlXPathNewContext(xmlDocPtr doc) {
6094  xmlXPathContextPtr ret;
6095 
6096  ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6097  if (ret == NULL) {
6098  xmlXPathErrMemory(NULL, "creating context\n");
6099  return(NULL);
6100  }
6101  memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6102  ret->doc = doc;
6103  ret->node = NULL;
6104 
6105  ret->varHash = NULL;
6106 
6107  ret->nb_types = 0;
6108  ret->max_types = 0;
6109  ret->types = NULL;
6110 
6111  ret->funcHash = xmlHashCreate(0);
6112 
6113  ret->nb_axis = 0;
6114  ret->max_axis = 0;
6115  ret->axis = NULL;
6116 
6117  ret->nsHash = NULL;
6118  ret->user = NULL;
6119 
6120  ret->contextSize = -1;
6121  ret->proximityPosition = -1;
6122 
6123  ret->maxDepth = INT_MAX;
6124  ret->maxParserDepth = INT_MAX;
6125 
6126 #ifdef XP_DEFAULT_CACHE_ON
6127  if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6128  xmlXPathFreeContext(ret);
6129  return(NULL);
6130  }
6131 #endif
6132 
6133  xmlXPathRegisterAllFunctions(ret);
6134 
6135  return(ret);
6136 }
6137 
6144 void
6145 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6146  if (ctxt == NULL) return;
6147 
6148  if (ctxt->cache != NULL)
6149  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6150  xmlXPathRegisteredNsCleanup(ctxt);
6151  xmlXPathRegisteredFuncsCleanup(ctxt);
6152  xmlXPathRegisteredVariablesCleanup(ctxt);
6153  xmlResetError(&ctxt->lastError);
6154  xmlFree(ctxt);
6155 }
6156 
6157 /************************************************************************
6158  * *
6159  * Routines to handle XPath parser contexts *
6160  * *
6161  ************************************************************************/
6162 
6163 #define CHECK_CTXT(ctxt) \
6164  if (ctxt == NULL) { \
6165  __xmlRaiseError(NULL, NULL, NULL, \
6166  NULL, NULL, XML_FROM_XPATH, \
6167  XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6168  __FILE__, __LINE__, \
6169  NULL, NULL, NULL, 0, 0, \
6170  "NULL context pointer\n"); \
6171  return(NULL); \
6172  } \
6173 
6174 #define CHECK_CTXT_NEG(ctxt) \
6175  if (ctxt == NULL) { \
6176  __xmlRaiseError(NULL, NULL, NULL, \
6177  NULL, NULL, XML_FROM_XPATH, \
6178  XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6179  __FILE__, __LINE__, \
6180  NULL, NULL, NULL, 0, 0, \
6181  "NULL context pointer\n"); \
6182  return(-1); \
6183  } \
6184 
6185 
6186 #define CHECK_CONTEXT(ctxt) \
6187  if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6188  (ctxt->doc->children == NULL)) { \
6189  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6190  return(NULL); \
6191  }
6192 
6193 
6203 xmlXPathParserContextPtr
6204 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6205  xmlXPathParserContextPtr ret;
6206 
6207  ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6208  if (ret == NULL) {
6209  xmlXPathErrMemory(ctxt, "creating parser context\n");
6210  return(NULL);
6211  }
6212  memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6213  ret->cur = ret->base = str;
6214  ret->context = ctxt;
6215 
6216  ret->comp = xmlXPathNewCompExpr();
6217  if (ret->comp == NULL) {
6218  xmlFree(ret->valueTab);
6219  xmlFree(ret);
6220  return(NULL);
6221  }
6222  if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6223  ret->comp->dict = ctxt->dict;
6224  xmlDictReference(ret->comp->dict);
6225  }
6226 
6227  return(ret);
6228 }
6229 
6239 static xmlXPathParserContextPtr
6240 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6241  xmlXPathParserContextPtr ret;
6242 
6243  ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6244  if (ret == NULL) {
6245  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6246  return(NULL);
6247  }
6248  memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6249 
6250  /* Allocate the value stack */
6251  ret->valueTab = (xmlXPathObjectPtr *)
6252  xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6253  if (ret->valueTab == NULL) {
6254  xmlFree(ret);
6255  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6256  return(NULL);
6257  }
6258  ret->valueNr = 0;
6259  ret->valueMax = 10;
6260  ret->value = NULL;
6261  ret->valueFrame = 0;
6262 
6263  ret->context = ctxt;
6264  ret->comp = comp;
6265 
6266  return(ret);
6267 }
6268 
6275 void
6276 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6277  int i;
6278 
6279  if (ctxt->valueTab != NULL) {
6280  for (i = 0; i < ctxt->valueNr; i++) {
6281  if (ctxt->context)
6282  xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6283  else
6284  xmlXPathFreeObject(ctxt->valueTab[i]);
6285  }
6286  xmlFree(ctxt->valueTab);
6287  }
6288  if (ctxt->comp != NULL) {
6289 #ifdef XPATH_STREAMING
6290  if (ctxt->comp->stream != NULL) {
6291  xmlFreePatternList(ctxt->comp->stream);
6292  ctxt->comp->stream = NULL;
6293  }
6294 #endif
6295  xmlXPathFreeCompExpr(ctxt->comp);
6296  }
6297  xmlFree(ctxt);
6298 }
6299 
6300 /************************************************************************
6301  * *
6302  * The implicit core function library *
6303  * *
6304  ************************************************************************/
6305 
6315 static unsigned int
6316 xmlXPathNodeValHash(xmlNodePtr node) {
6317  int len = 2;
6318  const xmlChar * string = NULL;
6319  xmlNodePtr tmp = NULL;
6320  unsigned int ret = 0;
6321 
6322  if (node == NULL)
6323  return(0);
6324 
6325  if (node->type == XML_DOCUMENT_NODE) {
6327  if (tmp == NULL)
6328  node = node->children;
6329  else
6330  node = tmp;
6331 
6332  if (node == NULL)
6333  return(0);
6334  }
6335 
6336  switch (node->type) {
6337  case XML_COMMENT_NODE:
6338  case XML_PI_NODE:
6340  case XML_TEXT_NODE:
6341  string = node->content;
6342  if (string == NULL)
6343  return(0);
6344  if (string[0] == 0)
6345  return(0);
6346  return(((unsigned int) string[0]) +
6347  (((unsigned int) string[1]) << 8));
6348  case XML_NAMESPACE_DECL:
6349  string = ((xmlNsPtr)node)->href;
6350  if (string == NULL)
6351  return(0);
6352  if (string[0] == 0)
6353  return(0);
6354  return(((unsigned int) string[0]) +
6355  (((unsigned int) string[1]) << 8));
6356  case XML_ATTRIBUTE_NODE:
6357  tmp = ((xmlAttrPtr) node)->children;
6358  break;
6359  case XML_ELEMENT_NODE:
6360  tmp = node->children;
6361  break;
6362  default:
6363  return(0);
6364  }
6365  while (tmp != NULL) {
6366  switch (tmp->type) {
6368  case XML_TEXT_NODE:
6369  string = tmp->content;
6370  break;
6371  default:
6372  string = NULL;
6373  break;
6374  }
6375  if ((string != NULL) && (string[0] != 0)) {
6376  if (len == 1) {
6377  return(ret + (((unsigned int) string[0]) << 8));
6378  }
6379  if (string[1] == 0) {
6380  len = 1;
6381  ret = (unsigned int) string[0];
6382  } else {
6383  return(((unsigned int) string[0]) +
6384  (((unsigned int) string[1]) << 8));
6385  }
6386  }
6387  /*
6388  * Skip to next node
6389  */
6390  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6391  if (tmp->children->type != XML_ENTITY_DECL) {
6392  tmp = tmp->children;
6393  continue;
6394  }
6395  }
6396  if (tmp == node)
6397  break;
6398 
6399  if (tmp->next != NULL) {
6400  tmp = tmp->next;
6401  continue;
6402  }
6403 
6404  do {
6405  tmp = tmp->parent;
6406  if (tmp == NULL)
6407  break;
6408  if (tmp == node) {
6409  tmp = NULL;
6410  break;
6411  }
6412  if (tmp->next != NULL) {
6413  tmp = tmp->next;
6414  break;
6415  }
6416  } while (tmp != NULL);
6417  }
6418  return(ret);
6419 }
6420 
6430 static unsigned int
6431 xmlXPathStringHash(const xmlChar * string) {
6432  if (string == NULL)
6433  return((unsigned int) 0);
6434  if (string[0] == 0)
6435  return(0);
6436  return(((unsigned int) string[0]) +
6437  (((unsigned int) string[1]) << 8));
6438 }
6439 
6462 static int
6463 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6464  xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6465  int i, ret = 0;
6466  xmlNodeSetPtr ns;
6467  xmlChar *str2;
6468 
6469  if ((f == NULL) || (arg == NULL) ||
6470  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6471  xmlXPathReleaseObject(ctxt->context, arg);
6472  xmlXPathReleaseObject(ctxt->context, f);
6473  return(0);
6474  }
6475  ns = arg->nodesetval;
6476  if (ns != NULL) {
6477  for (i = 0;i < ns->nodeNr;i++) {
6478  str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6479  if (str2 != NULL) {
6480  valuePush(ctxt,
6481  xmlXPathCacheNewString(ctxt->context, str2));
6482  xmlFree(str2);
6483  xmlXPathNumberFunction(ctxt, 1);
6484  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6485  ret = xmlXPathCompareValues(ctxt, inf, strict);
6486  if (ret)
6487  break;
6488  }
6489  }
6490  }
6491  xmlXPathReleaseObject(ctxt->context, arg);
6492  xmlXPathReleaseObject(ctxt->context, f);
6493  return(ret);
6494 }
6495 
6517 static int
6518 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6519  xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6520  int i, ret = 0;
6521  xmlNodeSetPtr ns;
6522  xmlChar *str2;
6523 
6524  if ((s == NULL) || (arg == NULL) ||
6525  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6526  xmlXPathReleaseObject(ctxt->context, arg);
6527  xmlXPathReleaseObject(ctxt->context, s);
6528  return(0);
6529  }
6530  ns = arg->nodesetval;
6531  if (ns != NULL) {
6532  for (i = 0;i < ns->nodeNr;i++) {
6533  str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6534  if (str2 != NULL) {
6535  valuePush(ctxt,
6536  xmlXPathCacheNewString(ctxt->context, str2));
6537  xmlFree(str2);
6538  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6539  ret = xmlXPathCompareValues(ctxt, inf, strict);
6540  if (ret)
6541  break;
6542  }
6543  }
6544  }
6545  xmlXPathReleaseObject(ctxt->context, arg);
6546  xmlXPathReleaseObject(ctxt->context, s);
6547  return(ret);
6548 }
6549 
6578 static int
6579 xmlXPathCompareNodeSets(int inf, int strict,
6580  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6581  int i, j, init = 0;
6582  double val1;
6583  double *values2;
6584  int ret = 0;
6585  xmlNodeSetPtr ns1;
6586  xmlNodeSetPtr ns2;
6587 
6588  if ((arg1 == NULL) ||
6589  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6590  xmlXPathFreeObject(arg2);
6591  return(0);
6592  }
6593  if ((arg2 == NULL) ||
6594  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6595  xmlXPathFreeObject(arg1);
6596  xmlXPathFreeObject(arg2);
6597  return(0);
6598  }
6599 
6600  ns1 = arg1->nodesetval;
6601  ns2 = arg2->nodesetval;
6602 
6603  if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6604  xmlXPathFreeObject(arg1);
6605  xmlXPathFreeObject(arg2);
6606  return(0);
6607  }
6608  if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6609  xmlXPathFreeObject(arg1);
6610  xmlXPathFreeObject(arg2);
6611  return(0);
6612  }
6613 
6614  values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6615  if (values2 == NULL) {
6616  /* TODO: Propagate memory error. */
6617  xmlXPathErrMemory(NULL, "comparing nodesets\n");
6618  xmlXPathFreeObject(arg1);
6619  xmlXPathFreeObject(arg2);
6620  return(0);
6621  }
6622  for (i = 0;i < ns1->nodeNr;i++) {
6623  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6624  if (xmlXPathIsNaN(val1))
6625  continue;
6626  for (j = 0;j < ns2->nodeNr;j++) {
6627  if (init == 0) {
6628  values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6629  }
6630  if (xmlXPathIsNaN(values2[j]))
6631  continue;
6632  if (inf && strict)
6633  ret = (val1 < values2[j]);
6634  else if (inf && !strict)
6635  ret = (val1 <= values2[j]);
6636  else if (!inf && strict)
6637  ret = (val1 > values2[j]);
6638  else if (!inf && !strict)
6639  ret = (val1 >= values2[j]);
6640  if (ret)
6641  break;
6642  }
6643  if (ret)
6644  break;
6645  init = 1;
6646  }
6647  xmlFree(values2);
6648  xmlXPathFreeObject(arg1);
6649  xmlXPathFreeObject(arg2);
6650  return(ret);
6651 }
6652 
6674 static int
6675 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6676  xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6677  if ((val == NULL) || (arg == NULL) ||
6678  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6679  return(0);
6680 
6681  switch(val->type) {
6682  case XPATH_NUMBER:
6683  return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6684  case XPATH_NODESET:
6685  case XPATH_XSLT_TREE:
6