Bug Summary

File:xpath.c
Location:line 14203, column 7
Description:Value stored to 'ret' is never read

Annotated Source Code

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