VirtualBox

source: vbox/trunk/src/libs/libxml2-2.9.2/xpath.c@ 60028

最後變更 在這個檔案從60028是 58076,由 vboxsync 提交於 9 年 前

upstream fixes post 2.9.2

  • 屬性 svn:eol-style 設為 native
檔案大小: 418.3 KB
 
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: [email protected]
14 *
15 */
16
17#define IN_LIBXML
18#include "libxml.h"
19
20#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
31#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
34#ifdef HAVE_SIGNAL_H
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#include "buf.h"
59
60#ifdef LIBXML_PATTERN_ENABLED
61#define XPATH_STREAMING
62#endif
63
64#define TODO \
65 xmlGenericError(xmlGenericErrorContext, \
66 "Unimplemented block at %s:%d\n", \
67 __FILE__, __LINE__);
68
69/**
70 * WITH_TIM_SORT:
71 *
72 * Use the Timsort algorithm provided in timsort.h to sort
73 * nodeset as this is a great improvement over the old Shell sort
74 * used in xmlXPathNodeSetSort()
75 */
76#define WITH_TIM_SORT
77
78/*
79* XP_OPTIMIZED_NON_ELEM_COMPARISON:
80* If defined, this will use xmlXPathCmpNodesExt() instead of
81* xmlXPathCmpNodes(). The new function is optimized comparison of
82* non-element nodes; actually it will speed up comparison only if
83* xmlXPathOrderDocElems() was called in order to index the elements of
84* a tree in document order; Libxslt does such an indexing, thus it will
85* benefit from this optimization.
86*/
87#define XP_OPTIMIZED_NON_ELEM_COMPARISON
88
89/*
90* XP_OPTIMIZED_FILTER_FIRST:
91* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
92* in a way, that it stop evaluation at the first node.
93*/
94#define XP_OPTIMIZED_FILTER_FIRST
95
96/*
97* XP_DEBUG_OBJ_USAGE:
98* Internal flag to enable tracking of how much XPath objects have been
99* created.
100*/
101/* #define XP_DEBUG_OBJ_USAGE */
102
103/*
104 * XPATH_MAX_STEPS:
105 * when compiling an XPath expression we arbitrary limit the maximum
106 * number of step operation in the compiled expression. 1000000 is
107 * an insanely large value which should never be reached under normal
108 * circumstances
109 */
110#define XPATH_MAX_STEPS 1000000
111
112/*
113 * XPATH_MAX_STACK_DEPTH:
114 * when evaluating an XPath expression we arbitrary limit the maximum
115 * number of object allowed to be pushed on the stack. 1000000 is
116 * an insanely large value which should never be reached under normal
117 * circumstances
118 */
119#define XPATH_MAX_STACK_DEPTH 1000000
120
121/*
122 * XPATH_MAX_NODESET_LENGTH:
123 * when evaluating an XPath expression nodesets are created and we
124 * arbitrary limit the maximum length of those node set. 10000000 is
125 * an insanely large value which should never be reached under normal
126 * circumstances, one would first need to construct an in memory tree
127 * with more than 10 millions nodes.
128 */
129#define XPATH_MAX_NODESET_LENGTH 10000000
130
131/*
132 * TODO:
133 * There are a few spots where some tests are done which depend upon ascii
134 * data. These should be enhanced for full UTF8 support (see particularly
135 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
136 */
137
138#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
139/**
140 * xmlXPathCmpNodesExt:
141 * @node1: the first node
142 * @node2: the second node
143 *
144 * Compare two nodes w.r.t document order.
145 * This one is optimized for handling of non-element nodes.
146 *
147 * Returns -2 in case of error 1 if first point < second point, 0 if
148 * it's the same node, -1 otherwise
149 */
150static int
151xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
152 int depth1, depth2;
153 int misc = 0, precedence1 = 0, precedence2 = 0;
154 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
155 xmlNodePtr cur, root;
156 long l1, l2;
157
158 if ((node1 == NULL) || (node2 == NULL))
159 return(-2);
160
161 if (node1 == node2)
162 return(0);
163
164 /*
165 * a couple of optimizations which will avoid computations in most cases
166 */
167 switch (node1->type) {
168 case XML_ELEMENT_NODE:
169 if (node2->type == XML_ELEMENT_NODE) {
170 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
171 (0 > (long) node2->content) &&
172 (node1->doc == node2->doc))
173 {
174 l1 = -((long) node1->content);
175 l2 = -((long) node2->content);
176 if (l1 < l2)
177 return(1);
178 if (l1 > l2)
179 return(-1);
180 } else
181 goto turtle_comparison;
182 }
183 break;
184 case XML_ATTRIBUTE_NODE:
185 precedence1 = 1; /* element is owner */
186 miscNode1 = node1;
187 node1 = node1->parent;
188 misc = 1;
189 break;
190 case XML_TEXT_NODE:
191 case XML_CDATA_SECTION_NODE:
192 case XML_COMMENT_NODE:
193 case XML_PI_NODE: {
194 miscNode1 = node1;
195 /*
196 * Find nearest element node.
197 */
198 if (node1->prev != NULL) {
199 do {
200 node1 = node1->prev;
201 if (node1->type == XML_ELEMENT_NODE) {
202 precedence1 = 3; /* element in prev-sibl axis */
203 break;
204 }
205 if (node1->prev == NULL) {
206 precedence1 = 2; /* element is parent */
207 /*
208 * URGENT TODO: Are there any cases, where the
209 * parent of such a node is not an element node?
210 */
211 node1 = node1->parent;
212 break;
213 }
214 } while (1);
215 } else {
216 precedence1 = 2; /* element is parent */
217 node1 = node1->parent;
218 }
219 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
220 (0 <= (long) node1->content)) {
221 /*
222 * Fallback for whatever case.
223 */
224 node1 = miscNode1;
225 precedence1 = 0;
226 } else
227 misc = 1;
228 }
229 break;
230 case XML_NAMESPACE_DECL:
231 /*
232 * TODO: why do we return 1 for namespace nodes?
233 */
234 return(1);
235 default:
236 break;
237 }
238 switch (node2->type) {
239 case XML_ELEMENT_NODE:
240 break;
241 case XML_ATTRIBUTE_NODE:
242 precedence2 = 1; /* element is owner */
243 miscNode2 = node2;
244 node2 = node2->parent;
245 misc = 1;
246 break;
247 case XML_TEXT_NODE:
248 case XML_CDATA_SECTION_NODE:
249 case XML_COMMENT_NODE:
250 case XML_PI_NODE: {
251 miscNode2 = node2;
252 if (node2->prev != NULL) {
253 do {
254 node2 = node2->prev;
255 if (node2->type == XML_ELEMENT_NODE) {
256 precedence2 = 3; /* element in prev-sibl axis */
257 break;
258 }
259 if (node2->prev == NULL) {
260 precedence2 = 2; /* element is parent */
261 node2 = node2->parent;
262 break;
263 }
264 } while (1);
265 } else {
266 precedence2 = 2; /* element is parent */
267 node2 = node2->parent;
268 }
269 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
270 (0 <= (long) node2->content))
271 {
272 node2 = miscNode2;
273 precedence2 = 0;
274 } else
275 misc = 1;
276 }
277 break;
278 case XML_NAMESPACE_DECL:
279 return(1);
280 default:
281 break;
282 }
283 if (misc) {
284 if (node1 == node2) {
285 if (precedence1 == precedence2) {
286 /*
287 * The ugly case; but normally there aren't many
288 * adjacent non-element nodes around.
289 */
290 cur = miscNode2->prev;
291 while (cur != NULL) {
292 if (cur == miscNode1)
293 return(1);
294 if (cur->type == XML_ELEMENT_NODE)
295 return(-1);
296 cur = cur->prev;
297 }
298 return (-1);
299 } else {
300 /*
301 * Evaluate based on higher precedence wrt to the element.
302 * TODO: This assumes attributes are sorted before content.
303 * Is this 100% correct?
304 */
305 if (precedence1 < precedence2)
306 return(1);
307 else
308 return(-1);
309 }
310 }
311 /*
312 * Special case: One of the helper-elements is contained by the other.
313 * <foo>
314 * <node2>
315 * <node1>Text-1(precedence1 == 2)</node1>
316 * </node2>
317 * Text-6(precedence2 == 3)
318 * </foo>
319 */
320 if ((precedence2 == 3) && (precedence1 > 1)) {
321 cur = node1->parent;
322 while (cur) {
323 if (cur == node2)
324 return(1);
325 cur = cur->parent;
326 }
327 }
328 if ((precedence1 == 3) && (precedence2 > 1)) {
329 cur = node2->parent;
330 while (cur) {
331 if (cur == node1)
332 return(-1);
333 cur = cur->parent;
334 }
335 }
336 }
337
338 /*
339 * Speedup using document order if availble.
340 */
341 if ((node1->type == XML_ELEMENT_NODE) &&
342 (node2->type == XML_ELEMENT_NODE) &&
343 (0 > (long) node1->content) &&
344 (0 > (long) node2->content) &&
345 (node1->doc == node2->doc)) {
346
347 l1 = -((long) node1->content);
348 l2 = -((long) node2->content);
349 if (l1 < l2)
350 return(1);
351 if (l1 > l2)
352 return(-1);
353 }
354
355turtle_comparison:
356
357 if (node1 == node2->prev)
358 return(1);
359 if (node1 == node2->next)
360 return(-1);
361 /*
362 * compute depth to root
363 */
364 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
365 if (cur->parent == node1)
366 return(1);
367 depth2++;
368 }
369 root = cur;
370 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
371 if (cur->parent == node2)
372 return(-1);
373 depth1++;
374 }
375 /*
376 * Distinct document (or distinct entities :-( ) case.
377 */
378 if (root != cur) {
379 return(-2);
380 }
381 /*
382 * get the nearest common ancestor.
383 */
384 while (depth1 > depth2) {
385 depth1--;
386 node1 = node1->parent;
387 }
388 while (depth2 > depth1) {
389 depth2--;
390 node2 = node2->parent;
391 }
392 while (node1->parent != node2->parent) {
393 node1 = node1->parent;
394 node2 = node2->parent;
395 /* should not happen but just in case ... */
396 if ((node1 == NULL) || (node2 == NULL))
397 return(-2);
398 }
399 /*
400 * Find who's first.
401 */
402 if (node1 == node2->prev)
403 return(1);
404 if (node1 == node2->next)
405 return(-1);
406 /*
407 * Speedup using document order if availble.
408 */
409 if ((node1->type == XML_ELEMENT_NODE) &&
410 (node2->type == XML_ELEMENT_NODE) &&
411 (0 > (long) node1->content) &&
412 (0 > (long) node2->content) &&
413 (node1->doc == node2->doc)) {
414
415 l1 = -((long) node1->content);
416 l2 = -((long) node2->content);
417 if (l1 < l2)
418 return(1);
419 if (l1 > l2)
420 return(-1);
421 }
422
423 for (cur = node1->next;cur != NULL;cur = cur->next)
424 if (cur == node2)
425 return(1);
426 return(-1); /* assume there is no sibling list corruption */
427}
428#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
429
430/*
431 * Wrapper for the Timsort argorithm from timsort.h
432 */
433#ifdef WITH_TIM_SORT
434#define SORT_NAME libxml_domnode
435#define SORT_TYPE xmlNodePtr
436/**
437 * wrap_cmp:
438 * @x: a node
439 * @y: another node
440 *
441 * Comparison function for the Timsort implementation
442 *
443 * Returns -2 in case of error -1 if first point < second point, 0 if
444 * it's the same node, +1 otherwise
445 */
446static
447int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
448#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
449 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
450 {
451 int res = xmlXPathCmpNodesExt(x, y);
452 return res == -2 ? res : -res;
453 }
454#else
455 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
456 {
457 int res = xmlXPathCmpNodes(x, y);
458 return res == -2 ? res : -res;
459 }
460#endif
461#define SORT_CMP(x, y) (wrap_cmp(x, y))
462#include "timsort.h"
463#endif /* WITH_TIM_SORT */
464
465#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
466
467/************************************************************************
468 * *
469 * Floating point stuff *
470 * *
471 ************************************************************************/
472
473#ifndef TRIO_REPLACE_STDIO
474#define TRIO_PUBLIC static
475#endif
476#include "trionan.c"
477
478/*
479 * The lack of portability of this section of the libc is annoying !
480 */
481double xmlXPathNAN = 0;
482double xmlXPathPINF = 1;
483double xmlXPathNINF = -1;
484static double xmlXPathNZERO = 0; /* not exported from headers */
485static int xmlXPathInitialized = 0;
486
487/**
488 * xmlXPathInit:
489 *
490 * Initialize the XPath environment
491 */
492void
493xmlXPathInit(void) {
494 if (xmlXPathInitialized) return;
495
496 xmlXPathPINF = trio_pinf();
497 xmlXPathNINF = trio_ninf();
498 xmlXPathNAN = trio_nan();
499 xmlXPathNZERO = trio_nzero();
500
501 xmlXPathInitialized = 1;
502}
503
504/**
505 * xmlXPathIsNaN:
506 * @val: a double value
507 *
508 * Provides a portable isnan() function to detect whether a double
509 * is a NotaNumber. Based on trio code
510 * http://sourceforge.net/projects/ctrio/
511 *
512 * Returns 1 if the value is a NaN, 0 otherwise
513 */
514int
515xmlXPathIsNaN(double val) {
516 return(trio_isnan(val));
517}
518
519/**
520 * xmlXPathIsInf:
521 * @val: a double value
522 *
523 * Provides a portable isinf() function to detect whether a double
524 * is a +Infinite or -Infinite. Based on trio code
525 * http://sourceforge.net/projects/ctrio/
526 *
527 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
528 */
529int
530xmlXPathIsInf(double val) {
531 return(trio_isinf(val));
532}
533
534#endif /* SCHEMAS or XPATH */
535#ifdef LIBXML_XPATH_ENABLED
536/**
537 * xmlXPathGetSign:
538 * @val: a double value
539 *
540 * Provides a portable function to detect the sign of a double
541 * Modified from trio code
542 * http://sourceforge.net/projects/ctrio/
543 *
544 * Returns 1 if the value is Negative, 0 if positive
545 */
546static int
547xmlXPathGetSign(double val) {
548 return(trio_signbit(val));
549}
550
551
552/*
553 * TODO: when compatibility allows remove all "fake node libxslt" strings
554 * the test should just be name[0] = ' '
555 */
556#ifdef DEBUG_XPATH_EXPRESSION
557#define DEBUG_STEP
558#define DEBUG_EXPR
559#define DEBUG_EVAL_COUNTS
560#endif
561
562static xmlNs xmlXPathXMLNamespaceStruct = {
563 NULL,
564 XML_NAMESPACE_DECL,
565 XML_XML_NAMESPACE,
566 BAD_CAST "xml",
567 NULL,
568 NULL
569};
570static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
571#ifndef LIBXML_THREAD_ENABLED
572/*
573 * Optimizer is disabled only when threaded apps are detected while
574 * the library ain't compiled for thread safety.
575 */
576static int xmlXPathDisableOptimizer = 0;
577#endif
578
579/************************************************************************
580 * *
581 * Error handling routines *
582 * *
583 ************************************************************************/
584
585/**
586 * XP_ERRORNULL:
587 * @X: the error code
588 *
589 * Macro to raise an XPath error and return NULL.
590 */
591#define XP_ERRORNULL(X) \
592 { xmlXPathErr(ctxt, X); return(NULL); }
593
594/*
595 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
596 */
597static const char *xmlXPathErrorMessages[] = {
598 "Ok\n",
599 "Number encoding\n",
600 "Unfinished literal\n",
601 "Start of literal\n",
602 "Expected $ for variable reference\n",
603 "Undefined variable\n",
604 "Invalid predicate\n",
605 "Invalid expression\n",
606 "Missing closing curly brace\n",
607 "Unregistered function\n",
608 "Invalid operand\n",
609 "Invalid type\n",
610 "Invalid number of arguments\n",
611 "Invalid context size\n",
612 "Invalid context position\n",
613 "Memory allocation error\n",
614 "Syntax error\n",
615 "Resource error\n",
616 "Sub resource error\n",
617 "Undefined namespace prefix\n",
618 "Encoding error\n",
619 "Char out of XML range\n",
620 "Invalid or incomplete context\n",
621 "Stack usage error\n",
622 "Forbidden variable\n",
623 "?? Unknown error ??\n" /* Must be last in the list! */
624};
625#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
626 sizeof(xmlXPathErrorMessages[0])) - 1)
627/**
628 * xmlXPathErrMemory:
629 * @ctxt: an XPath context
630 * @extra: extra informations
631 *
632 * Handle a redefinition of attribute error
633 */
634static void
635xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
636{
637 if (ctxt != NULL) {
638 if (extra) {
639 xmlChar buf[200];
640
641 xmlStrPrintf(buf, 200,
642 BAD_CAST "Memory allocation failed : %s\n",
643 extra);
644 ctxt->lastError.message = (char *) xmlStrdup(buf);
645 } else {
646 ctxt->lastError.message = (char *)
647 xmlStrdup(BAD_CAST "Memory allocation failed\n");
648 }
649 ctxt->lastError.domain = XML_FROM_XPATH;
650 ctxt->lastError.code = XML_ERR_NO_MEMORY;
651 if (ctxt->error != NULL)
652 ctxt->error(ctxt->userData, &ctxt->lastError);
653 } else {
654 if (extra)
655 __xmlRaiseError(NULL, NULL, NULL,
656 NULL, NULL, XML_FROM_XPATH,
657 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
658 extra, NULL, NULL, 0, 0,
659 "Memory allocation failed : %s\n", extra);
660 else
661 __xmlRaiseError(NULL, NULL, NULL,
662 NULL, NULL, XML_FROM_XPATH,
663 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
664 NULL, NULL, NULL, 0, 0,
665 "Memory allocation failed\n");
666 }
667}
668
669/**
670 * xmlXPathPErrMemory:
671 * @ctxt: an XPath parser context
672 * @extra: extra informations
673 *
674 * Handle a redefinition of attribute error
675 */
676static void
677xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
678{
679 if (ctxt == NULL)
680 xmlXPathErrMemory(NULL, extra);
681 else {
682 ctxt->error = XPATH_MEMORY_ERROR;
683 xmlXPathErrMemory(ctxt->context, extra);
684 }
685}
686
687/**
688 * xmlXPathErr:
689 * @ctxt: a XPath parser context
690 * @error: the error code
691 *
692 * Handle an XPath error
693 */
694void
695xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
696{
697 if ((error < 0) || (error > MAXERRNO))
698 error = MAXERRNO;
699 if (ctxt == NULL) {
700 __xmlRaiseError(NULL, NULL, NULL,
701 NULL, NULL, XML_FROM_XPATH,
702 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703 XML_ERR_ERROR, NULL, 0,
704 NULL, NULL, NULL, 0, 0,
705 "%s", xmlXPathErrorMessages[error]);
706 return;
707 }
708 ctxt->error = error;
709 if (ctxt->context == NULL) {
710 __xmlRaiseError(NULL, NULL, NULL,
711 NULL, NULL, XML_FROM_XPATH,
712 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
713 XML_ERR_ERROR, NULL, 0,
714 (const char *) ctxt->base, NULL, NULL,
715 ctxt->cur - ctxt->base, 0,
716 "%s", xmlXPathErrorMessages[error]);
717 return;
718 }
719
720 /* cleanup current last error */
721 xmlResetError(&ctxt->context->lastError);
722
723 ctxt->context->lastError.domain = XML_FROM_XPATH;
724 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
725 XPATH_EXPRESSION_OK;
726 ctxt->context->lastError.level = XML_ERR_ERROR;
727 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
728 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
729 ctxt->context->lastError.node = ctxt->context->debugNode;
730 if (ctxt->context->error != NULL) {
731 ctxt->context->error(ctxt->context->userData,
732 &ctxt->context->lastError);
733 } else {
734 __xmlRaiseError(NULL, NULL, NULL,
735 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
736 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
737 XML_ERR_ERROR, NULL, 0,
738 (const char *) ctxt->base, NULL, NULL,
739 ctxt->cur - ctxt->base, 0,
740 "%s", xmlXPathErrorMessages[error]);
741 }
742
743}
744
745/**
746 * xmlXPatherror:
747 * @ctxt: the XPath Parser context
748 * @file: the file name
749 * @line: the line number
750 * @no: the error number
751 *
752 * Formats an error message.
753 */
754void
755xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
756 int line ATTRIBUTE_UNUSED, int no) {
757 xmlXPathErr(ctxt, no);
758}
759
760/************************************************************************
761 * *
762 * Utilities *
763 * *
764 ************************************************************************/
765
766/**
767 * xsltPointerList:
768 *
769 * Pointer-list for various purposes.
770 */
771typedef struct _xmlPointerList xmlPointerList;
772typedef xmlPointerList *xmlPointerListPtr;
773struct _xmlPointerList {
774 void **items;
775 int number;
776 int size;
777};
778/*
779* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
780* and here, we should make the functions public.
781*/
782static int
783xmlPointerListAddSize(xmlPointerListPtr list,
784 void *item,
785 int initialSize)
786{
787 if (list->items == NULL) {
788 if (initialSize <= 0)
789 initialSize = 1;
790 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
791 if (list->items == NULL) {
792 xmlXPathErrMemory(NULL,
793 "xmlPointerListCreate: allocating item\n");
794 return(-1);
795 }
796 list->number = 0;
797 list->size = initialSize;
798 } else if (list->size <= list->number) {
799 if (list->size > 50000000) {
800 xmlXPathErrMemory(NULL,
801 "xmlPointerListAddSize: re-allocating item\n");
802 return(-1);
803 }
804 list->size *= 2;
805 list->items = (void **) xmlRealloc(list->items,
806 list->size * sizeof(void *));
807 if (list->items == NULL) {
808 xmlXPathErrMemory(NULL,
809 "xmlPointerListAddSize: re-allocating item\n");
810 list->size = 0;
811 return(-1);
812 }
813 }
814 list->items[list->number++] = item;
815 return(0);
816}
817
818/**
819 * xsltPointerListCreate:
820 *
821 * Creates an xsltPointerList structure.
822 *
823 * Returns a xsltPointerList structure or NULL in case of an error.
824 */
825static xmlPointerListPtr
826xmlPointerListCreate(int initialSize)
827{
828 xmlPointerListPtr ret;
829
830 ret = xmlMalloc(sizeof(xmlPointerList));
831 if (ret == NULL) {
832 xmlXPathErrMemory(NULL,
833 "xmlPointerListCreate: allocating item\n");
834 return (NULL);
835 }
836 memset(ret, 0, sizeof(xmlPointerList));
837 if (initialSize > 0) {
838 xmlPointerListAddSize(ret, NULL, initialSize);
839 ret->number = 0;
840 }
841 return (ret);
842}
843
844/**
845 * xsltPointerListFree:
846 *
847 * Frees the xsltPointerList structure. This does not free
848 * the content of the list.
849 */
850static void
851xmlPointerListFree(xmlPointerListPtr list)
852{
853 if (list == NULL)
854 return;
855 if (list->items != NULL)
856 xmlFree(list->items);
857 xmlFree(list);
858}
859
860/************************************************************************
861 * *
862 * Parser Types *
863 * *
864 ************************************************************************/
865
866/*
867 * Types are private:
868 */
869
870typedef enum {
871 XPATH_OP_END=0,
872 XPATH_OP_AND,
873 XPATH_OP_OR,
874 XPATH_OP_EQUAL,
875 XPATH_OP_CMP,
876 XPATH_OP_PLUS,
877 XPATH_OP_MULT,
878 XPATH_OP_UNION,
879 XPATH_OP_ROOT,
880 XPATH_OP_NODE,
881 XPATH_OP_RESET, /* 10 */
882 XPATH_OP_COLLECT,
883 XPATH_OP_VALUE, /* 12 */
884 XPATH_OP_VARIABLE,
885 XPATH_OP_FUNCTION,
886 XPATH_OP_ARG,
887 XPATH_OP_PREDICATE,
888 XPATH_OP_FILTER, /* 17 */
889 XPATH_OP_SORT /* 18 */
890#ifdef LIBXML_XPTR_ENABLED
891 ,XPATH_OP_RANGETO
892#endif
893} xmlXPathOp;
894
895typedef enum {
896 AXIS_ANCESTOR = 1,
897 AXIS_ANCESTOR_OR_SELF,
898 AXIS_ATTRIBUTE,
899 AXIS_CHILD,
900 AXIS_DESCENDANT,
901 AXIS_DESCENDANT_OR_SELF,
902 AXIS_FOLLOWING,
903 AXIS_FOLLOWING_SIBLING,
904 AXIS_NAMESPACE,
905 AXIS_PARENT,
906 AXIS_PRECEDING,
907 AXIS_PRECEDING_SIBLING,
908 AXIS_SELF
909} xmlXPathAxisVal;
910
911typedef enum {
912 NODE_TEST_NONE = 0,
913 NODE_TEST_TYPE = 1,
914 NODE_TEST_PI = 2,
915 NODE_TEST_ALL = 3,
916 NODE_TEST_NS = 4,
917 NODE_TEST_NAME = 5
918} xmlXPathTestVal;
919
920typedef enum {
921 NODE_TYPE_NODE = 0,
922 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
923 NODE_TYPE_TEXT = XML_TEXT_NODE,
924 NODE_TYPE_PI = XML_PI_NODE
925} xmlXPathTypeVal;
926
927typedef struct _xmlXPathStepOp xmlXPathStepOp;
928typedef xmlXPathStepOp *xmlXPathStepOpPtr;
929struct _xmlXPathStepOp {
930 xmlXPathOp op; /* The identifier of the operation */
931 int ch1; /* First child */
932 int ch2; /* Second child */
933 int value;
934 int value2;
935 int value3;
936 void *value4;
937 void *value5;
938 void *cache;
939 void *cacheURI;
940};
941
942struct _xmlXPathCompExpr {
943 int nbStep; /* Number of steps in this expression */
944 int maxStep; /* Maximum number of steps allocated */
945 xmlXPathStepOp *steps; /* ops for computation of this expression */
946 int last; /* index of last step in expression */
947 xmlChar *expr; /* the expression being computed */
948 xmlDictPtr dict; /* the dictionnary to use if any */
949#ifdef DEBUG_EVAL_COUNTS
950 int nb;
951 xmlChar *string;
952#endif
953#ifdef XPATH_STREAMING
954 xmlPatternPtr stream;
955#endif
956};
957
958/************************************************************************
959 * *
960 * Forward declarations *
961 * *
962 ************************************************************************/
963static void
964xmlXPathFreeValueTree(xmlNodeSetPtr obj);
965static void
966xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
967static int
968xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
969 xmlXPathStepOpPtr op, xmlNodePtr *first);
970static int
971xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
972 xmlXPathStepOpPtr op,
973 int isPredicate);
974
975/************************************************************************
976 * *
977 * Parser Type functions *
978 * *
979 ************************************************************************/
980
981/**
982 * xmlXPathNewCompExpr:
983 *
984 * Create a new Xpath component
985 *
986 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
987 */
988static xmlXPathCompExprPtr
989xmlXPathNewCompExpr(void) {
990 xmlXPathCompExprPtr cur;
991
992 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
993 if (cur == NULL) {
994 xmlXPathErrMemory(NULL, "allocating component\n");
995 return(NULL);
996 }
997 memset(cur, 0, sizeof(xmlXPathCompExpr));
998 cur->maxStep = 10;
999 cur->nbStep = 0;
1000 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1001 sizeof(xmlXPathStepOp));
1002 if (cur->steps == NULL) {
1003 xmlXPathErrMemory(NULL, "allocating steps\n");
1004 xmlFree(cur);
1005 return(NULL);
1006 }
1007 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1008 cur->last = -1;
1009#ifdef DEBUG_EVAL_COUNTS
1010 cur->nb = 0;
1011#endif
1012 return(cur);
1013}
1014
1015/**
1016 * xmlXPathFreeCompExpr:
1017 * @comp: an XPATH comp
1018 *
1019 * Free up the memory allocated by @comp
1020 */
1021void
1022xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1023{
1024 xmlXPathStepOpPtr op;
1025 int i;
1026
1027 if (comp == NULL)
1028 return;
1029 if (comp->dict == NULL) {
1030 for (i = 0; i < comp->nbStep; i++) {
1031 op = &comp->steps[i];
1032 if (op->value4 != NULL) {
1033 if (op->op == XPATH_OP_VALUE)
1034 xmlXPathFreeObject(op->value4);
1035 else
1036 xmlFree(op->value4);
1037 }
1038 if (op->value5 != NULL)
1039 xmlFree(op->value5);
1040 }
1041 } else {
1042 for (i = 0; i < comp->nbStep; i++) {
1043 op = &comp->steps[i];
1044 if (op->value4 != NULL) {
1045 if (op->op == XPATH_OP_VALUE)
1046 xmlXPathFreeObject(op->value4);
1047 }
1048 }
1049 xmlDictFree(comp->dict);
1050 }
1051 if (comp->steps != NULL) {
1052 xmlFree(comp->steps);
1053 }
1054#ifdef DEBUG_EVAL_COUNTS
1055 if (comp->string != NULL) {
1056 xmlFree(comp->string);
1057 }
1058#endif
1059#ifdef XPATH_STREAMING
1060 if (comp->stream != NULL) {
1061 xmlFreePatternList(comp->stream);
1062 }
1063#endif
1064 if (comp->expr != NULL) {
1065 xmlFree(comp->expr);
1066 }
1067
1068 xmlFree(comp);
1069}
1070
1071/**
1072 * xmlXPathCompExprAdd:
1073 * @comp: the compiled expression
1074 * @ch1: first child index
1075 * @ch2: second child index
1076 * @op: an op
1077 * @value: the first int value
1078 * @value2: the second int value
1079 * @value3: the third int value
1080 * @value4: the first string value
1081 * @value5: the second string value
1082 *
1083 * Add a step to an XPath Compiled Expression
1084 *
1085 * Returns -1 in case of failure, the index otherwise
1086 */
1087static int
1088xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1089 xmlXPathOp op, int value,
1090 int value2, int value3, void *value4, void *value5) {
1091 if (comp->nbStep >= comp->maxStep) {
1092 xmlXPathStepOp *real;
1093
1094 if (comp->maxStep >= XPATH_MAX_STEPS) {
1095 xmlXPathErrMemory(NULL, "adding step\n");
1096 return(-1);
1097 }
1098 comp->maxStep *= 2;
1099 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1100 comp->maxStep * sizeof(xmlXPathStepOp));
1101 if (real == NULL) {
1102 comp->maxStep /= 2;
1103 xmlXPathErrMemory(NULL, "adding step\n");
1104 return(-1);
1105 }
1106 comp->steps = real;
1107 }
1108 comp->last = comp->nbStep;
1109 comp->steps[comp->nbStep].ch1 = ch1;
1110 comp->steps[comp->nbStep].ch2 = ch2;
1111 comp->steps[comp->nbStep].op = op;
1112 comp->steps[comp->nbStep].value = value;
1113 comp->steps[comp->nbStep].value2 = value2;
1114 comp->steps[comp->nbStep].value3 = value3;
1115 if ((comp->dict != NULL) &&
1116 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1117 (op == XPATH_OP_COLLECT))) {
1118 if (value4 != NULL) {
1119 comp->steps[comp->nbStep].value4 = (xmlChar *)
1120 (void *)xmlDictLookup(comp->dict, value4, -1);
1121 xmlFree(value4);
1122 } else
1123 comp->steps[comp->nbStep].value4 = NULL;
1124 if (value5 != NULL) {
1125 comp->steps[comp->nbStep].value5 = (xmlChar *)
1126 (void *)xmlDictLookup(comp->dict, value5, -1);
1127 xmlFree(value5);
1128 } else
1129 comp->steps[comp->nbStep].value5 = NULL;
1130 } else {
1131 comp->steps[comp->nbStep].value4 = value4;
1132 comp->steps[comp->nbStep].value5 = value5;
1133 }
1134 comp->steps[comp->nbStep].cache = NULL;
1135 return(comp->nbStep++);
1136}
1137
1138/**
1139 * xmlXPathCompSwap:
1140 * @comp: the compiled expression
1141 * @op: operation index
1142 *
1143 * Swaps 2 operations in the compiled expression
1144 */
1145static void
1146xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1147 int tmp;
1148
1149#ifndef LIBXML_THREAD_ENABLED
1150 /*
1151 * Since this manipulates possibly shared variables, this is
1152 * disabled if one detects that the library is used in a multithreaded
1153 * application
1154 */
1155 if (xmlXPathDisableOptimizer)
1156 return;
1157#endif
1158
1159 tmp = op->ch1;
1160 op->ch1 = op->ch2;
1161 op->ch2 = tmp;
1162}
1163
1164#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1165 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1166 (op), (val), (val2), (val3), (val4), (val5))
1167#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1168 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1169 (op), (val), (val2), (val3), (val4), (val5))
1170
1171#define PUSH_LEAVE_EXPR(op, val, val2) \
1172xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1173
1174#define PUSH_UNARY_EXPR(op, ch, val, val2) \
1175xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1176
1177#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1178xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1179 (val), (val2), 0 ,NULL ,NULL)
1180
1181/************************************************************************
1182 * *
1183 * XPath object cache structures *
1184 * *
1185 ************************************************************************/
1186
1187/* #define XP_DEFAULT_CACHE_ON */
1188
1189#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1190
1191typedef struct _xmlXPathContextCache xmlXPathContextCache;
1192typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1193struct _xmlXPathContextCache {
1194 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1195 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1196 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1197 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1198 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1199 int maxNodeset;
1200 int maxString;
1201 int maxBoolean;
1202 int maxNumber;
1203 int maxMisc;
1204#ifdef XP_DEBUG_OBJ_USAGE
1205 int dbgCachedAll;
1206 int dbgCachedNodeset;
1207 int dbgCachedString;
1208 int dbgCachedBool;
1209 int dbgCachedNumber;
1210 int dbgCachedPoint;
1211 int dbgCachedRange;
1212 int dbgCachedLocset;
1213 int dbgCachedUsers;
1214 int dbgCachedXSLTTree;
1215 int dbgCachedUndefined;
1216
1217
1218 int dbgReusedAll;
1219 int dbgReusedNodeset;
1220 int dbgReusedString;
1221 int dbgReusedBool;
1222 int dbgReusedNumber;
1223 int dbgReusedPoint;
1224 int dbgReusedRange;
1225 int dbgReusedLocset;
1226 int dbgReusedUsers;
1227 int dbgReusedXSLTTree;
1228 int dbgReusedUndefined;
1229
1230#endif
1231};
1232
1233/************************************************************************
1234 * *
1235 * Debugging related functions *
1236 * *
1237 ************************************************************************/
1238
1239#define STRANGE \
1240 xmlGenericError(xmlGenericErrorContext, \
1241 "Internal error at %s:%d\n", \
1242 __FILE__, __LINE__);
1243
1244#ifdef LIBXML_DEBUG_ENABLED
1245static void
1246xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1247 int i;
1248 char shift[100];
1249
1250 for (i = 0;((i < depth) && (i < 25));i++)
1251 shift[2 * i] = shift[2 * i + 1] = ' ';
1252 shift[2 * i] = shift[2 * i + 1] = 0;
1253 if (cur == NULL) {
1254 fprintf(output, "%s", shift);
1255 fprintf(output, "Node is NULL !\n");
1256 return;
1257
1258 }
1259
1260 if ((cur->type == XML_DOCUMENT_NODE) ||
1261 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1262 fprintf(output, "%s", shift);
1263 fprintf(output, " /\n");
1264 } else if (cur->type == XML_ATTRIBUTE_NODE)
1265 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1266 else
1267 xmlDebugDumpOneNode(output, cur, depth);
1268}
1269static void
1270xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1271 xmlNodePtr tmp;
1272 int i;
1273 char shift[100];
1274
1275 for (i = 0;((i < depth) && (i < 25));i++)
1276 shift[2 * i] = shift[2 * i + 1] = ' ';
1277 shift[2 * i] = shift[2 * i + 1] = 0;
1278 if (cur == NULL) {
1279 fprintf(output, "%s", shift);
1280 fprintf(output, "Node is NULL !\n");
1281 return;
1282
1283 }
1284
1285 while (cur != NULL) {
1286 tmp = cur;
1287 cur = cur->next;
1288 xmlDebugDumpOneNode(output, tmp, depth);
1289 }
1290}
1291
1292static void
1293xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1294 int i;
1295 char shift[100];
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 if (cur == NULL) {
1302 fprintf(output, "%s", shift);
1303 fprintf(output, "NodeSet is NULL !\n");
1304 return;
1305
1306 }
1307
1308 if (cur != NULL) {
1309 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1310 for (i = 0;i < cur->nodeNr;i++) {
1311 fprintf(output, "%s", shift);
1312 fprintf(output, "%d", i + 1);
1313 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1314 }
1315 }
1316}
1317
1318static void
1319xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1320 int i;
1321 char shift[100];
1322
1323 for (i = 0;((i < depth) && (i < 25));i++)
1324 shift[2 * i] = shift[2 * i + 1] = ' ';
1325 shift[2 * i] = shift[2 * i + 1] = 0;
1326
1327 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1328 fprintf(output, "%s", shift);
1329 fprintf(output, "Value Tree is NULL !\n");
1330 return;
1331
1332 }
1333
1334 fprintf(output, "%s", shift);
1335 fprintf(output, "%d", i + 1);
1336 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1337}
1338#if defined(LIBXML_XPTR_ENABLED)
1339static void
1340xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1341 int i;
1342 char shift[100];
1343
1344 for (i = 0;((i < depth) && (i < 25));i++)
1345 shift[2 * i] = shift[2 * i + 1] = ' ';
1346 shift[2 * i] = shift[2 * i + 1] = 0;
1347
1348 if (cur == NULL) {
1349 fprintf(output, "%s", shift);
1350 fprintf(output, "LocationSet is NULL !\n");
1351 return;
1352
1353 }
1354
1355 for (i = 0;i < cur->locNr;i++) {
1356 fprintf(output, "%s", shift);
1357 fprintf(output, "%d : ", i + 1);
1358 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1359 }
1360}
1361#endif /* LIBXML_XPTR_ENABLED */
1362
1363/**
1364 * xmlXPathDebugDumpObject:
1365 * @output: the FILE * to dump the output
1366 * @cur: the object to inspect
1367 * @depth: indentation level
1368 *
1369 * Dump the content of the object for debugging purposes
1370 */
1371void
1372xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1373 int i;
1374 char shift[100];
1375
1376 if (output == NULL) return;
1377
1378 for (i = 0;((i < depth) && (i < 25));i++)
1379 shift[2 * i] = shift[2 * i + 1] = ' ';
1380 shift[2 * i] = shift[2 * i + 1] = 0;
1381
1382
1383 fprintf(output, "%s", shift);
1384
1385 if (cur == NULL) {
1386 fprintf(output, "Object is empty (NULL)\n");
1387 return;
1388 }
1389 switch(cur->type) {
1390 case XPATH_UNDEFINED:
1391 fprintf(output, "Object is uninitialized\n");
1392 break;
1393 case XPATH_NODESET:
1394 fprintf(output, "Object is a Node Set :\n");
1395 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1396 break;
1397 case XPATH_XSLT_TREE:
1398 fprintf(output, "Object is an XSLT value tree :\n");
1399 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1400 break;
1401 case XPATH_BOOLEAN:
1402 fprintf(output, "Object is a Boolean : ");
1403 if (cur->boolval) fprintf(output, "true\n");
1404 else fprintf(output, "false\n");
1405 break;
1406 case XPATH_NUMBER:
1407 switch (xmlXPathIsInf(cur->floatval)) {
1408 case 1:
1409 fprintf(output, "Object is a number : Infinity\n");
1410 break;
1411 case -1:
1412 fprintf(output, "Object is a number : -Infinity\n");
1413 break;
1414 default:
1415 if (xmlXPathIsNaN(cur->floatval)) {
1416 fprintf(output, "Object is a number : NaN\n");
1417 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1418 fprintf(output, "Object is a number : 0\n");
1419 } else {
1420 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1421 }
1422 }
1423 break;
1424 case XPATH_STRING:
1425 fprintf(output, "Object is a string : ");
1426 xmlDebugDumpString(output, cur->stringval);
1427 fprintf(output, "\n");
1428 break;
1429 case XPATH_POINT:
1430 fprintf(output, "Object is a point : index %d in node", cur->index);
1431 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1432 fprintf(output, "\n");
1433 break;
1434 case XPATH_RANGE:
1435 if ((cur->user2 == NULL) ||
1436 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1437 fprintf(output, "Object is a collapsed range :\n");
1438 fprintf(output, "%s", shift);
1439 if (cur->index >= 0)
1440 fprintf(output, "index %d in ", cur->index);
1441 fprintf(output, "node\n");
1442 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1443 depth + 1);
1444 } else {
1445 fprintf(output, "Object is a range :\n");
1446 fprintf(output, "%s", shift);
1447 fprintf(output, "From ");
1448 if (cur->index >= 0)
1449 fprintf(output, "index %d in ", cur->index);
1450 fprintf(output, "node\n");
1451 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1452 depth + 1);
1453 fprintf(output, "%s", shift);
1454 fprintf(output, "To ");
1455 if (cur->index2 >= 0)
1456 fprintf(output, "index %d in ", cur->index2);
1457 fprintf(output, "node\n");
1458 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1459 depth + 1);
1460 fprintf(output, "\n");
1461 }
1462 break;
1463 case XPATH_LOCATIONSET:
1464#if defined(LIBXML_XPTR_ENABLED)
1465 fprintf(output, "Object is a Location Set:\n");
1466 xmlXPathDebugDumpLocationSet(output,
1467 (xmlLocationSetPtr) cur->user, depth);
1468#endif
1469 break;
1470 case XPATH_USERS:
1471 fprintf(output, "Object is user defined\n");
1472 break;
1473 }
1474}
1475
1476static void
1477xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1478 xmlXPathStepOpPtr op, int depth) {
1479 int i;
1480 char shift[100];
1481
1482 for (i = 0;((i < depth) && (i < 25));i++)
1483 shift[2 * i] = shift[2 * i + 1] = ' ';
1484 shift[2 * i] = shift[2 * i + 1] = 0;
1485
1486 fprintf(output, "%s", shift);
1487 if (op == NULL) {
1488 fprintf(output, "Step is NULL\n");
1489 return;
1490 }
1491 switch (op->op) {
1492 case XPATH_OP_END:
1493 fprintf(output, "END"); break;
1494 case XPATH_OP_AND:
1495 fprintf(output, "AND"); break;
1496 case XPATH_OP_OR:
1497 fprintf(output, "OR"); break;
1498 case XPATH_OP_EQUAL:
1499 if (op->value)
1500 fprintf(output, "EQUAL =");
1501 else
1502 fprintf(output, "EQUAL !=");
1503 break;
1504 case XPATH_OP_CMP:
1505 if (op->value)
1506 fprintf(output, "CMP <");
1507 else
1508 fprintf(output, "CMP >");
1509 if (!op->value2)
1510 fprintf(output, "=");
1511 break;
1512 case XPATH_OP_PLUS:
1513 if (op->value == 0)
1514 fprintf(output, "PLUS -");
1515 else if (op->value == 1)
1516 fprintf(output, "PLUS +");
1517 else if (op->value == 2)
1518 fprintf(output, "PLUS unary -");
1519 else if (op->value == 3)
1520 fprintf(output, "PLUS unary - -");
1521 break;
1522 case XPATH_OP_MULT:
1523 if (op->value == 0)
1524 fprintf(output, "MULT *");
1525 else if (op->value == 1)
1526 fprintf(output, "MULT div");
1527 else
1528 fprintf(output, "MULT mod");
1529 break;
1530 case XPATH_OP_UNION:
1531 fprintf(output, "UNION"); break;
1532 case XPATH_OP_ROOT:
1533 fprintf(output, "ROOT"); break;
1534 case XPATH_OP_NODE:
1535 fprintf(output, "NODE"); break;
1536 case XPATH_OP_RESET:
1537 fprintf(output, "RESET"); break;
1538 case XPATH_OP_SORT:
1539 fprintf(output, "SORT"); break;
1540 case XPATH_OP_COLLECT: {
1541 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1542 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1543 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1544 const xmlChar *prefix = op->value4;
1545 const xmlChar *name = op->value5;
1546
1547 fprintf(output, "COLLECT ");
1548 switch (axis) {
1549 case AXIS_ANCESTOR:
1550 fprintf(output, " 'ancestors' "); break;
1551 case AXIS_ANCESTOR_OR_SELF:
1552 fprintf(output, " 'ancestors-or-self' "); break;
1553 case AXIS_ATTRIBUTE:
1554 fprintf(output, " 'attributes' "); break;
1555 case AXIS_CHILD:
1556 fprintf(output, " 'child' "); break;
1557 case AXIS_DESCENDANT:
1558 fprintf(output, " 'descendant' "); break;
1559 case AXIS_DESCENDANT_OR_SELF:
1560 fprintf(output, " 'descendant-or-self' "); break;
1561 case AXIS_FOLLOWING:
1562 fprintf(output, " 'following' "); break;
1563 case AXIS_FOLLOWING_SIBLING:
1564 fprintf(output, " 'following-siblings' "); break;
1565 case AXIS_NAMESPACE:
1566 fprintf(output, " 'namespace' "); break;
1567 case AXIS_PARENT:
1568 fprintf(output, " 'parent' "); break;
1569 case AXIS_PRECEDING:
1570 fprintf(output, " 'preceding' "); break;
1571 case AXIS_PRECEDING_SIBLING:
1572 fprintf(output, " 'preceding-sibling' "); break;
1573 case AXIS_SELF:
1574 fprintf(output, " 'self' "); break;
1575 }
1576 switch (test) {
1577 case NODE_TEST_NONE:
1578 fprintf(output, "'none' "); break;
1579 case NODE_TEST_TYPE:
1580 fprintf(output, "'type' "); break;
1581 case NODE_TEST_PI:
1582 fprintf(output, "'PI' "); break;
1583 case NODE_TEST_ALL:
1584 fprintf(output, "'all' "); break;
1585 case NODE_TEST_NS:
1586 fprintf(output, "'namespace' "); break;
1587 case NODE_TEST_NAME:
1588 fprintf(output, "'name' "); break;
1589 }
1590 switch (type) {
1591 case NODE_TYPE_NODE:
1592 fprintf(output, "'node' "); break;
1593 case NODE_TYPE_COMMENT:
1594 fprintf(output, "'comment' "); break;
1595 case NODE_TYPE_TEXT:
1596 fprintf(output, "'text' "); break;
1597 case NODE_TYPE_PI:
1598 fprintf(output, "'PI' "); break;
1599 }
1600 if (prefix != NULL)
1601 fprintf(output, "%s:", prefix);
1602 if (name != NULL)
1603 fprintf(output, "%s", (const char *) name);
1604 break;
1605
1606 }
1607 case XPATH_OP_VALUE: {
1608 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1609
1610 fprintf(output, "ELEM ");
1611 xmlXPathDebugDumpObject(output, object, 0);
1612 goto finish;
1613 }
1614 case XPATH_OP_VARIABLE: {
1615 const xmlChar *prefix = op->value5;
1616 const xmlChar *name = op->value4;
1617
1618 if (prefix != NULL)
1619 fprintf(output, "VARIABLE %s:%s", prefix, name);
1620 else
1621 fprintf(output, "VARIABLE %s", name);
1622 break;
1623 }
1624 case XPATH_OP_FUNCTION: {
1625 int nbargs = op->value;
1626 const xmlChar *prefix = op->value5;
1627 const xmlChar *name = op->value4;
1628
1629 if (prefix != NULL)
1630 fprintf(output, "FUNCTION %s:%s(%d args)",
1631 prefix, name, nbargs);
1632 else
1633 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1634 break;
1635 }
1636 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1637 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1638 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1639#ifdef LIBXML_XPTR_ENABLED
1640 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1641#endif
1642 default:
1643 fprintf(output, "UNKNOWN %d\n", op->op); return;
1644 }
1645 fprintf(output, "\n");
1646finish:
1647 if (op->ch1 >= 0)
1648 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1649 if (op->ch2 >= 0)
1650 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1651}
1652
1653/**
1654 * xmlXPathDebugDumpCompExpr:
1655 * @output: the FILE * for the output
1656 * @comp: the precompiled XPath expression
1657 * @depth: the indentation level.
1658 *
1659 * Dumps the tree of the compiled XPath expression.
1660 */
1661void
1662xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1663 int depth) {
1664 int i;
1665 char shift[100];
1666
1667 if ((output == NULL) || (comp == NULL)) return;
1668
1669 for (i = 0;((i < depth) && (i < 25));i++)
1670 shift[2 * i] = shift[2 * i + 1] = ' ';
1671 shift[2 * i] = shift[2 * i + 1] = 0;
1672
1673 fprintf(output, "%s", shift);
1674
1675 fprintf(output, "Compiled Expression : %d elements\n",
1676 comp->nbStep);
1677 i = comp->last;
1678 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1679}
1680
1681#ifdef XP_DEBUG_OBJ_USAGE
1682
1683/*
1684* XPath object usage related debugging variables.
1685*/
1686static int xmlXPathDebugObjCounterUndefined = 0;
1687static int xmlXPathDebugObjCounterNodeset = 0;
1688static int xmlXPathDebugObjCounterBool = 0;
1689static int xmlXPathDebugObjCounterNumber = 0;
1690static int xmlXPathDebugObjCounterString = 0;
1691static int xmlXPathDebugObjCounterPoint = 0;
1692static int xmlXPathDebugObjCounterRange = 0;
1693static int xmlXPathDebugObjCounterLocset = 0;
1694static int xmlXPathDebugObjCounterUsers = 0;
1695static int xmlXPathDebugObjCounterXSLTTree = 0;
1696static int xmlXPathDebugObjCounterAll = 0;
1697
1698static int xmlXPathDebugObjTotalUndefined = 0;
1699static int xmlXPathDebugObjTotalNodeset = 0;
1700static int xmlXPathDebugObjTotalBool = 0;
1701static int xmlXPathDebugObjTotalNumber = 0;
1702static int xmlXPathDebugObjTotalString = 0;
1703static int xmlXPathDebugObjTotalPoint = 0;
1704static int xmlXPathDebugObjTotalRange = 0;
1705static int xmlXPathDebugObjTotalLocset = 0;
1706static int xmlXPathDebugObjTotalUsers = 0;
1707static int xmlXPathDebugObjTotalXSLTTree = 0;
1708static int xmlXPathDebugObjTotalAll = 0;
1709
1710static int xmlXPathDebugObjMaxUndefined = 0;
1711static int xmlXPathDebugObjMaxNodeset = 0;
1712static int xmlXPathDebugObjMaxBool = 0;
1713static int xmlXPathDebugObjMaxNumber = 0;
1714static int xmlXPathDebugObjMaxString = 0;
1715static int xmlXPathDebugObjMaxPoint = 0;
1716static int xmlXPathDebugObjMaxRange = 0;
1717static int xmlXPathDebugObjMaxLocset = 0;
1718static int xmlXPathDebugObjMaxUsers = 0;
1719static int xmlXPathDebugObjMaxXSLTTree = 0;
1720static int xmlXPathDebugObjMaxAll = 0;
1721
1722/* REVISIT TODO: Make this static when committing */
1723static void
1724xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1725{
1726 if (ctxt != NULL) {
1727 if (ctxt->cache != NULL) {
1728 xmlXPathContextCachePtr cache =
1729 (xmlXPathContextCachePtr) ctxt->cache;
1730
1731 cache->dbgCachedAll = 0;
1732 cache->dbgCachedNodeset = 0;
1733 cache->dbgCachedString = 0;
1734 cache->dbgCachedBool = 0;
1735 cache->dbgCachedNumber = 0;
1736 cache->dbgCachedPoint = 0;
1737 cache->dbgCachedRange = 0;
1738 cache->dbgCachedLocset = 0;
1739 cache->dbgCachedUsers = 0;
1740 cache->dbgCachedXSLTTree = 0;
1741 cache->dbgCachedUndefined = 0;
1742
1743 cache->dbgReusedAll = 0;
1744 cache->dbgReusedNodeset = 0;
1745 cache->dbgReusedString = 0;
1746 cache->dbgReusedBool = 0;
1747 cache->dbgReusedNumber = 0;
1748 cache->dbgReusedPoint = 0;
1749 cache->dbgReusedRange = 0;
1750 cache->dbgReusedLocset = 0;
1751 cache->dbgReusedUsers = 0;
1752 cache->dbgReusedXSLTTree = 0;
1753 cache->dbgReusedUndefined = 0;
1754 }
1755 }
1756
1757 xmlXPathDebugObjCounterUndefined = 0;
1758 xmlXPathDebugObjCounterNodeset = 0;
1759 xmlXPathDebugObjCounterBool = 0;
1760 xmlXPathDebugObjCounterNumber = 0;
1761 xmlXPathDebugObjCounterString = 0;
1762 xmlXPathDebugObjCounterPoint = 0;
1763 xmlXPathDebugObjCounterRange = 0;
1764 xmlXPathDebugObjCounterLocset = 0;
1765 xmlXPathDebugObjCounterUsers = 0;
1766 xmlXPathDebugObjCounterXSLTTree = 0;
1767 xmlXPathDebugObjCounterAll = 0;
1768
1769 xmlXPathDebugObjTotalUndefined = 0;
1770 xmlXPathDebugObjTotalNodeset = 0;
1771 xmlXPathDebugObjTotalBool = 0;
1772 xmlXPathDebugObjTotalNumber = 0;
1773 xmlXPathDebugObjTotalString = 0;
1774 xmlXPathDebugObjTotalPoint = 0;
1775 xmlXPathDebugObjTotalRange = 0;
1776 xmlXPathDebugObjTotalLocset = 0;
1777 xmlXPathDebugObjTotalUsers = 0;
1778 xmlXPathDebugObjTotalXSLTTree = 0;
1779 xmlXPathDebugObjTotalAll = 0;
1780
1781 xmlXPathDebugObjMaxUndefined = 0;
1782 xmlXPathDebugObjMaxNodeset = 0;
1783 xmlXPathDebugObjMaxBool = 0;
1784 xmlXPathDebugObjMaxNumber = 0;
1785 xmlXPathDebugObjMaxString = 0;
1786 xmlXPathDebugObjMaxPoint = 0;
1787 xmlXPathDebugObjMaxRange = 0;
1788 xmlXPathDebugObjMaxLocset = 0;
1789 xmlXPathDebugObjMaxUsers = 0;
1790 xmlXPathDebugObjMaxXSLTTree = 0;
1791 xmlXPathDebugObjMaxAll = 0;
1792
1793}
1794
1795static void
1796xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1797 xmlXPathObjectType objType)
1798{
1799 int isCached = 0;
1800
1801 if (ctxt != NULL) {
1802 if (ctxt->cache != NULL) {
1803 xmlXPathContextCachePtr cache =
1804 (xmlXPathContextCachePtr) ctxt->cache;
1805
1806 isCached = 1;
1807
1808 cache->dbgReusedAll++;
1809 switch (objType) {
1810 case XPATH_UNDEFINED:
1811 cache->dbgReusedUndefined++;
1812 break;
1813 case XPATH_NODESET:
1814 cache->dbgReusedNodeset++;
1815 break;
1816 case XPATH_BOOLEAN:
1817 cache->dbgReusedBool++;
1818 break;
1819 case XPATH_NUMBER:
1820 cache->dbgReusedNumber++;
1821 break;
1822 case XPATH_STRING:
1823 cache->dbgReusedString++;
1824 break;
1825 case XPATH_POINT:
1826 cache->dbgReusedPoint++;
1827 break;
1828 case XPATH_RANGE:
1829 cache->dbgReusedRange++;
1830 break;
1831 case XPATH_LOCATIONSET:
1832 cache->dbgReusedLocset++;
1833 break;
1834 case XPATH_USERS:
1835 cache->dbgReusedUsers++;
1836 break;
1837 case XPATH_XSLT_TREE:
1838 cache->dbgReusedXSLTTree++;
1839 break;
1840 default:
1841 break;
1842 }
1843 }
1844 }
1845
1846 switch (objType) {
1847 case XPATH_UNDEFINED:
1848 if (! isCached)
1849 xmlXPathDebugObjTotalUndefined++;
1850 xmlXPathDebugObjCounterUndefined++;
1851 if (xmlXPathDebugObjCounterUndefined >
1852 xmlXPathDebugObjMaxUndefined)
1853 xmlXPathDebugObjMaxUndefined =
1854 xmlXPathDebugObjCounterUndefined;
1855 break;
1856 case XPATH_NODESET:
1857 if (! isCached)
1858 xmlXPathDebugObjTotalNodeset++;
1859 xmlXPathDebugObjCounterNodeset++;
1860 if (xmlXPathDebugObjCounterNodeset >
1861 xmlXPathDebugObjMaxNodeset)
1862 xmlXPathDebugObjMaxNodeset =
1863 xmlXPathDebugObjCounterNodeset;
1864 break;
1865 case XPATH_BOOLEAN:
1866 if (! isCached)
1867 xmlXPathDebugObjTotalBool++;
1868 xmlXPathDebugObjCounterBool++;
1869 if (xmlXPathDebugObjCounterBool >
1870 xmlXPathDebugObjMaxBool)
1871 xmlXPathDebugObjMaxBool =
1872 xmlXPathDebugObjCounterBool;
1873 break;
1874 case XPATH_NUMBER:
1875 if (! isCached)
1876 xmlXPathDebugObjTotalNumber++;
1877 xmlXPathDebugObjCounterNumber++;
1878 if (xmlXPathDebugObjCounterNumber >
1879 xmlXPathDebugObjMaxNumber)
1880 xmlXPathDebugObjMaxNumber =
1881 xmlXPathDebugObjCounterNumber;
1882 break;
1883 case XPATH_STRING:
1884 if (! isCached)
1885 xmlXPathDebugObjTotalString++;
1886 xmlXPathDebugObjCounterString++;
1887 if (xmlXPathDebugObjCounterString >
1888 xmlXPathDebugObjMaxString)
1889 xmlXPathDebugObjMaxString =
1890 xmlXPathDebugObjCounterString;
1891 break;
1892 case XPATH_POINT:
1893 if (! isCached)
1894 xmlXPathDebugObjTotalPoint++;
1895 xmlXPathDebugObjCounterPoint++;
1896 if (xmlXPathDebugObjCounterPoint >
1897 xmlXPathDebugObjMaxPoint)
1898 xmlXPathDebugObjMaxPoint =
1899 xmlXPathDebugObjCounterPoint;
1900 break;
1901 case XPATH_RANGE:
1902 if (! isCached)
1903 xmlXPathDebugObjTotalRange++;
1904 xmlXPathDebugObjCounterRange++;
1905 if (xmlXPathDebugObjCounterRange >
1906 xmlXPathDebugObjMaxRange)
1907 xmlXPathDebugObjMaxRange =
1908 xmlXPathDebugObjCounterRange;
1909 break;
1910 case XPATH_LOCATIONSET:
1911 if (! isCached)
1912 xmlXPathDebugObjTotalLocset++;
1913 xmlXPathDebugObjCounterLocset++;
1914 if (xmlXPathDebugObjCounterLocset >
1915 xmlXPathDebugObjMaxLocset)
1916 xmlXPathDebugObjMaxLocset =
1917 xmlXPathDebugObjCounterLocset;
1918 break;
1919 case XPATH_USERS:
1920 if (! isCached)
1921 xmlXPathDebugObjTotalUsers++;
1922 xmlXPathDebugObjCounterUsers++;
1923 if (xmlXPathDebugObjCounterUsers >
1924 xmlXPathDebugObjMaxUsers)
1925 xmlXPathDebugObjMaxUsers =
1926 xmlXPathDebugObjCounterUsers;
1927 break;
1928 case XPATH_XSLT_TREE:
1929 if (! isCached)
1930 xmlXPathDebugObjTotalXSLTTree++;
1931 xmlXPathDebugObjCounterXSLTTree++;
1932 if (xmlXPathDebugObjCounterXSLTTree >
1933 xmlXPathDebugObjMaxXSLTTree)
1934 xmlXPathDebugObjMaxXSLTTree =
1935 xmlXPathDebugObjCounterXSLTTree;
1936 break;
1937 default:
1938 break;
1939 }
1940 if (! isCached)
1941 xmlXPathDebugObjTotalAll++;
1942 xmlXPathDebugObjCounterAll++;
1943 if (xmlXPathDebugObjCounterAll >
1944 xmlXPathDebugObjMaxAll)
1945 xmlXPathDebugObjMaxAll =
1946 xmlXPathDebugObjCounterAll;
1947}
1948
1949static void
1950xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1951 xmlXPathObjectType objType)
1952{
1953 int isCached = 0;
1954
1955 if (ctxt != NULL) {
1956 if (ctxt->cache != NULL) {
1957 xmlXPathContextCachePtr cache =
1958 (xmlXPathContextCachePtr) ctxt->cache;
1959
1960 isCached = 1;
1961
1962 cache->dbgCachedAll++;
1963 switch (objType) {
1964 case XPATH_UNDEFINED:
1965 cache->dbgCachedUndefined++;
1966 break;
1967 case XPATH_NODESET:
1968 cache->dbgCachedNodeset++;
1969 break;
1970 case XPATH_BOOLEAN:
1971 cache->dbgCachedBool++;
1972 break;
1973 case XPATH_NUMBER:
1974 cache->dbgCachedNumber++;
1975 break;
1976 case XPATH_STRING:
1977 cache->dbgCachedString++;
1978 break;
1979 case XPATH_POINT:
1980 cache->dbgCachedPoint++;
1981 break;
1982 case XPATH_RANGE:
1983 cache->dbgCachedRange++;
1984 break;
1985 case XPATH_LOCATIONSET:
1986 cache->dbgCachedLocset++;
1987 break;
1988 case XPATH_USERS:
1989 cache->dbgCachedUsers++;
1990 break;
1991 case XPATH_XSLT_TREE:
1992 cache->dbgCachedXSLTTree++;
1993 break;
1994 default:
1995 break;
1996 }
1997
1998 }
1999 }
2000 switch (objType) {
2001 case XPATH_UNDEFINED:
2002 xmlXPathDebugObjCounterUndefined--;
2003 break;
2004 case XPATH_NODESET:
2005 xmlXPathDebugObjCounterNodeset--;
2006 break;
2007 case XPATH_BOOLEAN:
2008 xmlXPathDebugObjCounterBool--;
2009 break;
2010 case XPATH_NUMBER:
2011 xmlXPathDebugObjCounterNumber--;
2012 break;
2013 case XPATH_STRING:
2014 xmlXPathDebugObjCounterString--;
2015 break;
2016 case XPATH_POINT:
2017 xmlXPathDebugObjCounterPoint--;
2018 break;
2019 case XPATH_RANGE:
2020 xmlXPathDebugObjCounterRange--;
2021 break;
2022 case XPATH_LOCATIONSET:
2023 xmlXPathDebugObjCounterLocset--;
2024 break;
2025 case XPATH_USERS:
2026 xmlXPathDebugObjCounterUsers--;
2027 break;
2028 case XPATH_XSLT_TREE:
2029 xmlXPathDebugObjCounterXSLTTree--;
2030 break;
2031 default:
2032 break;
2033 }
2034 xmlXPathDebugObjCounterAll--;
2035}
2036
2037/* REVISIT TODO: Make this static when committing */
2038static void
2039xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2040{
2041 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2042 reqXSLTTree, reqUndefined;
2043 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2044 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2045 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2046 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2047 int leftObjs = xmlXPathDebugObjCounterAll;
2048
2049 reqAll = xmlXPathDebugObjTotalAll;
2050 reqNodeset = xmlXPathDebugObjTotalNodeset;
2051 reqString = xmlXPathDebugObjTotalString;
2052 reqBool = xmlXPathDebugObjTotalBool;
2053 reqNumber = xmlXPathDebugObjTotalNumber;
2054 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2055 reqUndefined = xmlXPathDebugObjTotalUndefined;
2056
2057 printf("# XPath object usage:\n");
2058
2059 if (ctxt != NULL) {
2060 if (ctxt->cache != NULL) {
2061 xmlXPathContextCachePtr cache =
2062 (xmlXPathContextCachePtr) ctxt->cache;
2063
2064 reAll = cache->dbgReusedAll;
2065 reqAll += reAll;
2066 reNodeset = cache->dbgReusedNodeset;
2067 reqNodeset += reNodeset;
2068 reString = cache->dbgReusedString;
2069 reqString += reString;
2070 reBool = cache->dbgReusedBool;
2071 reqBool += reBool;
2072 reNumber = cache->dbgReusedNumber;
2073 reqNumber += reNumber;
2074 reXSLTTree = cache->dbgReusedXSLTTree;
2075 reqXSLTTree += reXSLTTree;
2076 reUndefined = cache->dbgReusedUndefined;
2077 reqUndefined += reUndefined;
2078
2079 caAll = cache->dbgCachedAll;
2080 caBool = cache->dbgCachedBool;
2081 caNodeset = cache->dbgCachedNodeset;
2082 caString = cache->dbgCachedString;
2083 caNumber = cache->dbgCachedNumber;
2084 caXSLTTree = cache->dbgCachedXSLTTree;
2085 caUndefined = cache->dbgCachedUndefined;
2086
2087 if (cache->nodesetObjs)
2088 leftObjs -= cache->nodesetObjs->number;
2089 if (cache->stringObjs)
2090 leftObjs -= cache->stringObjs->number;
2091 if (cache->booleanObjs)
2092 leftObjs -= cache->booleanObjs->number;
2093 if (cache->numberObjs)
2094 leftObjs -= cache->numberObjs->number;
2095 if (cache->miscObjs)
2096 leftObjs -= cache->miscObjs->number;
2097 }
2098 }
2099
2100 printf("# all\n");
2101 printf("# total : %d\n", reqAll);
2102 printf("# left : %d\n", leftObjs);
2103 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2104 printf("# reused : %d\n", reAll);
2105 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2106
2107 printf("# node-sets\n");
2108 printf("# total : %d\n", reqNodeset);
2109 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2110 printf("# reused : %d\n", reNodeset);
2111 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2112
2113 printf("# strings\n");
2114 printf("# total : %d\n", reqString);
2115 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2116 printf("# reused : %d\n", reString);
2117 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2118
2119 printf("# booleans\n");
2120 printf("# total : %d\n", reqBool);
2121 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2122 printf("# reused : %d\n", reBool);
2123 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2124
2125 printf("# numbers\n");
2126 printf("# total : %d\n", reqNumber);
2127 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2128 printf("# reused : %d\n", reNumber);
2129 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2130
2131 printf("# XSLT result tree fragments\n");
2132 printf("# total : %d\n", reqXSLTTree);
2133 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2134 printf("# reused : %d\n", reXSLTTree);
2135 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2136
2137 printf("# undefined\n");
2138 printf("# total : %d\n", reqUndefined);
2139 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2140 printf("# reused : %d\n", reUndefined);
2141 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2142
2143}
2144
2145#endif /* XP_DEBUG_OBJ_USAGE */
2146
2147#endif /* LIBXML_DEBUG_ENABLED */
2148
2149/************************************************************************
2150 * *
2151 * XPath object caching *
2152 * *
2153 ************************************************************************/
2154
2155/**
2156 * xmlXPathNewCache:
2157 *
2158 * Create a new object cache
2159 *
2160 * Returns the xmlXPathCache just allocated.
2161 */
2162static xmlXPathContextCachePtr
2163xmlXPathNewCache(void)
2164{
2165 xmlXPathContextCachePtr ret;
2166
2167 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2168 if (ret == NULL) {
2169 xmlXPathErrMemory(NULL, "creating object cache\n");
2170 return(NULL);
2171 }
2172 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2173 ret->maxNodeset = 100;
2174 ret->maxString = 100;
2175 ret->maxBoolean = 100;
2176 ret->maxNumber = 100;
2177 ret->maxMisc = 100;
2178 return(ret);
2179}
2180
2181static void
2182xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2183{
2184 int i;
2185 xmlXPathObjectPtr obj;
2186
2187 if (list == NULL)
2188 return;
2189
2190 for (i = 0; i < list->number; i++) {
2191 obj = list->items[i];
2192 /*
2193 * Note that it is already assured that we don't need to
2194 * look out for namespace nodes in the node-set.
2195 */
2196 if (obj->nodesetval != NULL) {
2197 if (obj->nodesetval->nodeTab != NULL)
2198 xmlFree(obj->nodesetval->nodeTab);
2199 xmlFree(obj->nodesetval);
2200 }
2201 xmlFree(obj);
2202#ifdef XP_DEBUG_OBJ_USAGE
2203 xmlXPathDebugObjCounterAll--;
2204#endif
2205 }
2206 xmlPointerListFree(list);
2207}
2208
2209static void
2210xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2211{
2212 if (cache == NULL)
2213 return;
2214 if (cache->nodesetObjs)
2215 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2216 if (cache->stringObjs)
2217 xmlXPathCacheFreeObjectList(cache->stringObjs);
2218 if (cache->booleanObjs)
2219 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2220 if (cache->numberObjs)
2221 xmlXPathCacheFreeObjectList(cache->numberObjs);
2222 if (cache->miscObjs)
2223 xmlXPathCacheFreeObjectList(cache->miscObjs);
2224 xmlFree(cache);
2225}
2226
2227/**
2228 * xmlXPathContextSetCache:
2229 *
2230 * @ctxt: the XPath context
2231 * @active: enables/disables (creates/frees) the cache
2232 * @value: a value with semantics dependant on @options
2233 * @options: options (currently only the value 0 is used)
2234 *
2235 * Creates/frees an object cache on the XPath context.
2236 * If activates XPath objects (xmlXPathObject) will be cached internally
2237 * to be reused.
2238 * @options:
2239 * 0: This will set the XPath object caching:
2240 * @value:
2241 * This will set the maximum number of XPath objects
2242 * to be cached per slot
2243 * There are 5 slots for: node-set, string, number, boolean, and
2244 * misc objects. Use <0 for the default number (100).
2245 * Other values for @options have currently no effect.
2246 *
2247 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2248 */
2249int
2250xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2251 int active,
2252 int value,
2253 int options)
2254{
2255 if (ctxt == NULL)
2256 return(-1);
2257 if (active) {
2258 xmlXPathContextCachePtr cache;
2259
2260 if (ctxt->cache == NULL) {
2261 ctxt->cache = xmlXPathNewCache();
2262 if (ctxt->cache == NULL)
2263 return(-1);
2264 }
2265 cache = (xmlXPathContextCachePtr) ctxt->cache;
2266 if (options == 0) {
2267 if (value < 0)
2268 value = 100;
2269 cache->maxNodeset = value;
2270 cache->maxString = value;
2271 cache->maxNumber = value;
2272 cache->maxBoolean = value;
2273 cache->maxMisc = value;
2274 }
2275 } else if (ctxt->cache != NULL) {
2276 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2277 ctxt->cache = NULL;
2278 }
2279 return(0);
2280}
2281
2282/**
2283 * xmlXPathCacheWrapNodeSet:
2284 * @ctxt: the XPath context
2285 * @val: the NodePtr value
2286 *
2287 * This is the cached version of xmlXPathWrapNodeSet().
2288 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2289 *
2290 * Returns the created or reused object.
2291 */
2292static xmlXPathObjectPtr
2293xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2294{
2295 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2296 xmlXPathContextCachePtr cache =
2297 (xmlXPathContextCachePtr) ctxt->cache;
2298
2299 if ((cache->miscObjs != NULL) &&
2300 (cache->miscObjs->number != 0))
2301 {
2302 xmlXPathObjectPtr ret;
2303
2304 ret = (xmlXPathObjectPtr)
2305 cache->miscObjs->items[--cache->miscObjs->number];
2306 ret->type = XPATH_NODESET;
2307 ret->nodesetval = val;
2308#ifdef XP_DEBUG_OBJ_USAGE
2309 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2310#endif
2311 return(ret);
2312 }
2313 }
2314
2315 return(xmlXPathWrapNodeSet(val));
2316
2317}
2318
2319/**
2320 * xmlXPathCacheWrapString:
2321 * @ctxt: the XPath context
2322 * @val: the xmlChar * value
2323 *
2324 * This is the cached version of xmlXPathWrapString().
2325 * Wraps the @val string into an XPath object.
2326 *
2327 * Returns the created or reused object.
2328 */
2329static xmlXPathObjectPtr
2330xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2331{
2332 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2333 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2334
2335 if ((cache->stringObjs != NULL) &&
2336 (cache->stringObjs->number != 0))
2337 {
2338
2339 xmlXPathObjectPtr ret;
2340
2341 ret = (xmlXPathObjectPtr)
2342 cache->stringObjs->items[--cache->stringObjs->number];
2343 ret->type = XPATH_STRING;
2344 ret->stringval = val;
2345#ifdef XP_DEBUG_OBJ_USAGE
2346 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2347#endif
2348 return(ret);
2349 } else if ((cache->miscObjs != NULL) &&
2350 (cache->miscObjs->number != 0))
2351 {
2352 xmlXPathObjectPtr ret;
2353 /*
2354 * Fallback to misc-cache.
2355 */
2356 ret = (xmlXPathObjectPtr)
2357 cache->miscObjs->items[--cache->miscObjs->number];
2358
2359 ret->type = XPATH_STRING;
2360 ret->stringval = val;
2361#ifdef XP_DEBUG_OBJ_USAGE
2362 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2363#endif
2364 return(ret);
2365 }
2366 }
2367 return(xmlXPathWrapString(val));
2368}
2369
2370/**
2371 * xmlXPathCacheNewNodeSet:
2372 * @ctxt: the XPath context
2373 * @val: the NodePtr value
2374 *
2375 * This is the cached version of xmlXPathNewNodeSet().
2376 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2377 * it with the single Node @val
2378 *
2379 * Returns the created or reused object.
2380 */
2381static xmlXPathObjectPtr
2382xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2383{
2384 if ((ctxt != NULL) && (ctxt->cache)) {
2385 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2386
2387 if ((cache->nodesetObjs != NULL) &&
2388 (cache->nodesetObjs->number != 0))
2389 {
2390 xmlXPathObjectPtr ret;
2391 /*
2392 * Use the nodset-cache.
2393 */
2394 ret = (xmlXPathObjectPtr)
2395 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2396 ret->type = XPATH_NODESET;
2397 ret->boolval = 0;
2398 if (val) {
2399 if ((ret->nodesetval->nodeMax == 0) ||
2400 (val->type == XML_NAMESPACE_DECL))
2401 {
2402 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2403 } else {
2404 ret->nodesetval->nodeTab[0] = val;
2405 ret->nodesetval->nodeNr = 1;
2406 }
2407 }
2408#ifdef XP_DEBUG_OBJ_USAGE
2409 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2410#endif
2411 return(ret);
2412 } else if ((cache->miscObjs != NULL) &&
2413 (cache->miscObjs->number != 0))
2414 {
2415 xmlXPathObjectPtr ret;
2416 /*
2417 * Fallback to misc-cache.
2418 */
2419
2420 ret = (xmlXPathObjectPtr)
2421 cache->miscObjs->items[--cache->miscObjs->number];
2422
2423 ret->type = XPATH_NODESET;
2424 ret->boolval = 0;
2425 ret->nodesetval = xmlXPathNodeSetCreate(val);
2426 if (ret->nodesetval == NULL) {
2427 ctxt->lastError.domain = XML_FROM_XPATH;
2428 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2429 return(NULL);
2430 }
2431#ifdef XP_DEBUG_OBJ_USAGE
2432 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2433#endif
2434 return(ret);
2435 }
2436 }
2437 return(xmlXPathNewNodeSet(val));
2438}
2439
2440/**
2441 * xmlXPathCacheNewCString:
2442 * @ctxt: the XPath context
2443 * @val: the char * value
2444 *
2445 * This is the cached version of xmlXPathNewCString().
2446 * Acquire an xmlXPathObjectPtr of type string and of value @val
2447 *
2448 * Returns the created or reused object.
2449 */
2450static xmlXPathObjectPtr
2451xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2452{
2453 if ((ctxt != NULL) && (ctxt->cache)) {
2454 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2455
2456 if ((cache->stringObjs != NULL) &&
2457 (cache->stringObjs->number != 0))
2458 {
2459 xmlXPathObjectPtr ret;
2460
2461 ret = (xmlXPathObjectPtr)
2462 cache->stringObjs->items[--cache->stringObjs->number];
2463
2464 ret->type = XPATH_STRING;
2465 ret->stringval = xmlStrdup(BAD_CAST val);
2466#ifdef XP_DEBUG_OBJ_USAGE
2467 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2468#endif
2469 return(ret);
2470 } else if ((cache->miscObjs != NULL) &&
2471 (cache->miscObjs->number != 0))
2472 {
2473 xmlXPathObjectPtr ret;
2474
2475 ret = (xmlXPathObjectPtr)
2476 cache->miscObjs->items[--cache->miscObjs->number];
2477
2478 ret->type = XPATH_STRING;
2479 ret->stringval = xmlStrdup(BAD_CAST val);
2480#ifdef XP_DEBUG_OBJ_USAGE
2481 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2482#endif
2483 return(ret);
2484 }
2485 }
2486 return(xmlXPathNewCString(val));
2487}
2488
2489/**
2490 * xmlXPathCacheNewString:
2491 * @ctxt: the XPath context
2492 * @val: the xmlChar * value
2493 *
2494 * This is the cached version of xmlXPathNewString().
2495 * Acquire an xmlXPathObjectPtr of type string and of value @val
2496 *
2497 * Returns the created or reused object.
2498 */
2499static xmlXPathObjectPtr
2500xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2501{
2502 if ((ctxt != NULL) && (ctxt->cache)) {
2503 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2504
2505 if ((cache->stringObjs != NULL) &&
2506 (cache->stringObjs->number != 0))
2507 {
2508 xmlXPathObjectPtr ret;
2509
2510 ret = (xmlXPathObjectPtr)
2511 cache->stringObjs->items[--cache->stringObjs->number];
2512 ret->type = XPATH_STRING;
2513 if (val != NULL)
2514 ret->stringval = xmlStrdup(val);
2515 else
2516 ret->stringval = xmlStrdup((const xmlChar *)"");
2517#ifdef XP_DEBUG_OBJ_USAGE
2518 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2519#endif
2520 return(ret);
2521 } else if ((cache->miscObjs != NULL) &&
2522 (cache->miscObjs->number != 0))
2523 {
2524 xmlXPathObjectPtr ret;
2525
2526 ret = (xmlXPathObjectPtr)
2527 cache->miscObjs->items[--cache->miscObjs->number];
2528
2529 ret->type = XPATH_STRING;
2530 if (val != NULL)
2531 ret->stringval = xmlStrdup(val);
2532 else
2533 ret->stringval = xmlStrdup((const xmlChar *)"");
2534#ifdef XP_DEBUG_OBJ_USAGE
2535 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2536#endif
2537 return(ret);
2538 }
2539 }
2540 return(xmlXPathNewString(val));
2541}
2542
2543/**
2544 * xmlXPathCacheNewBoolean:
2545 * @ctxt: the XPath context
2546 * @val: the boolean value
2547 *
2548 * This is the cached version of xmlXPathNewBoolean().
2549 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2550 *
2551 * Returns the created or reused object.
2552 */
2553static xmlXPathObjectPtr
2554xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2555{
2556 if ((ctxt != NULL) && (ctxt->cache)) {
2557 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2558
2559 if ((cache->booleanObjs != NULL) &&
2560 (cache->booleanObjs->number != 0))
2561 {
2562 xmlXPathObjectPtr ret;
2563
2564 ret = (xmlXPathObjectPtr)
2565 cache->booleanObjs->items[--cache->booleanObjs->number];
2566 ret->type = XPATH_BOOLEAN;
2567 ret->boolval = (val != 0);
2568#ifdef XP_DEBUG_OBJ_USAGE
2569 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2570#endif
2571 return(ret);
2572 } else if ((cache->miscObjs != NULL) &&
2573 (cache->miscObjs->number != 0))
2574 {
2575 xmlXPathObjectPtr ret;
2576
2577 ret = (xmlXPathObjectPtr)
2578 cache->miscObjs->items[--cache->miscObjs->number];
2579
2580 ret->type = XPATH_BOOLEAN;
2581 ret->boolval = (val != 0);
2582#ifdef XP_DEBUG_OBJ_USAGE
2583 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2584#endif
2585 return(ret);
2586 }
2587 }
2588 return(xmlXPathNewBoolean(val));
2589}
2590
2591/**
2592 * xmlXPathCacheNewFloat:
2593 * @ctxt: the XPath context
2594 * @val: the double value
2595 *
2596 * This is the cached version of xmlXPathNewFloat().
2597 * Acquires an xmlXPathObjectPtr of type double and of value @val
2598 *
2599 * Returns the created or reused object.
2600 */
2601static xmlXPathObjectPtr
2602xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2603{
2604 if ((ctxt != NULL) && (ctxt->cache)) {
2605 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2606
2607 if ((cache->numberObjs != NULL) &&
2608 (cache->numberObjs->number != 0))
2609 {
2610 xmlXPathObjectPtr ret;
2611
2612 ret = (xmlXPathObjectPtr)
2613 cache->numberObjs->items[--cache->numberObjs->number];
2614 ret->type = XPATH_NUMBER;
2615 ret->floatval = val;
2616#ifdef XP_DEBUG_OBJ_USAGE
2617 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2618#endif
2619 return(ret);
2620 } else if ((cache->miscObjs != NULL) &&
2621 (cache->miscObjs->number != 0))
2622 {
2623 xmlXPathObjectPtr ret;
2624
2625 ret = (xmlXPathObjectPtr)
2626 cache->miscObjs->items[--cache->miscObjs->number];
2627
2628 ret->type = XPATH_NUMBER;
2629 ret->floatval = val;
2630#ifdef XP_DEBUG_OBJ_USAGE
2631 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2632#endif
2633 return(ret);
2634 }
2635 }
2636 return(xmlXPathNewFloat(val));
2637}
2638
2639/**
2640 * xmlXPathCacheConvertString:
2641 * @ctxt: the XPath context
2642 * @val: an XPath object
2643 *
2644 * This is the cached version of xmlXPathConvertString().
2645 * Converts an existing object to its string() equivalent
2646 *
2647 * Returns a created or reused object, the old one is freed (cached)
2648 * (or the operation is done directly on @val)
2649 */
2650
2651static xmlXPathObjectPtr
2652xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2653 xmlChar *res = NULL;
2654
2655 if (val == NULL)
2656 return(xmlXPathCacheNewCString(ctxt, ""));
2657
2658 switch (val->type) {
2659 case XPATH_UNDEFINED:
2660#ifdef DEBUG_EXPR
2661 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2662#endif
2663 break;
2664 case XPATH_NODESET:
2665 case XPATH_XSLT_TREE:
2666 res = xmlXPathCastNodeSetToString(val->nodesetval);
2667 break;
2668 case XPATH_STRING:
2669 return(val);
2670 case XPATH_BOOLEAN:
2671 res = xmlXPathCastBooleanToString(val->boolval);
2672 break;
2673 case XPATH_NUMBER:
2674 res = xmlXPathCastNumberToString(val->floatval);
2675 break;
2676 case XPATH_USERS:
2677 case XPATH_POINT:
2678 case XPATH_RANGE:
2679 case XPATH_LOCATIONSET:
2680 TODO;
2681 break;
2682 }
2683 xmlXPathReleaseObject(ctxt, val);
2684 if (res == NULL)
2685 return(xmlXPathCacheNewCString(ctxt, ""));
2686 return(xmlXPathCacheWrapString(ctxt, res));
2687}
2688
2689/**
2690 * xmlXPathCacheObjectCopy:
2691 * @ctxt: the XPath context
2692 * @val: the original object
2693 *
2694 * This is the cached version of xmlXPathObjectCopy().
2695 * Acquire a copy of a given object
2696 *
2697 * Returns a created or reused created object.
2698 */
2699static xmlXPathObjectPtr
2700xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2701{
2702 if (val == NULL)
2703 return(NULL);
2704
2705 if (XP_HAS_CACHE(ctxt)) {
2706 switch (val->type) {
2707 case XPATH_NODESET:
2708 return(xmlXPathCacheWrapNodeSet(ctxt,
2709 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2710 case XPATH_STRING:
2711 return(xmlXPathCacheNewString(ctxt, val->stringval));
2712 case XPATH_BOOLEAN:
2713 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2714 case XPATH_NUMBER:
2715 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2716 default:
2717 break;
2718 }
2719 }
2720 return(xmlXPathObjectCopy(val));
2721}
2722
2723/**
2724 * xmlXPathCacheConvertBoolean:
2725 * @ctxt: the XPath context
2726 * @val: an XPath object
2727 *
2728 * This is the cached version of xmlXPathConvertBoolean().
2729 * Converts an existing object to its boolean() equivalent
2730 *
2731 * Returns a created or reused object, the old one is freed (or the operation
2732 * is done directly on @val)
2733 */
2734static xmlXPathObjectPtr
2735xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2736 xmlXPathObjectPtr ret;
2737
2738 if (val == NULL)
2739 return(xmlXPathCacheNewBoolean(ctxt, 0));
2740 if (val->type == XPATH_BOOLEAN)
2741 return(val);
2742 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2743 xmlXPathReleaseObject(ctxt, val);
2744 return(ret);
2745}
2746
2747/**
2748 * xmlXPathCacheConvertNumber:
2749 * @ctxt: the XPath context
2750 * @val: an XPath object
2751 *
2752 * This is the cached version of xmlXPathConvertNumber().
2753 * Converts an existing object to its number() equivalent
2754 *
2755 * Returns a created or reused object, the old one is freed (or the operation
2756 * is done directly on @val)
2757 */
2758static xmlXPathObjectPtr
2759xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2760 xmlXPathObjectPtr ret;
2761
2762 if (val == NULL)
2763 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2764 if (val->type == XPATH_NUMBER)
2765 return(val);
2766 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2767 xmlXPathReleaseObject(ctxt, val);
2768 return(ret);
2769}
2770
2771/************************************************************************
2772 * *
2773 * Parser stacks related functions and macros *
2774 * *
2775 ************************************************************************/
2776
2777/**
2778 * xmlXPathSetFrame:
2779 * @ctxt: an XPath parser context
2780 *
2781 * Set the callee evaluation frame
2782 *
2783 * Returns the previous frame value to be restored once done
2784 */
2785static int
2786xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2787 int ret;
2788
2789 if (ctxt == NULL)
2790 return(0);
2791 ret = ctxt->valueFrame;
2792 ctxt->valueFrame = ctxt->valueNr;
2793 return(ret);
2794}
2795
2796/**
2797 * xmlXPathPopFrame:
2798 * @ctxt: an XPath parser context
2799 * @frame: the previous frame value
2800 *
2801 * Remove the callee evaluation frame
2802 */
2803static void
2804xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2805 if (ctxt == NULL)
2806 return;
2807 if (ctxt->valueNr < ctxt->valueFrame) {
2808 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2809 }
2810 ctxt->valueFrame = frame;
2811}
2812
2813/**
2814 * valuePop:
2815 * @ctxt: an XPath evaluation context
2816 *
2817 * Pops the top XPath object from the value stack
2818 *
2819 * Returns the XPath object just removed
2820 */
2821xmlXPathObjectPtr
2822valuePop(xmlXPathParserContextPtr ctxt)
2823{
2824 xmlXPathObjectPtr ret;
2825
2826 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2827 return (NULL);
2828
2829 if (ctxt->valueNr <= ctxt->valueFrame) {
2830 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2831 return (NULL);
2832 }
2833
2834 ctxt->valueNr--;
2835 if (ctxt->valueNr > 0)
2836 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2837 else
2838 ctxt->value = NULL;
2839 ret = ctxt->valueTab[ctxt->valueNr];
2840 ctxt->valueTab[ctxt->valueNr] = NULL;
2841 return (ret);
2842}
2843/**
2844 * valuePush:
2845 * @ctxt: an XPath evaluation context
2846 * @value: the XPath object
2847 *
2848 * Pushes a new XPath object on top of the value stack
2849 *
2850 * returns the number of items on the value stack
2851 */
2852int
2853valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2854{
2855 if ((ctxt == NULL) || (value == NULL)) return(-1);
2856 if (ctxt->valueNr >= ctxt->valueMax) {
2857 xmlXPathObjectPtr *tmp;
2858
2859 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2860 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2861 ctxt->error = XPATH_MEMORY_ERROR;
2862 return (0);
2863 }
2864 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2865 2 * ctxt->valueMax *
2866 sizeof(ctxt->valueTab[0]));
2867 if (tmp == NULL) {
2868 xmlXPathErrMemory(NULL, "pushing value\n");
2869 ctxt->error = XPATH_MEMORY_ERROR;
2870 return (0);
2871 }
2872 ctxt->valueMax *= 2;
2873 ctxt->valueTab = tmp;
2874 }
2875 ctxt->valueTab[ctxt->valueNr] = value;
2876 ctxt->value = value;
2877 return (ctxt->valueNr++);
2878}
2879
2880/**
2881 * xmlXPathPopBoolean:
2882 * @ctxt: an XPath parser context
2883 *
2884 * Pops a boolean from the stack, handling conversion if needed.
2885 * Check error with #xmlXPathCheckError.
2886 *
2887 * Returns the boolean
2888 */
2889int
2890xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2891 xmlXPathObjectPtr obj;
2892 int ret;
2893
2894 obj = valuePop(ctxt);
2895 if (obj == NULL) {
2896 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2897 return(0);
2898 }
2899 if (obj->type != XPATH_BOOLEAN)
2900 ret = xmlXPathCastToBoolean(obj);
2901 else
2902 ret = obj->boolval;
2903 xmlXPathReleaseObject(ctxt->context, obj);
2904 return(ret);
2905}
2906
2907/**
2908 * xmlXPathPopNumber:
2909 * @ctxt: an XPath parser context
2910 *
2911 * Pops a number from the stack, handling conversion if needed.
2912 * Check error with #xmlXPathCheckError.
2913 *
2914 * Returns the number
2915 */
2916double
2917xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2918 xmlXPathObjectPtr obj;
2919 double ret;
2920
2921 obj = valuePop(ctxt);
2922 if (obj == NULL) {
2923 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2924 return(0);
2925 }
2926 if (obj->type != XPATH_NUMBER)
2927 ret = xmlXPathCastToNumber(obj);
2928 else
2929 ret = obj->floatval;
2930 xmlXPathReleaseObject(ctxt->context, obj);
2931 return(ret);
2932}
2933
2934/**
2935 * xmlXPathPopString:
2936 * @ctxt: an XPath parser context
2937 *
2938 * Pops a string from the stack, handling conversion if needed.
2939 * Check error with #xmlXPathCheckError.
2940 *
2941 * Returns the string
2942 */
2943xmlChar *
2944xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2945 xmlXPathObjectPtr obj;
2946 xmlChar * ret;
2947
2948 obj = valuePop(ctxt);
2949 if (obj == NULL) {
2950 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2951 return(NULL);
2952 }
2953 ret = xmlXPathCastToString(obj); /* this does required strdup */
2954 /* TODO: needs refactoring somewhere else */
2955 if (obj->stringval == ret)
2956 obj->stringval = NULL;
2957 xmlXPathReleaseObject(ctxt->context, obj);
2958 return(ret);
2959}
2960
2961/**
2962 * xmlXPathPopNodeSet:
2963 * @ctxt: an XPath parser context
2964 *
2965 * Pops a node-set from the stack, handling conversion if needed.
2966 * Check error with #xmlXPathCheckError.
2967 *
2968 * Returns the node-set
2969 */
2970xmlNodeSetPtr
2971xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2972 xmlXPathObjectPtr obj;
2973 xmlNodeSetPtr ret;
2974
2975 if (ctxt == NULL) return(NULL);
2976 if (ctxt->value == NULL) {
2977 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2978 return(NULL);
2979 }
2980 if (!xmlXPathStackIsNodeSet(ctxt)) {
2981 xmlXPathSetTypeError(ctxt);
2982 return(NULL);
2983 }
2984 obj = valuePop(ctxt);
2985 ret = obj->nodesetval;
2986#if 0
2987 /* to fix memory leak of not clearing obj->user */
2988 if (obj->boolval && obj->user != NULL)
2989 xmlFreeNodeList((xmlNodePtr) obj->user);
2990#endif
2991 obj->nodesetval = NULL;
2992 xmlXPathReleaseObject(ctxt->context, obj);
2993 return(ret);
2994}
2995
2996/**
2997 * xmlXPathPopExternal:
2998 * @ctxt: an XPath parser context
2999 *
3000 * Pops an external object from the stack, handling conversion if needed.
3001 * Check error with #xmlXPathCheckError.
3002 *
3003 * Returns the object
3004 */
3005void *
3006xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3007 xmlXPathObjectPtr obj;
3008 void * ret;
3009
3010 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3011 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3012 return(NULL);
3013 }
3014 if (ctxt->value->type != XPATH_USERS) {
3015 xmlXPathSetTypeError(ctxt);
3016 return(NULL);
3017 }
3018 obj = valuePop(ctxt);
3019 ret = obj->user;
3020 obj->user = NULL;
3021 xmlXPathReleaseObject(ctxt->context, obj);
3022 return(ret);
3023}
3024
3025/*
3026 * Macros for accessing the content. Those should be used only by the parser,
3027 * and not exported.
3028 *
3029 * Dirty macros, i.e. one need to make assumption on the context to use them
3030 *
3031 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3032 * CUR returns the current xmlChar value, i.e. a 8 bit value
3033 * in ISO-Latin or UTF-8.
3034 * This should be used internally by the parser
3035 * only to compare to ASCII values otherwise it would break when
3036 * running with UTF-8 encoding.
3037 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3038 * to compare on ASCII based substring.
3039 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3040 * strings within the parser.
3041 * CURRENT Returns the current char value, with the full decoding of
3042 * UTF-8 if we are using this mode. It returns an int.
3043 * NEXT Skip to the next character, this does the proper decoding
3044 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3045 * It returns the pointer to the current xmlChar.
3046 */
3047
3048#define CUR (*ctxt->cur)
3049#define SKIP(val) ctxt->cur += (val)
3050#define NXT(val) ctxt->cur[(val)]
3051#define CUR_PTR ctxt->cur
3052#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3053
3054#define COPY_BUF(l,b,i,v) \
3055 if (l == 1) b[i++] = (xmlChar) v; \
3056 else i += xmlCopyChar(l,&b[i],v)
3057
3058#define NEXTL(l) ctxt->cur += l
3059
3060#define SKIP_BLANKS \
3061 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3062
3063#define CURRENT (*ctxt->cur)
3064#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3065
3066
3067#ifndef DBL_DIG
3068#define DBL_DIG 16
3069#endif
3070#ifndef DBL_EPSILON
3071#define DBL_EPSILON 1E-9
3072#endif
3073
3074#define UPPER_DOUBLE 1E9
3075#define LOWER_DOUBLE 1E-5
3076#define LOWER_DOUBLE_EXP 5
3077
3078#define INTEGER_DIGITS DBL_DIG
3079#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3080#define EXPONENT_DIGITS (3 + 2)
3081
3082/**
3083 * xmlXPathFormatNumber:
3084 * @number: number to format
3085 * @buffer: output buffer
3086 * @buffersize: size of output buffer
3087 *
3088 * Convert the number into a string representation.
3089 */
3090static void
3091xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3092{
3093 switch (xmlXPathIsInf(number)) {
3094 case 1:
3095 if (buffersize > (int)sizeof("Infinity"))
3096 snprintf(buffer, buffersize, "Infinity");
3097 break;
3098 case -1:
3099 if (buffersize > (int)sizeof("-Infinity"))
3100 snprintf(buffer, buffersize, "-Infinity");
3101 break;
3102 default:
3103 if (xmlXPathIsNaN(number)) {
3104 if (buffersize > (int)sizeof("NaN"))
3105 snprintf(buffer, buffersize, "NaN");
3106 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
3107 snprintf(buffer, buffersize, "0");
3108 } else if (number == ((int) number)) {
3109 char work[30];
3110 char *ptr, *cur;
3111 int value = (int) number;
3112
3113 ptr = &buffer[0];
3114 if (value == 0) {
3115 *ptr++ = '0';
3116 } else {
3117 snprintf(work, 29, "%d", value);
3118 cur = &work[0];
3119 while ((*cur) && (ptr - buffer < buffersize)) {
3120 *ptr++ = *cur++;
3121 }
3122 }
3123 if (ptr - buffer < buffersize) {
3124 *ptr = 0;
3125 } else if (buffersize > 0) {
3126 ptr--;
3127 *ptr = 0;
3128 }
3129 } else {
3130 /*
3131 For the dimension of work,
3132 DBL_DIG is number of significant digits
3133 EXPONENT is only needed for "scientific notation"
3134 3 is sign, decimal point, and terminating zero
3135 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3136 Note that this dimension is slightly (a few characters)
3137 larger than actually necessary.
3138 */
3139 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3140 int integer_place, fraction_place;
3141 char *ptr;
3142 char *after_fraction;
3143 double absolute_value;
3144 int size;
3145
3146 absolute_value = fabs(number);
3147
3148 /*
3149 * First choose format - scientific or regular floating point.
3150 * In either case, result is in work, and after_fraction points
3151 * just past the fractional part.
3152 */
3153 if ( ((absolute_value > UPPER_DOUBLE) ||
3154 (absolute_value < LOWER_DOUBLE)) &&
3155 (absolute_value != 0.0) ) {
3156 /* Use scientific notation */
3157 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3158 fraction_place = DBL_DIG - 1;
3159 size = snprintf(work, sizeof(work),"%*.*e",
3160 integer_place, fraction_place, number);
3161 while ((size > 0) && (work[size] != 'e')) size--;
3162
3163 }
3164 else {
3165 /* Use regular notation */
3166 if (absolute_value > 0.0) {
3167 integer_place = (int)log10(absolute_value);
3168 if (integer_place > 0)
3169 fraction_place = DBL_DIG - integer_place - 1;
3170 else
3171 fraction_place = DBL_DIG - integer_place;
3172 } else {
3173 fraction_place = 1;
3174 }
3175 size = snprintf(work, sizeof(work), "%0.*f",
3176 fraction_place, number);
3177 }
3178
3179 /* Remove leading spaces sometimes inserted by snprintf */
3180 while (work[0] == ' ') {
3181 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3182 size--;
3183 }
3184
3185 /* Remove fractional trailing zeroes */
3186 after_fraction = work + size;
3187 ptr = after_fraction;
3188 while (*(--ptr) == '0')
3189 ;
3190 if (*ptr != '.')
3191 ptr++;
3192 while ((*ptr++ = *after_fraction++) != 0);
3193
3194 /* Finally copy result back to caller */
3195 size = strlen(work) + 1;
3196 if (size > buffersize) {
3197 work[buffersize - 1] = 0;
3198 size = buffersize;
3199 }
3200 memmove(buffer, work, size);
3201 }
3202 break;
3203 }
3204}
3205
3206
3207/************************************************************************
3208 * *
3209 * Routines to handle NodeSets *
3210 * *
3211 ************************************************************************/
3212
3213/**
3214 * xmlXPathOrderDocElems:
3215 * @doc: an input document
3216 *
3217 * Call this routine to speed up XPath computation on static documents.
3218 * This stamps all the element nodes with the document order
3219 * Like for line information, the order is kept in the element->content
3220 * field, the value stored is actually - the node number (starting at -1)
3221 * to be able to differentiate from line numbers.
3222 *
3223 * Returns the number of elements found in the document or -1 in case
3224 * of error.
3225 */
3226long
3227xmlXPathOrderDocElems(xmlDocPtr doc) {
3228 long count = 0;
3229 xmlNodePtr cur;
3230
3231 if (doc == NULL)
3232 return(-1);
3233 cur = doc->children;
3234 while (cur != NULL) {
3235 if (cur->type == XML_ELEMENT_NODE) {
3236 cur->content = (void *) (-(++count));
3237 if (cur->children != NULL) {
3238 cur = cur->children;
3239 continue;
3240 }
3241 }
3242 if (cur->next != NULL) {
3243 cur = cur->next;
3244 continue;
3245 }
3246 do {
3247 cur = cur->parent;
3248 if (cur == NULL)
3249 break;
3250 if (cur == (xmlNodePtr) doc) {
3251 cur = NULL;
3252 break;
3253 }
3254 if (cur->next != NULL) {
3255 cur = cur->next;
3256 break;
3257 }
3258 } while (cur != NULL);
3259 }
3260 return(count);
3261}
3262
3263/**
3264 * xmlXPathCmpNodes:
3265 * @node1: the first node
3266 * @node2: the second node
3267 *
3268 * Compare two nodes w.r.t document order
3269 *
3270 * Returns -2 in case of error 1 if first point < second point, 0 if
3271 * it's the same node, -1 otherwise
3272 */
3273int
3274xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3275 int depth1, depth2;
3276 int attr1 = 0, attr2 = 0;
3277 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3278 xmlNodePtr cur, root;
3279
3280 if ((node1 == NULL) || (node2 == NULL))
3281 return(-2);
3282 /*
3283 * a couple of optimizations which will avoid computations in most cases
3284 */
3285 if (node1 == node2) /* trivial case */
3286 return(0);
3287 if (node1->type == XML_ATTRIBUTE_NODE) {
3288 attr1 = 1;
3289 attrNode1 = node1;
3290 node1 = node1->parent;
3291 }
3292 if (node2->type == XML_ATTRIBUTE_NODE) {
3293 attr2 = 1;
3294 attrNode2 = node2;
3295 node2 = node2->parent;
3296 }
3297 if (node1 == node2) {
3298 if (attr1 == attr2) {
3299 /* not required, but we keep attributes in order */
3300 if (attr1 != 0) {
3301 cur = attrNode2->prev;
3302 while (cur != NULL) {
3303 if (cur == attrNode1)
3304 return (1);
3305 cur = cur->prev;
3306 }
3307 return (-1);
3308 }
3309 return(0);
3310 }
3311 if (attr2 == 1)
3312 return(1);
3313 return(-1);
3314 }
3315 if ((node1->type == XML_NAMESPACE_DECL) ||
3316 (node2->type == XML_NAMESPACE_DECL))
3317 return(1);
3318 if (node1 == node2->prev)
3319 return(1);
3320 if (node1 == node2->next)
3321 return(-1);
3322
3323 /*
3324 * Speedup using document order if availble.
3325 */
3326 if ((node1->type == XML_ELEMENT_NODE) &&
3327 (node2->type == XML_ELEMENT_NODE) &&
3328 (0 > (long) node1->content) &&
3329 (0 > (long) node2->content) &&
3330 (node1->doc == node2->doc)) {
3331 long l1, l2;
3332
3333 l1 = -((long) node1->content);
3334 l2 = -((long) node2->content);
3335 if (l1 < l2)
3336 return(1);
3337 if (l1 > l2)
3338 return(-1);
3339 }
3340
3341 /*
3342 * compute depth to root
3343 */
3344 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3345 if (cur == node1)
3346 return(1);
3347 depth2++;
3348 }
3349 root = cur;
3350 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3351 if (cur == node2)
3352 return(-1);
3353 depth1++;
3354 }
3355 /*
3356 * Distinct document (or distinct entities :-( ) case.
3357 */
3358 if (root != cur) {
3359 return(-2);
3360 }
3361 /*
3362 * get the nearest common ancestor.
3363 */
3364 while (depth1 > depth2) {
3365 depth1--;
3366 node1 = node1->parent;
3367 }
3368 while (depth2 > depth1) {
3369 depth2--;
3370 node2 = node2->parent;
3371 }
3372 while (node1->parent != node2->parent) {
3373 node1 = node1->parent;
3374 node2 = node2->parent;
3375 /* should not happen but just in case ... */
3376 if ((node1 == NULL) || (node2 == NULL))
3377 return(-2);
3378 }
3379 /*
3380 * Find who's first.
3381 */
3382 if (node1 == node2->prev)
3383 return(1);
3384 if (node1 == node2->next)
3385 return(-1);
3386 /*
3387 * Speedup using document order if availble.
3388 */
3389 if ((node1->type == XML_ELEMENT_NODE) &&
3390 (node2->type == XML_ELEMENT_NODE) &&
3391 (0 > (long) node1->content) &&
3392 (0 > (long) node2->content) &&
3393 (node1->doc == node2->doc)) {
3394 long l1, l2;
3395
3396 l1 = -((long) node1->content);
3397 l2 = -((long) node2->content);
3398 if (l1 < l2)
3399 return(1);
3400 if (l1 > l2)
3401 return(-1);
3402 }
3403
3404 for (cur = node1->next;cur != NULL;cur = cur->next)
3405 if (cur == node2)
3406 return(1);
3407 return(-1); /* assume there is no sibling list corruption */
3408}
3409
3410/**
3411 * xmlXPathNodeSetSort:
3412 * @set: the node set
3413 *
3414 * Sort the node set in document order
3415 */
3416void
3417xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3418#ifndef WITH_TIM_SORT
3419 int i, j, incr, len;
3420 xmlNodePtr tmp;
3421#endif
3422
3423 if (set == NULL)
3424 return;
3425
3426#ifndef WITH_TIM_SORT
3427 /*
3428 * Use the old Shell's sort implementation to sort the node-set
3429 * Timsort ought to be quite faster
3430 */
3431 len = set->nodeNr;
3432 for (incr = len / 2; incr > 0; incr /= 2) {
3433 for (i = incr; i < len; i++) {
3434 j = i - incr;
3435 while (j >= 0) {
3436#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3437 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3438 set->nodeTab[j + incr]) == -1)
3439#else
3440 if (xmlXPathCmpNodes(set->nodeTab[j],
3441 set->nodeTab[j + incr]) == -1)
3442#endif
3443 {
3444 tmp = set->nodeTab[j];
3445 set->nodeTab[j] = set->nodeTab[j + incr];
3446 set->nodeTab[j + incr] = tmp;
3447 j -= incr;
3448 } else
3449 break;
3450 }
3451 }
3452 }
3453#else /* WITH_TIM_SORT */
3454 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3455#endif /* WITH_TIM_SORT */
3456}
3457
3458#define XML_NODESET_DEFAULT 10
3459/**
3460 * xmlXPathNodeSetDupNs:
3461 * @node: the parent node of the namespace XPath node
3462 * @ns: the libxml namespace declaration node.
3463 *
3464 * Namespace node in libxml don't match the XPath semantic. In a node set
3465 * the namespace nodes are duplicated and the next pointer is set to the
3466 * parent node in the XPath semantic.
3467 *
3468 * Returns the newly created object.
3469 */
3470static xmlNodePtr
3471xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3472 xmlNsPtr cur;
3473
3474 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3475 return(NULL);
3476 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3477 return((xmlNodePtr) ns);
3478
3479 /*
3480 * Allocate a new Namespace and fill the fields.
3481 */
3482 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3483 if (cur == NULL) {
3484 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3485 return(NULL);
3486 }
3487 memset(cur, 0, sizeof(xmlNs));
3488 cur->type = XML_NAMESPACE_DECL;
3489 if (ns->href != NULL)
3490 cur->href = xmlStrdup(ns->href);
3491 if (ns->prefix != NULL)
3492 cur->prefix = xmlStrdup(ns->prefix);
3493 cur->next = (xmlNsPtr) node;
3494 return((xmlNodePtr) cur);
3495}
3496
3497/**
3498 * xmlXPathNodeSetFreeNs:
3499 * @ns: the XPath namespace node found in a nodeset.
3500 *
3501 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3502 * the namespace nodes are duplicated and the next pointer is set to the
3503 * parent node in the XPath semantic. Check if such a node needs to be freed
3504 */
3505void
3506xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3507 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3508 return;
3509
3510 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3511 if (ns->href != NULL)
3512 xmlFree((xmlChar *)ns->href);
3513 if (ns->prefix != NULL)
3514 xmlFree((xmlChar *)ns->prefix);
3515 xmlFree(ns);
3516 }
3517}
3518
3519/**
3520 * xmlXPathNodeSetCreate:
3521 * @val: an initial xmlNodePtr, or NULL
3522 *
3523 * Create a new xmlNodeSetPtr of type double and of value @val
3524 *
3525 * Returns the newly created object.
3526 */
3527xmlNodeSetPtr
3528xmlXPathNodeSetCreate(xmlNodePtr val) {
3529 xmlNodeSetPtr ret;
3530
3531 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3532 if (ret == NULL) {
3533 xmlXPathErrMemory(NULL, "creating nodeset\n");
3534 return(NULL);
3535 }
3536 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3537 if (val != NULL) {
3538 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3539 sizeof(xmlNodePtr));
3540 if (ret->nodeTab == NULL) {
3541 xmlXPathErrMemory(NULL, "creating nodeset\n");
3542 xmlFree(ret);
3543 return(NULL);
3544 }
3545 memset(ret->nodeTab, 0 ,
3546 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3547 ret->nodeMax = XML_NODESET_DEFAULT;
3548 if (val->type == XML_NAMESPACE_DECL) {
3549 xmlNsPtr ns = (xmlNsPtr) val;
3550
3551 ret->nodeTab[ret->nodeNr++] =
3552 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3553 } else
3554 ret->nodeTab[ret->nodeNr++] = val;
3555 }
3556 return(ret);
3557}
3558
3559/**
3560 * xmlXPathNodeSetCreateSize:
3561 * @size: the initial size of the set
3562 *
3563 * Create a new xmlNodeSetPtr of type double and of value @val
3564 *
3565 * Returns the newly created object.
3566 */
3567static xmlNodeSetPtr
3568xmlXPathNodeSetCreateSize(int size) {
3569 xmlNodeSetPtr ret;
3570
3571 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3572 if (ret == NULL) {
3573 xmlXPathErrMemory(NULL, "creating nodeset\n");
3574 return(NULL);
3575 }
3576 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3577 if (size < XML_NODESET_DEFAULT)
3578 size = XML_NODESET_DEFAULT;
3579 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3580 if (ret->nodeTab == NULL) {
3581 xmlXPathErrMemory(NULL, "creating nodeset\n");
3582 xmlFree(ret);
3583 return(NULL);
3584 }
3585 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3586 ret->nodeMax = size;
3587 return(ret);
3588}
3589
3590/**
3591 * xmlXPathNodeSetContains:
3592 * @cur: the node-set
3593 * @val: the node
3594 *
3595 * checks whether @cur contains @val
3596 *
3597 * Returns true (1) if @cur contains @val, false (0) otherwise
3598 */
3599int
3600xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3601 int i;
3602
3603 if ((cur == NULL) || (val == NULL)) return(0);
3604 if (val->type == XML_NAMESPACE_DECL) {
3605 for (i = 0; i < cur->nodeNr; i++) {
3606 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3607 xmlNsPtr ns1, ns2;
3608
3609 ns1 = (xmlNsPtr) val;
3610 ns2 = (xmlNsPtr) cur->nodeTab[i];
3611 if (ns1 == ns2)
3612 return(1);
3613 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3614 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3615 return(1);
3616 }
3617 }
3618 } else {
3619 for (i = 0; i < cur->nodeNr; i++) {
3620 if (cur->nodeTab[i] == val)
3621 return(1);
3622 }
3623 }
3624 return(0);
3625}
3626
3627/**
3628 * xmlXPathNodeSetAddNs:
3629 * @cur: the initial node set
3630 * @node: the hosting node
3631 * @ns: a the namespace node
3632 *
3633 * add a new namespace node to an existing NodeSet
3634 *
3635 * Returns 0 in case of success and -1 in case of error
3636 */
3637int
3638xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3639 int i;
3640
3641
3642 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3643 (ns->type != XML_NAMESPACE_DECL) ||
3644 (node->type != XML_ELEMENT_NODE))
3645 return(-1);
3646
3647 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3648 /*
3649 * prevent duplicates
3650 */
3651 for (i = 0;i < cur->nodeNr;i++) {
3652 if ((cur->nodeTab[i] != NULL) &&
3653 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3654 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3655 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3656 return(0);
3657 }
3658
3659 /*
3660 * grow the nodeTab if needed
3661 */
3662 if (cur->nodeMax == 0) {
3663 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3664 sizeof(xmlNodePtr));
3665 if (cur->nodeTab == NULL) {
3666 xmlXPathErrMemory(NULL, "growing nodeset\n");
3667 return(-1);
3668 }
3669 memset(cur->nodeTab, 0 ,
3670 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3671 cur->nodeMax = XML_NODESET_DEFAULT;
3672 } else if (cur->nodeNr == cur->nodeMax) {
3673 xmlNodePtr *temp;
3674
3675 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3676 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3677 return(-1);
3678 }
3679 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3680 sizeof(xmlNodePtr));
3681 if (temp == NULL) {
3682 xmlXPathErrMemory(NULL, "growing nodeset\n");
3683 return(-1);
3684 }
3685 cur->nodeMax *= 2;
3686 cur->nodeTab = temp;
3687 }
3688 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3689 return(0);
3690}
3691
3692/**
3693 * xmlXPathNodeSetAdd:
3694 * @cur: the initial node set
3695 * @val: a new xmlNodePtr
3696 *
3697 * add a new xmlNodePtr to an existing NodeSet
3698 *
3699 * Returns 0 in case of success, and -1 in case of error
3700 */
3701int
3702xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3703 int i;
3704
3705 if ((cur == NULL) || (val == NULL)) return(-1);
3706
3707 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3708 /*
3709 * prevent duplcates
3710 */
3711 for (i = 0;i < cur->nodeNr;i++)
3712 if (cur->nodeTab[i] == val) return(0);
3713
3714 /*
3715 * grow the nodeTab if needed
3716 */
3717 if (cur->nodeMax == 0) {
3718 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3719 sizeof(xmlNodePtr));
3720 if (cur->nodeTab == NULL) {
3721 xmlXPathErrMemory(NULL, "growing nodeset\n");
3722 return(-1);
3723 }
3724 memset(cur->nodeTab, 0 ,
3725 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3726 cur->nodeMax = XML_NODESET_DEFAULT;
3727 } else if (cur->nodeNr == cur->nodeMax) {
3728 xmlNodePtr *temp;
3729
3730 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3731 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3732 return(-1);
3733 }
3734 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3735 sizeof(xmlNodePtr));
3736 if (temp == NULL) {
3737 xmlXPathErrMemory(NULL, "growing nodeset\n");
3738 return(-1);
3739 }
3740 cur->nodeMax *= 2;
3741 cur->nodeTab = temp;
3742 }
3743 if (val->type == XML_NAMESPACE_DECL) {
3744 xmlNsPtr ns = (xmlNsPtr) val;
3745
3746 cur->nodeTab[cur->nodeNr++] =
3747 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3748 } else
3749 cur->nodeTab[cur->nodeNr++] = val;
3750 return(0);
3751}
3752
3753/**
3754 * xmlXPathNodeSetAddUnique:
3755 * @cur: the initial node set
3756 * @val: a new xmlNodePtr
3757 *
3758 * add a new xmlNodePtr to an existing NodeSet, optimized version
3759 * when we are sure the node is not already in the set.
3760 *
3761 * Returns 0 in case of success and -1 in case of failure
3762 */
3763int
3764xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3765 if ((cur == NULL) || (val == NULL)) return(-1);
3766
3767 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3768 /*
3769 * grow the nodeTab if needed
3770 */
3771 if (cur->nodeMax == 0) {
3772 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3773 sizeof(xmlNodePtr));
3774 if (cur->nodeTab == NULL) {
3775 xmlXPathErrMemory(NULL, "growing nodeset\n");
3776 return(-1);
3777 }
3778 memset(cur->nodeTab, 0 ,
3779 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3780 cur->nodeMax = XML_NODESET_DEFAULT;
3781 } else if (cur->nodeNr == cur->nodeMax) {
3782 xmlNodePtr *temp;
3783
3784 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3785 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3786 return(-1);
3787 }
3788 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3789 sizeof(xmlNodePtr));
3790 if (temp == NULL) {
3791 xmlXPathErrMemory(NULL, "growing nodeset\n");
3792 return(-1);
3793 }
3794 cur->nodeTab = temp;
3795 cur->nodeMax *= 2;
3796 }
3797 if (val->type == XML_NAMESPACE_DECL) {
3798 xmlNsPtr ns = (xmlNsPtr) val;
3799
3800 cur->nodeTab[cur->nodeNr++] =
3801 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3802 } else
3803 cur->nodeTab[cur->nodeNr++] = val;
3804 return(0);
3805}
3806
3807/**
3808 * xmlXPathNodeSetMerge:
3809 * @val1: the first NodeSet or NULL
3810 * @val2: the second NodeSet
3811 *
3812 * Merges two nodesets, all nodes from @val2 are added to @val1
3813 * if @val1 is NULL, a new set is created and copied from @val2
3814 *
3815 * Returns @val1 once extended or NULL in case of error.
3816 */
3817xmlNodeSetPtr
3818xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3819 int i, j, initNr, skip;
3820 xmlNodePtr n1, n2;
3821
3822 if (val2 == NULL) return(val1);
3823 if (val1 == NULL) {
3824 val1 = xmlXPathNodeSetCreate(NULL);
3825 if (val1 == NULL)
3826 return (NULL);
3827#if 0
3828 /*
3829 * TODO: The optimization won't work in every case, since
3830 * those nasty namespace nodes need to be added with
3831 * xmlXPathNodeSetDupNs() to the set; thus a pure
3832 * memcpy is not possible.
3833 * If there was a flag on the nodesetval, indicating that
3834 * some temporary nodes are in, that would be helpfull.
3835 */
3836 /*
3837 * Optimization: Create an equally sized node-set
3838 * and memcpy the content.
3839 */
3840 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3841 if (val1 == NULL)
3842 return(NULL);
3843 if (val2->nodeNr != 0) {
3844 if (val2->nodeNr == 1)
3845 *(val1->nodeTab) = *(val2->nodeTab);
3846 else {
3847 memcpy(val1->nodeTab, val2->nodeTab,
3848 val2->nodeNr * sizeof(xmlNodePtr));
3849 }
3850 val1->nodeNr = val2->nodeNr;
3851 }
3852 return(val1);
3853#endif
3854 }
3855
3856 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3857 initNr = val1->nodeNr;
3858
3859 for (i = 0;i < val2->nodeNr;i++) {
3860 n2 = val2->nodeTab[i];
3861 /*
3862 * check against duplicates
3863 */
3864 skip = 0;
3865 for (j = 0; j < initNr; j++) {
3866 n1 = val1->nodeTab[j];
3867 if (n1 == n2) {
3868 skip = 1;
3869 break;
3870 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3871 (n2->type == XML_NAMESPACE_DECL)) {
3872 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3873 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3874 ((xmlNsPtr) n2)->prefix)))
3875 {
3876 skip = 1;
3877 break;
3878 }
3879 }
3880 }
3881 if (skip)
3882 continue;
3883
3884 /*
3885 * grow the nodeTab if needed
3886 */
3887 if (val1->nodeMax == 0) {
3888 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3889 sizeof(xmlNodePtr));
3890 if (val1->nodeTab == NULL) {
3891 xmlXPathErrMemory(NULL, "merging nodeset\n");
3892 return(NULL);
3893 }
3894 memset(val1->nodeTab, 0 ,
3895 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3896 val1->nodeMax = XML_NODESET_DEFAULT;
3897 } else if (val1->nodeNr == val1->nodeMax) {
3898 xmlNodePtr *temp;
3899
3900 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3901 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3902 return(NULL);
3903 }
3904 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3905 sizeof(xmlNodePtr));
3906 if (temp == NULL) {
3907 xmlXPathErrMemory(NULL, "merging nodeset\n");
3908 return(NULL);
3909 }
3910 val1->nodeTab = temp;
3911 val1->nodeMax *= 2;
3912 }
3913 if (n2->type == XML_NAMESPACE_DECL) {
3914 xmlNsPtr ns = (xmlNsPtr) n2;
3915
3916 val1->nodeTab[val1->nodeNr++] =
3917 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3918 } else
3919 val1->nodeTab[val1->nodeNr++] = n2;
3920 }
3921
3922 return(val1);
3923}
3924
3925
3926/**
3927 * xmlXPathNodeSetMergeAndClear:
3928 * @set1: the first NodeSet or NULL
3929 * @set2: the second NodeSet
3930 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3931 *
3932 * Merges two nodesets, all nodes from @set2 are added to @set1
3933 * if @set1 is NULL, a new set is created and copied from @set2.
3934 * Checks for duplicate nodes. Clears set2.
3935 *
3936 * Returns @set1 once extended or NULL in case of error.
3937 */
3938static xmlNodeSetPtr
3939xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3940 int hasNullEntries)
3941{
3942 if ((set1 == NULL) && (hasNullEntries == 0)) {
3943 /*
3944 * Note that doing a memcpy of the list, namespace nodes are
3945 * just assigned to set1, since set2 is cleared anyway.
3946 */
3947 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3948 if (set1 == NULL)
3949 return(NULL);
3950 if (set2->nodeNr != 0) {
3951 memcpy(set1->nodeTab, set2->nodeTab,
3952 set2->nodeNr * sizeof(xmlNodePtr));
3953 set1->nodeNr = set2->nodeNr;
3954 }
3955 } else {
3956 int i, j, initNbSet1;
3957 xmlNodePtr n1, n2;
3958
3959 if (set1 == NULL)
3960 set1 = xmlXPathNodeSetCreate(NULL);
3961 if (set1 == NULL)
3962 return (NULL);
3963
3964 initNbSet1 = set1->nodeNr;
3965 for (i = 0;i < set2->nodeNr;i++) {
3966 n2 = set2->nodeTab[i];
3967 /*
3968 * Skip NULLed entries.
3969 */
3970 if (n2 == NULL)
3971 continue;
3972 /*
3973 * Skip duplicates.
3974 */
3975 for (j = 0; j < initNbSet1; j++) {
3976 n1 = set1->nodeTab[j];
3977 if (n1 == n2) {
3978 goto skip_node;
3979 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3980 (n2->type == XML_NAMESPACE_DECL))
3981 {
3982 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3983 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3984 ((xmlNsPtr) n2)->prefix)))
3985 {
3986 /*
3987 * Free the namespace node.
3988 */
3989 set2->nodeTab[i] = NULL;
3990 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3991 goto skip_node;
3992 }
3993 }
3994 }
3995 /*
3996 * grow the nodeTab if needed
3997 */
3998 if (set1->nodeMax == 0) {
3999 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4000 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4001 if (set1->nodeTab == NULL) {
4002 xmlXPathErrMemory(NULL, "merging nodeset\n");
4003 return(NULL);
4004 }
4005 memset(set1->nodeTab, 0,
4006 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4007 set1->nodeMax = XML_NODESET_DEFAULT;
4008 } else if (set1->nodeNr >= set1->nodeMax) {
4009 xmlNodePtr *temp;
4010
4011 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4012 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4013 return(NULL);
4014 }
4015 temp = (xmlNodePtr *) xmlRealloc(
4016 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4017 if (temp == NULL) {
4018 xmlXPathErrMemory(NULL, "merging nodeset\n");
4019 return(NULL);
4020 }
4021 set1->nodeTab = temp;
4022 set1->nodeMax *= 2;
4023 }
4024 if (n2->type == XML_NAMESPACE_DECL) {
4025 xmlNsPtr ns = (xmlNsPtr) n2;
4026
4027 set1->nodeTab[set1->nodeNr++] =
4028 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4029 } else
4030 set1->nodeTab[set1->nodeNr++] = n2;
4031skip_node:
4032 {}
4033 }
4034 }
4035 set2->nodeNr = 0;
4036 return(set1);
4037}
4038
4039/**
4040 * xmlXPathNodeSetMergeAndClearNoDupls:
4041 * @set1: the first NodeSet or NULL
4042 * @set2: the second NodeSet
4043 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4044 *
4045 * Merges two nodesets, all nodes from @set2 are added to @set1
4046 * if @set1 is NULL, a new set is created and copied from @set2.
4047 * Doesn't chack for duplicate nodes. Clears set2.
4048 *
4049 * Returns @set1 once extended or NULL in case of error.
4050 */
4051static xmlNodeSetPtr
4052xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4053 int hasNullEntries)
4054{
4055 if (set2 == NULL)
4056 return(set1);
4057 if ((set1 == NULL) && (hasNullEntries == 0)) {
4058 /*
4059 * Note that doing a memcpy of the list, namespace nodes are
4060 * just assigned to set1, since set2 is cleared anyway.
4061 */
4062 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4063 if (set1 == NULL)
4064 return(NULL);
4065 if (set2->nodeNr != 0) {
4066 memcpy(set1->nodeTab, set2->nodeTab,
4067 set2->nodeNr * sizeof(xmlNodePtr));
4068 set1->nodeNr = set2->nodeNr;
4069 }
4070 } else {
4071 int i;
4072 xmlNodePtr n2;
4073
4074 if (set1 == NULL)
4075 set1 = xmlXPathNodeSetCreate(NULL);
4076 if (set1 == NULL)
4077 return (NULL);
4078
4079 for (i = 0;i < set2->nodeNr;i++) {
4080 n2 = set2->nodeTab[i];
4081 /*
4082 * Skip NULLed entries.
4083 */
4084 if (n2 == NULL)
4085 continue;
4086 if (set1->nodeMax == 0) {
4087 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4088 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4089 if (set1->nodeTab == NULL) {
4090 xmlXPathErrMemory(NULL, "merging nodeset\n");
4091 return(NULL);
4092 }
4093 memset(set1->nodeTab, 0,
4094 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4095 set1->nodeMax = XML_NODESET_DEFAULT;
4096 } else if (set1->nodeNr >= set1->nodeMax) {
4097 xmlNodePtr *temp;
4098
4099 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4100 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4101 return(NULL);
4102 }
4103 temp = (xmlNodePtr *) xmlRealloc(
4104 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4105 if (temp == NULL) {
4106 xmlXPathErrMemory(NULL, "merging nodeset\n");
4107 return(NULL);
4108 }
4109 set1->nodeTab = temp;
4110 set1->nodeMax *= 2;
4111 }
4112 set1->nodeTab[set1->nodeNr++] = n2;
4113 }
4114 }
4115 set2->nodeNr = 0;
4116 return(set1);
4117}
4118
4119/**
4120 * xmlXPathNodeSetDel:
4121 * @cur: the initial node set
4122 * @val: an xmlNodePtr
4123 *
4124 * Removes an xmlNodePtr from an existing NodeSet
4125 */
4126void
4127xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4128 int i;
4129
4130 if (cur == NULL) return;
4131 if (val == NULL) return;
4132
4133 /*
4134 * find node in nodeTab
4135 */
4136 for (i = 0;i < cur->nodeNr;i++)
4137 if (cur->nodeTab[i] == val) break;
4138
4139 if (i >= cur->nodeNr) { /* not found */
4140#ifdef DEBUG
4141 xmlGenericError(xmlGenericErrorContext,
4142 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4143 val->name);
4144#endif
4145 return;
4146 }
4147 if ((cur->nodeTab[i] != NULL) &&
4148 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4149 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4150 cur->nodeNr--;
4151 for (;i < cur->nodeNr;i++)
4152 cur->nodeTab[i] = cur->nodeTab[i + 1];
4153 cur->nodeTab[cur->nodeNr] = NULL;
4154}
4155
4156/**
4157 * xmlXPathNodeSetRemove:
4158 * @cur: the initial node set
4159 * @val: the index to remove
4160 *
4161 * Removes an entry from an existing NodeSet list.
4162 */
4163void
4164xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4165 if (cur == NULL) return;
4166 if (val >= cur->nodeNr) return;
4167 if ((cur->nodeTab[val] != NULL) &&
4168 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4169 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4170 cur->nodeNr--;
4171 for (;val < cur->nodeNr;val++)
4172 cur->nodeTab[val] = cur->nodeTab[val + 1];
4173 cur->nodeTab[cur->nodeNr] = NULL;
4174}
4175
4176/**
4177 * xmlXPathFreeNodeSet:
4178 * @obj: the xmlNodeSetPtr to free
4179 *
4180 * Free the NodeSet compound (not the actual nodes !).
4181 */
4182void
4183xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4184 if (obj == NULL) return;
4185 if (obj->nodeTab != NULL) {
4186 int i;
4187
4188 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4189 for (i = 0;i < obj->nodeNr;i++)
4190 if ((obj->nodeTab[i] != NULL) &&
4191 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4192 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4193 xmlFree(obj->nodeTab);
4194 }
4195 xmlFree(obj);
4196}
4197
4198/**
4199 * xmlXPathNodeSetClear:
4200 * @set: the node set to clear
4201 *
4202 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4203 * are feed), but does *not* free the list itself. Sets the length of the
4204 * list to 0.
4205 */
4206static void
4207xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4208{
4209 if ((set == NULL) || (set->nodeNr <= 0))
4210 return;
4211 else if (hasNsNodes) {
4212 int i;
4213 xmlNodePtr node;
4214
4215 for (i = 0; i < set->nodeNr; i++) {
4216 node = set->nodeTab[i];
4217 if ((node != NULL) &&
4218 (node->type == XML_NAMESPACE_DECL))
4219 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4220 }
4221 }
4222 set->nodeNr = 0;
4223}
4224
4225/**
4226 * xmlXPathNodeSetClearFromPos:
4227 * @set: the node set to be cleared
4228 * @pos: the start position to clear from
4229 *
4230 * Clears the list from temporary XPath objects (e.g. namespace nodes
4231 * are feed) starting with the entry at @pos, but does *not* free the list
4232 * itself. Sets the length of the list to @pos.
4233 */
4234static void
4235xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4236{
4237 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4238 return;
4239 else if ((hasNsNodes)) {
4240 int i;
4241 xmlNodePtr node;
4242
4243 for (i = pos; i < set->nodeNr; i++) {
4244 node = set->nodeTab[i];
4245 if ((node != NULL) &&
4246 (node->type == XML_NAMESPACE_DECL))
4247 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4248 }
4249 }
4250 set->nodeNr = pos;
4251}
4252
4253/**
4254 * xmlXPathFreeValueTree:
4255 * @obj: the xmlNodeSetPtr to free
4256 *
4257 * Free the NodeSet compound and the actual tree, this is different
4258 * from xmlXPathFreeNodeSet()
4259 */
4260static void
4261xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4262 int i;
4263
4264 if (obj == NULL) return;
4265
4266 if (obj->nodeTab != NULL) {
4267 for (i = 0;i < obj->nodeNr;i++) {
4268 if (obj->nodeTab[i] != NULL) {
4269 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4270 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4271 } else {
4272 xmlFreeNodeList(obj->nodeTab[i]);
4273 }
4274 }
4275 }
4276 xmlFree(obj->nodeTab);
4277 }
4278 xmlFree(obj);
4279}
4280
4281#if defined(DEBUG) || defined(DEBUG_STEP)
4282/**
4283 * xmlGenericErrorContextNodeSet:
4284 * @output: a FILE * for the output
4285 * @obj: the xmlNodeSetPtr to display
4286 *
4287 * Quick display of a NodeSet
4288 */
4289void
4290xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4291 int i;
4292
4293 if (output == NULL) output = xmlGenericErrorContext;
4294 if (obj == NULL) {
4295 fprintf(output, "NodeSet == NULL !\n");
4296 return;
4297 }
4298 if (obj->nodeNr == 0) {
4299 fprintf(output, "NodeSet is empty\n");
4300 return;
4301 }
4302 if (obj->nodeTab == NULL) {
4303 fprintf(output, " nodeTab == NULL !\n");
4304 return;
4305 }
4306 for (i = 0; i < obj->nodeNr; i++) {
4307 if (obj->nodeTab[i] == NULL) {
4308 fprintf(output, " NULL !\n");
4309 return;
4310 }
4311 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4312 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4313 fprintf(output, " /");
4314 else if (obj->nodeTab[i]->name == NULL)
4315 fprintf(output, " noname!");
4316 else fprintf(output, " %s", obj->nodeTab[i]->name);
4317 }
4318 fprintf(output, "\n");
4319}
4320#endif
4321
4322/**
4323 * xmlXPathNewNodeSet:
4324 * @val: the NodePtr value
4325 *
4326 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4327 * it with the single Node @val
4328 *
4329 * Returns the newly created object.
4330 */
4331xmlXPathObjectPtr
4332xmlXPathNewNodeSet(xmlNodePtr val) {
4333 xmlXPathObjectPtr ret;
4334
4335 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4336 if (ret == NULL) {
4337 xmlXPathErrMemory(NULL, "creating nodeset\n");
4338 return(NULL);
4339 }
4340 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4341 ret->type = XPATH_NODESET;
4342 ret->boolval = 0;
4343 ret->nodesetval = xmlXPathNodeSetCreate(val);
4344 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4345#ifdef XP_DEBUG_OBJ_USAGE
4346 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4347#endif
4348 return(ret);
4349}
4350
4351/**
4352 * xmlXPathNewValueTree:
4353 * @val: the NodePtr value
4354 *
4355 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4356 * it with the tree root @val
4357 *
4358 * Returns the newly created object.
4359 */
4360xmlXPathObjectPtr
4361xmlXPathNewValueTree(xmlNodePtr val) {
4362 xmlXPathObjectPtr ret;
4363
4364 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4365 if (ret == NULL) {
4366 xmlXPathErrMemory(NULL, "creating result value tree\n");
4367 return(NULL);
4368 }
4369 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4370 ret->type = XPATH_XSLT_TREE;
4371 ret->boolval = 1;
4372 ret->user = (void *) val;
4373 ret->nodesetval = xmlXPathNodeSetCreate(val);
4374#ifdef XP_DEBUG_OBJ_USAGE
4375 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4376#endif
4377 return(ret);
4378}
4379
4380/**
4381 * xmlXPathNewNodeSetList:
4382 * @val: an existing NodeSet
4383 *
4384 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4385 * it with the Nodeset @val
4386 *
4387 * Returns the newly created object.
4388 */
4389xmlXPathObjectPtr
4390xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4391{
4392 xmlXPathObjectPtr ret;
4393 int i;
4394
4395 if (val == NULL)
4396 ret = NULL;
4397 else if (val->nodeTab == NULL)
4398 ret = xmlXPathNewNodeSet(NULL);
4399 else {
4400 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4401 if (ret) {
4402 for (i = 1; i < val->nodeNr; ++i) {
4403 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4404 < 0) break;
4405 }
4406 }
4407 }
4408
4409 return (ret);
4410}
4411
4412/**
4413 * xmlXPathWrapNodeSet:
4414 * @val: the NodePtr value
4415 *
4416 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4417 *
4418 * Returns the newly created object.
4419 */
4420xmlXPathObjectPtr
4421xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4422 xmlXPathObjectPtr ret;
4423
4424 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4425 if (ret == NULL) {
4426 xmlXPathErrMemory(NULL, "creating node set object\n");
4427 return(NULL);
4428 }
4429 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4430 ret->type = XPATH_NODESET;
4431 ret->nodesetval = val;
4432#ifdef XP_DEBUG_OBJ_USAGE
4433 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4434#endif
4435 return(ret);
4436}
4437
4438/**
4439 * xmlXPathFreeNodeSetList:
4440 * @obj: an existing NodeSetList object
4441 *
4442 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4443 * the list contrary to xmlXPathFreeObject().
4444 */
4445void
4446xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4447 if (obj == NULL) return;
4448#ifdef XP_DEBUG_OBJ_USAGE
4449 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4450#endif
4451 xmlFree(obj);
4452}
4453
4454/**
4455 * xmlXPathDifference:
4456 * @nodes1: a node-set
4457 * @nodes2: a node-set
4458 *
4459 * Implements the EXSLT - Sets difference() function:
4460 * node-set set:difference (node-set, node-set)
4461 *
4462 * Returns the difference between the two node sets, or nodes1 if
4463 * nodes2 is empty
4464 */
4465xmlNodeSetPtr
4466xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4467 xmlNodeSetPtr ret;
4468 int i, l1;
4469 xmlNodePtr cur;
4470
4471 if (xmlXPathNodeSetIsEmpty(nodes2))
4472 return(nodes1);
4473
4474 ret = xmlXPathNodeSetCreate(NULL);
4475 if (xmlXPathNodeSetIsEmpty(nodes1))
4476 return(ret);
4477
4478 l1 = xmlXPathNodeSetGetLength(nodes1);
4479
4480 for (i = 0; i < l1; i++) {
4481 cur = xmlXPathNodeSetItem(nodes1, i);
4482 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4483 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4484 break;
4485 }
4486 }
4487 return(ret);
4488}
4489
4490/**
4491 * xmlXPathIntersection:
4492 * @nodes1: a node-set
4493 * @nodes2: a node-set
4494 *
4495 * Implements the EXSLT - Sets intersection() function:
4496 * node-set set:intersection (node-set, node-set)
4497 *
4498 * Returns a node set comprising the nodes that are within both the
4499 * node sets passed as arguments
4500 */
4501xmlNodeSetPtr
4502xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4503 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4504 int i, l1;
4505 xmlNodePtr cur;
4506
4507 if (ret == NULL)
4508 return(ret);
4509 if (xmlXPathNodeSetIsEmpty(nodes1))
4510 return(ret);
4511 if (xmlXPathNodeSetIsEmpty(nodes2))
4512 return(ret);
4513
4514 l1 = xmlXPathNodeSetGetLength(nodes1);
4515
4516 for (i = 0; i < l1; i++) {
4517 cur = xmlXPathNodeSetItem(nodes1, i);
4518 if (xmlXPathNodeSetContains(nodes2, cur)) {
4519 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4520 break;
4521 }
4522 }
4523 return(ret);
4524}
4525
4526/**
4527 * xmlXPathDistinctSorted:
4528 * @nodes: a node-set, sorted by document order
4529 *
4530 * Implements the EXSLT - Sets distinct() function:
4531 * node-set set:distinct (node-set)
4532 *
4533 * Returns a subset of the nodes contained in @nodes, or @nodes if
4534 * it is empty
4535 */
4536xmlNodeSetPtr
4537xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4538 xmlNodeSetPtr ret;
4539 xmlHashTablePtr hash;
4540 int i, l;
4541 xmlChar * strval;
4542 xmlNodePtr cur;
4543
4544 if (xmlXPathNodeSetIsEmpty(nodes))
4545 return(nodes);
4546
4547 ret = xmlXPathNodeSetCreate(NULL);
4548 if (ret == NULL)
4549 return(ret);
4550 l = xmlXPathNodeSetGetLength(nodes);
4551 hash = xmlHashCreate (l);
4552 for (i = 0; i < l; i++) {
4553 cur = xmlXPathNodeSetItem(nodes, i);
4554 strval = xmlXPathCastNodeToString(cur);
4555 if (xmlHashLookup(hash, strval) == NULL) {
4556 xmlHashAddEntry(hash, strval, strval);
4557 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4558 break;
4559 } else {
4560 xmlFree(strval);
4561 }
4562 }
4563 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4564 return(ret);
4565}
4566
4567/**
4568 * xmlXPathDistinct:
4569 * @nodes: a node-set
4570 *
4571 * Implements the EXSLT - Sets distinct() function:
4572 * node-set set:distinct (node-set)
4573 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4574 * is called with the sorted node-set
4575 *
4576 * Returns a subset of the nodes contained in @nodes, or @nodes if
4577 * it is empty
4578 */
4579xmlNodeSetPtr
4580xmlXPathDistinct (xmlNodeSetPtr nodes) {
4581 if (xmlXPathNodeSetIsEmpty(nodes))
4582 return(nodes);
4583
4584 xmlXPathNodeSetSort(nodes);
4585 return(xmlXPathDistinctSorted(nodes));
4586}
4587
4588/**
4589 * xmlXPathHasSameNodes:
4590 * @nodes1: a node-set
4591 * @nodes2: a node-set
4592 *
4593 * Implements the EXSLT - Sets has-same-nodes function:
4594 * boolean set:has-same-node(node-set, node-set)
4595 *
4596 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4597 * otherwise
4598 */
4599int
4600xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4601 int i, l;
4602 xmlNodePtr cur;
4603
4604 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4605 xmlXPathNodeSetIsEmpty(nodes2))
4606 return(0);
4607
4608 l = xmlXPathNodeSetGetLength(nodes1);
4609 for (i = 0; i < l; i++) {
4610 cur = xmlXPathNodeSetItem(nodes1, i);
4611 if (xmlXPathNodeSetContains(nodes2, cur))
4612 return(1);
4613 }
4614 return(0);
4615}
4616
4617/**
4618 * xmlXPathNodeLeadingSorted:
4619 * @nodes: a node-set, sorted by document order
4620 * @node: a node
4621 *
4622 * Implements the EXSLT - Sets leading() function:
4623 * node-set set:leading (node-set, node-set)
4624 *
4625 * Returns the nodes in @nodes that precede @node in document order,
4626 * @nodes if @node is NULL or an empty node-set if @nodes
4627 * doesn't contain @node
4628 */
4629xmlNodeSetPtr
4630xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4631 int i, l;
4632 xmlNodePtr cur;
4633 xmlNodeSetPtr ret;
4634
4635 if (node == NULL)
4636 return(nodes);
4637
4638 ret = xmlXPathNodeSetCreate(NULL);
4639 if (ret == NULL)
4640 return(ret);
4641 if (xmlXPathNodeSetIsEmpty(nodes) ||
4642 (!xmlXPathNodeSetContains(nodes, node)))
4643 return(ret);
4644
4645 l = xmlXPathNodeSetGetLength(nodes);
4646 for (i = 0; i < l; i++) {
4647 cur = xmlXPathNodeSetItem(nodes, i);
4648 if (cur == node)
4649 break;
4650 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4651 break;
4652 }
4653 return(ret);
4654}
4655
4656/**
4657 * xmlXPathNodeLeading:
4658 * @nodes: a node-set
4659 * @node: a node
4660 *
4661 * Implements the EXSLT - Sets leading() function:
4662 * node-set set:leading (node-set, node-set)
4663 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4664 * is called.
4665 *
4666 * Returns the nodes in @nodes that precede @node in document order,
4667 * @nodes if @node is NULL or an empty node-set if @nodes
4668 * doesn't contain @node
4669 */
4670xmlNodeSetPtr
4671xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4672 xmlXPathNodeSetSort(nodes);
4673 return(xmlXPathNodeLeadingSorted(nodes, node));
4674}
4675
4676/**
4677 * xmlXPathLeadingSorted:
4678 * @nodes1: a node-set, sorted by document order
4679 * @nodes2: a node-set, sorted by document order
4680 *
4681 * Implements the EXSLT - Sets leading() function:
4682 * node-set set:leading (node-set, node-set)
4683 *
4684 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4685 * in document order, @nodes1 if @nodes2 is NULL or empty or
4686 * an empty node-set if @nodes1 doesn't contain @nodes2
4687 */
4688xmlNodeSetPtr
4689xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4690 if (xmlXPathNodeSetIsEmpty(nodes2))
4691 return(nodes1);
4692 return(xmlXPathNodeLeadingSorted(nodes1,
4693 xmlXPathNodeSetItem(nodes2, 1)));
4694}
4695
4696/**
4697 * xmlXPathLeading:
4698 * @nodes1: a node-set
4699 * @nodes2: a node-set
4700 *
4701 * Implements the EXSLT - Sets leading() function:
4702 * node-set set:leading (node-set, node-set)
4703 * @nodes1 and @nodes2 are sorted by document order, then
4704 * #exslSetsLeadingSorted is called.
4705 *
4706 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4707 * in document order, @nodes1 if @nodes2 is NULL or empty or
4708 * an empty node-set if @nodes1 doesn't contain @nodes2
4709 */
4710xmlNodeSetPtr
4711xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4712 if (xmlXPathNodeSetIsEmpty(nodes2))
4713 return(nodes1);
4714 if (xmlXPathNodeSetIsEmpty(nodes1))
4715 return(xmlXPathNodeSetCreate(NULL));
4716 xmlXPathNodeSetSort(nodes1);
4717 xmlXPathNodeSetSort(nodes2);
4718 return(xmlXPathNodeLeadingSorted(nodes1,
4719 xmlXPathNodeSetItem(nodes2, 1)));
4720}
4721
4722/**
4723 * xmlXPathNodeTrailingSorted:
4724 * @nodes: a node-set, sorted by document order
4725 * @node: a node
4726 *
4727 * Implements the EXSLT - Sets trailing() function:
4728 * node-set set:trailing (node-set, node-set)
4729 *
4730 * Returns the nodes in @nodes that follow @node in document order,
4731 * @nodes if @node is NULL or an empty node-set if @nodes
4732 * doesn't contain @node
4733 */
4734xmlNodeSetPtr
4735xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4736 int i, l;
4737 xmlNodePtr cur;
4738 xmlNodeSetPtr ret;
4739
4740 if (node == NULL)
4741 return(nodes);
4742
4743 ret = xmlXPathNodeSetCreate(NULL);
4744 if (ret == NULL)
4745 return(ret);
4746 if (xmlXPathNodeSetIsEmpty(nodes) ||
4747 (!xmlXPathNodeSetContains(nodes, node)))
4748 return(ret);
4749
4750 l = xmlXPathNodeSetGetLength(nodes);
4751 for (i = l - 1; i >= 0; i--) {
4752 cur = xmlXPathNodeSetItem(nodes, i);
4753 if (cur == node)
4754 break;
4755 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4756 break;
4757 }
4758 xmlXPathNodeSetSort(ret); /* bug 413451 */
4759 return(ret);
4760}
4761
4762/**
4763 * xmlXPathNodeTrailing:
4764 * @nodes: a node-set
4765 * @node: a node
4766 *
4767 * Implements the EXSLT - Sets trailing() function:
4768 * node-set set:trailing (node-set, node-set)
4769 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4770 * is called.
4771 *
4772 * Returns the nodes in @nodes that follow @node in document order,
4773 * @nodes if @node is NULL or an empty node-set if @nodes
4774 * doesn't contain @node
4775 */
4776xmlNodeSetPtr
4777xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4778 xmlXPathNodeSetSort(nodes);
4779 return(xmlXPathNodeTrailingSorted(nodes, node));
4780}
4781
4782/**
4783 * xmlXPathTrailingSorted:
4784 * @nodes1: a node-set, sorted by document order
4785 * @nodes2: a node-set, sorted by document order
4786 *
4787 * Implements the EXSLT - Sets trailing() function:
4788 * node-set set:trailing (node-set, node-set)
4789 *
4790 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4791 * in document order, @nodes1 if @nodes2 is NULL or empty or
4792 * an empty node-set if @nodes1 doesn't contain @nodes2
4793 */
4794xmlNodeSetPtr
4795xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4796 if (xmlXPathNodeSetIsEmpty(nodes2))
4797 return(nodes1);
4798 return(xmlXPathNodeTrailingSorted(nodes1,
4799 xmlXPathNodeSetItem(nodes2, 0)));
4800}
4801
4802/**
4803 * xmlXPathTrailing:
4804 * @nodes1: a node-set
4805 * @nodes2: a node-set
4806 *
4807 * Implements the EXSLT - Sets trailing() function:
4808 * node-set set:trailing (node-set, node-set)
4809 * @nodes1 and @nodes2 are sorted by document order, then
4810 * #xmlXPathTrailingSorted is called.
4811 *
4812 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4813 * in document order, @nodes1 if @nodes2 is NULL or empty or
4814 * an empty node-set if @nodes1 doesn't contain @nodes2
4815 */
4816xmlNodeSetPtr
4817xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4818 if (xmlXPathNodeSetIsEmpty(nodes2))
4819 return(nodes1);
4820 if (xmlXPathNodeSetIsEmpty(nodes1))
4821 return(xmlXPathNodeSetCreate(NULL));
4822 xmlXPathNodeSetSort(nodes1);
4823 xmlXPathNodeSetSort(nodes2);
4824 return(xmlXPathNodeTrailingSorted(nodes1,
4825 xmlXPathNodeSetItem(nodes2, 0)));
4826}
4827
4828/************************************************************************
4829 * *
4830 * Routines to handle extra functions *
4831 * *
4832 ************************************************************************/
4833
4834/**
4835 * xmlXPathRegisterFunc:
4836 * @ctxt: the XPath context
4837 * @name: the function name
4838 * @f: the function implementation or NULL
4839 *
4840 * Register a new function. If @f is NULL it unregisters the function
4841 *
4842 * Returns 0 in case of success, -1 in case of error
4843 */
4844int
4845xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4846 xmlXPathFunction f) {
4847 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4848}
4849
4850/**
4851 * xmlXPathRegisterFuncNS:
4852 * @ctxt: the XPath context
4853 * @name: the function name
4854 * @ns_uri: the function namespace URI
4855 * @f: the function implementation or NULL
4856 *
4857 * Register a new function. If @f is NULL it unregisters the function
4858 *
4859 * Returns 0 in case of success, -1 in case of error
4860 */
4861int
4862xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4863 const xmlChar *ns_uri, xmlXPathFunction f) {
4864 if (ctxt == NULL)
4865 return(-1);
4866 if (name == NULL)
4867 return(-1);
4868
4869 if (ctxt->funcHash == NULL)
4870 ctxt->funcHash = xmlHashCreate(0);
4871 if (ctxt->funcHash == NULL)
4872 return(-1);
4873 if (f == NULL)
4874 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4875 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4876}
4877
4878/**
4879 * xmlXPathRegisterFuncLookup:
4880 * @ctxt: the XPath context
4881 * @f: the lookup function
4882 * @funcCtxt: the lookup data
4883 *
4884 * Registers an external mechanism to do function lookup.
4885 */
4886void
4887xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4888 xmlXPathFuncLookupFunc f,
4889 void *funcCtxt) {
4890 if (ctxt == NULL)
4891 return;
4892 ctxt->funcLookupFunc = f;
4893 ctxt->funcLookupData = funcCtxt;
4894}
4895
4896/**
4897 * xmlXPathFunctionLookup:
4898 * @ctxt: the XPath context
4899 * @name: the function name
4900 *
4901 * Search in the Function array of the context for the given
4902 * function.
4903 *
4904 * Returns the xmlXPathFunction or NULL if not found
4905 */
4906xmlXPathFunction
4907xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4908 if (ctxt == NULL)
4909 return (NULL);
4910
4911 if (ctxt->funcLookupFunc != NULL) {
4912 xmlXPathFunction ret;
4913 xmlXPathFuncLookupFunc f;
4914
4915 f = ctxt->funcLookupFunc;
4916 ret = f(ctxt->funcLookupData, name, NULL);
4917 if (ret != NULL)
4918 return(ret);
4919 }
4920 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4921}
4922
4923/**
4924 * xmlXPathFunctionLookupNS:
4925 * @ctxt: the XPath context
4926 * @name: the function name
4927 * @ns_uri: the function namespace URI
4928 *
4929 * Search in the Function array of the context for the given
4930 * function.
4931 *
4932 * Returns the xmlXPathFunction or NULL if not found
4933 */
4934xmlXPathFunction
4935xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4936 const xmlChar *ns_uri) {
4937 xmlXPathFunction ret;
4938
4939 if (ctxt == NULL)
4940 return(NULL);
4941 if (name == NULL)
4942 return(NULL);
4943
4944 if (ctxt->funcLookupFunc != NULL) {
4945 xmlXPathFuncLookupFunc f;
4946
4947 f = ctxt->funcLookupFunc;
4948 ret = f(ctxt->funcLookupData, name, ns_uri);
4949 if (ret != NULL)
4950 return(ret);
4951 }
4952
4953 if (ctxt->funcHash == NULL)
4954 return(NULL);
4955
4956 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4957 return(ret);
4958}
4959
4960/**
4961 * xmlXPathRegisteredFuncsCleanup:
4962 * @ctxt: the XPath context
4963 *
4964 * Cleanup the XPath context data associated to registered functions
4965 */
4966void
4967xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4968 if (ctxt == NULL)
4969 return;
4970
4971 xmlHashFree(ctxt->funcHash, NULL);
4972 ctxt->funcHash = NULL;
4973}
4974
4975/************************************************************************
4976 * *
4977 * Routines to handle Variables *
4978 * *
4979 ************************************************************************/
4980
4981/**
4982 * xmlXPathRegisterVariable:
4983 * @ctxt: the XPath context
4984 * @name: the variable name
4985 * @value: the variable value or NULL
4986 *
4987 * Register a new variable value. If @value is NULL it unregisters
4988 * the variable
4989 *
4990 * Returns 0 in case of success, -1 in case of error
4991 */
4992int
4993xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4994 xmlXPathObjectPtr value) {
4995 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4996}
4997
4998/**
4999 * xmlXPathRegisterVariableNS:
5000 * @ctxt: the XPath context
5001 * @name: the variable name
5002 * @ns_uri: the variable namespace URI
5003 * @value: the variable value or NULL
5004 *
5005 * Register a new variable value. If @value is NULL it unregisters
5006 * the variable
5007 *
5008 * Returns 0 in case of success, -1 in case of error
5009 */
5010int
5011xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5012 const xmlChar *ns_uri,
5013 xmlXPathObjectPtr value) {
5014 if (ctxt == NULL)
5015 return(-1);
5016 if (name == NULL)
5017 return(-1);
5018
5019 if (ctxt->varHash == NULL)
5020 ctxt->varHash = xmlHashCreate(0);
5021 if (ctxt->varHash == NULL)
5022 return(-1);
5023 if (value == NULL)
5024 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5025 (xmlHashDeallocator)xmlXPathFreeObject));
5026 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5027 (void *) value,
5028 (xmlHashDeallocator)xmlXPathFreeObject));
5029}
5030
5031/**
5032 * xmlXPathRegisterVariableLookup:
5033 * @ctxt: the XPath context
5034 * @f: the lookup function
5035 * @data: the lookup data
5036 *
5037 * register an external mechanism to do variable lookup
5038 */
5039void
5040xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5041 xmlXPathVariableLookupFunc f, void *data) {
5042 if (ctxt == NULL)
5043 return;
5044 ctxt->varLookupFunc = f;
5045 ctxt->varLookupData = data;
5046}
5047
5048/**
5049 * xmlXPathVariableLookup:
5050 * @ctxt: the XPath context
5051 * @name: the variable name
5052 *
5053 * Search in the Variable array of the context for the given
5054 * variable value.
5055 *
5056 * Returns a copy of the value or NULL if not found
5057 */
5058xmlXPathObjectPtr
5059xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5060 if (ctxt == NULL)
5061 return(NULL);
5062
5063 if (ctxt->varLookupFunc != NULL) {
5064 xmlXPathObjectPtr ret;
5065
5066 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5067 (ctxt->varLookupData, name, NULL);
5068 return(ret);
5069 }
5070 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5071}
5072
5073/**
5074 * xmlXPathVariableLookupNS:
5075 * @ctxt: the XPath context
5076 * @name: the variable name
5077 * @ns_uri: the variable namespace URI
5078 *
5079 * Search in the Variable array of the context for the given
5080 * variable value.
5081 *
5082 * Returns the a copy of the value or NULL if not found
5083 */
5084xmlXPathObjectPtr
5085xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5086 const xmlChar *ns_uri) {
5087 if (ctxt == NULL)
5088 return(NULL);
5089
5090 if (ctxt->varLookupFunc != NULL) {
5091 xmlXPathObjectPtr ret;
5092
5093 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5094 (ctxt->varLookupData, name, ns_uri);
5095 if (ret != NULL) return(ret);
5096 }
5097
5098 if (ctxt->varHash == NULL)
5099 return(NULL);
5100 if (name == NULL)
5101 return(NULL);
5102
5103 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5104 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5105}
5106
5107/**
5108 * xmlXPathRegisteredVariablesCleanup:
5109 * @ctxt: the XPath context
5110 *
5111 * Cleanup the XPath context data associated to registered variables
5112 */
5113void
5114xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5115 if (ctxt == NULL)
5116 return;
5117
5118 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5119 ctxt->varHash = NULL;
5120}
5121
5122/**
5123 * xmlXPathRegisterNs:
5124 * @ctxt: the XPath context
5125 * @prefix: the namespace prefix cannot be NULL or empty string
5126 * @ns_uri: the namespace name
5127 *
5128 * Register a new namespace. If @ns_uri is NULL it unregisters
5129 * the namespace
5130 *
5131 * Returns 0 in case of success, -1 in case of error
5132 */
5133int
5134xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5135 const xmlChar *ns_uri) {
5136 if (ctxt == NULL)
5137 return(-1);
5138 if (prefix == NULL)
5139 return(-1);
5140 if (prefix[0] == 0)
5141 return(-1);
5142
5143 if (ctxt->nsHash == NULL)
5144 ctxt->nsHash = xmlHashCreate(10);
5145 if (ctxt->nsHash == NULL)
5146 return(-1);
5147 if (ns_uri == NULL)
5148 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5149 (xmlHashDeallocator)xmlFree));
5150 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5151 (xmlHashDeallocator)xmlFree));
5152}
5153
5154/**
5155 * xmlXPathNsLookup:
5156 * @ctxt: the XPath context
5157 * @prefix: the namespace prefix value
5158 *
5159 * Search in the namespace declaration array of the context for the given
5160 * namespace name associated to the given prefix
5161 *
5162 * Returns the value or NULL if not found
5163 */
5164const xmlChar *
5165xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5166 if (ctxt == NULL)
5167 return(NULL);
5168 if (prefix == NULL)
5169 return(NULL);
5170
5171#ifdef XML_XML_NAMESPACE
5172 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5173 return(XML_XML_NAMESPACE);
5174#endif
5175
5176 if (ctxt->namespaces != NULL) {
5177 int i;
5178
5179 for (i = 0;i < ctxt->nsNr;i++) {
5180 if ((ctxt->namespaces[i] != NULL) &&
5181 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5182 return(ctxt->namespaces[i]->href);
5183 }
5184 }
5185
5186 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5187}
5188
5189/**
5190 * xmlXPathRegisteredNsCleanup:
5191 * @ctxt: the XPath context
5192 *
5193 * Cleanup the XPath context data associated to registered variables
5194 */
5195void
5196xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5197 if (ctxt == NULL)
5198 return;
5199
5200 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5201 ctxt->nsHash = NULL;
5202}
5203
5204/************************************************************************
5205 * *
5206 * Routines to handle Values *
5207 * *
5208 ************************************************************************/
5209
5210/* Allocations are terrible, one needs to optimize all this !!! */
5211
5212/**
5213 * xmlXPathNewFloat:
5214 * @val: the double value
5215 *
5216 * Create a new xmlXPathObjectPtr of type double and of value @val
5217 *
5218 * Returns the newly created object.
5219 */
5220xmlXPathObjectPtr
5221xmlXPathNewFloat(double val) {
5222 xmlXPathObjectPtr ret;
5223
5224 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5225 if (ret == NULL) {
5226 xmlXPathErrMemory(NULL, "creating float object\n");
5227 return(NULL);
5228 }
5229 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5230 ret->type = XPATH_NUMBER;
5231 ret->floatval = val;
5232#ifdef XP_DEBUG_OBJ_USAGE
5233 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5234#endif
5235 return(ret);
5236}
5237
5238/**
5239 * xmlXPathNewBoolean:
5240 * @val: the boolean value
5241 *
5242 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5243 *
5244 * Returns the newly created object.
5245 */
5246xmlXPathObjectPtr
5247xmlXPathNewBoolean(int val) {
5248 xmlXPathObjectPtr ret;
5249
5250 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5251 if (ret == NULL) {
5252 xmlXPathErrMemory(NULL, "creating boolean object\n");
5253 return(NULL);
5254 }
5255 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5256 ret->type = XPATH_BOOLEAN;
5257 ret->boolval = (val != 0);
5258#ifdef XP_DEBUG_OBJ_USAGE
5259 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5260#endif
5261 return(ret);
5262}
5263
5264/**
5265 * xmlXPathNewString:
5266 * @val: the xmlChar * value
5267 *
5268 * Create a new xmlXPathObjectPtr of type string and of value @val
5269 *
5270 * Returns the newly created object.
5271 */
5272xmlXPathObjectPtr
5273xmlXPathNewString(const xmlChar *val) {
5274 xmlXPathObjectPtr ret;
5275
5276 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5277 if (ret == NULL) {
5278 xmlXPathErrMemory(NULL, "creating string object\n");
5279 return(NULL);
5280 }
5281 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5282 ret->type = XPATH_STRING;
5283 if (val != NULL)
5284 ret->stringval = xmlStrdup(val);
5285 else
5286 ret->stringval = xmlStrdup((const xmlChar *)"");
5287#ifdef XP_DEBUG_OBJ_USAGE
5288 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5289#endif
5290 return(ret);
5291}
5292
5293/**
5294 * xmlXPathWrapString:
5295 * @val: the xmlChar * value
5296 *
5297 * Wraps the @val string into an XPath object.
5298 *
5299 * Returns the newly created object.
5300 */
5301xmlXPathObjectPtr
5302xmlXPathWrapString (xmlChar *val) {
5303 xmlXPathObjectPtr ret;
5304
5305 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5306 if (ret == NULL) {
5307 xmlXPathErrMemory(NULL, "creating string object\n");
5308 return(NULL);
5309 }
5310 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5311 ret->type = XPATH_STRING;
5312 ret->stringval = val;
5313#ifdef XP_DEBUG_OBJ_USAGE
5314 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5315#endif
5316 return(ret);
5317}
5318
5319/**
5320 * xmlXPathNewCString:
5321 * @val: the char * value
5322 *
5323 * Create a new xmlXPathObjectPtr of type string and of value @val
5324 *
5325 * Returns the newly created object.
5326 */
5327xmlXPathObjectPtr
5328xmlXPathNewCString(const char *val) {
5329 xmlXPathObjectPtr ret;
5330
5331 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5332 if (ret == NULL) {
5333 xmlXPathErrMemory(NULL, "creating string object\n");
5334 return(NULL);
5335 }
5336 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5337 ret->type = XPATH_STRING;
5338 ret->stringval = xmlStrdup(BAD_CAST val);
5339#ifdef XP_DEBUG_OBJ_USAGE
5340 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5341#endif
5342 return(ret);
5343}
5344
5345/**
5346 * xmlXPathWrapCString:
5347 * @val: the char * value
5348 *
5349 * Wraps a string into an XPath object.
5350 *
5351 * Returns the newly created object.
5352 */
5353xmlXPathObjectPtr
5354xmlXPathWrapCString (char * val) {
5355 return(xmlXPathWrapString((xmlChar *)(val)));
5356}
5357
5358/**
5359 * xmlXPathWrapExternal:
5360 * @val: the user data
5361 *
5362 * Wraps the @val data into an XPath object.
5363 *
5364 * Returns the newly created object.
5365 */
5366xmlXPathObjectPtr
5367xmlXPathWrapExternal (void *val) {
5368 xmlXPathObjectPtr ret;
5369
5370 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5371 if (ret == NULL) {
5372 xmlXPathErrMemory(NULL, "creating user object\n");
5373 return(NULL);
5374 }
5375 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5376 ret->type = XPATH_USERS;
5377 ret->user = val;
5378#ifdef XP_DEBUG_OBJ_USAGE
5379 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5380#endif
5381 return(ret);
5382}
5383
5384/**
5385 * xmlXPathObjectCopy:
5386 * @val: the original object
5387 *
5388 * allocate a new copy of a given object
5389 *
5390 * Returns the newly created object.
5391 */
5392xmlXPathObjectPtr
5393xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5394 xmlXPathObjectPtr ret;
5395
5396 if (val == NULL)
5397 return(NULL);
5398
5399 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5400 if (ret == NULL) {
5401 xmlXPathErrMemory(NULL, "copying object\n");
5402 return(NULL);
5403 }
5404 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5405#ifdef XP_DEBUG_OBJ_USAGE
5406 xmlXPathDebugObjUsageRequested(NULL, val->type);
5407#endif
5408 switch (val->type) {
5409 case XPATH_BOOLEAN:
5410 case XPATH_NUMBER:
5411 case XPATH_POINT:
5412 case XPATH_RANGE:
5413 break;
5414 case XPATH_STRING:
5415 ret->stringval = xmlStrdup(val->stringval);
5416 break;
5417 case XPATH_XSLT_TREE:
5418#if 0
5419/*
5420 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5421 this previous handling is no longer correct, and can cause some serious
5422 problems (ref. bug 145547)
5423*/
5424 if ((val->nodesetval != NULL) &&
5425 (val->nodesetval->nodeTab != NULL)) {
5426 xmlNodePtr cur, tmp;
5427 xmlDocPtr top;
5428
5429 ret->boolval = 1;
5430 top = xmlNewDoc(NULL);
5431 top->name = (char *)
5432 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5433 ret->user = top;
5434 if (top != NULL) {
5435 top->doc = top;
5436 cur = val->nodesetval->nodeTab[0]->children;
5437 while (cur != NULL) {
5438 tmp = xmlDocCopyNode(cur, top, 1);
5439 xmlAddChild((xmlNodePtr) top, tmp);
5440 cur = cur->next;
5441 }
5442 }
5443
5444 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5445 } else
5446 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5447 /* Deallocate the copied tree value */
5448 break;
5449#endif
5450 case XPATH_NODESET:
5451 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5452 /* Do not deallocate the copied tree value */
5453 ret->boolval = 0;
5454 break;
5455 case XPATH_LOCATIONSET:
5456#ifdef LIBXML_XPTR_ENABLED
5457 {
5458 xmlLocationSetPtr loc = val->user;
5459 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5460 break;
5461 }
5462#endif
5463 case XPATH_USERS:
5464 ret->user = val->user;
5465 break;
5466 case XPATH_UNDEFINED:
5467 xmlGenericError(xmlGenericErrorContext,
5468 "xmlXPathObjectCopy: unsupported type %d\n",
5469 val->type);
5470 break;
5471 }
5472 return(ret);
5473}
5474
5475/**
5476 * xmlXPathFreeObject:
5477 * @obj: the object to free
5478 *
5479 * Free up an xmlXPathObjectPtr object.
5480 */
5481void
5482xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5483 if (obj == NULL) return;
5484 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5485 if (obj->boolval) {
5486#if 0
5487 if (obj->user != NULL) {
5488 xmlXPathFreeNodeSet(obj->nodesetval);
5489 xmlFreeNodeList((xmlNodePtr) obj->user);
5490 } else
5491#endif
5492 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5493 if (obj->nodesetval != NULL)
5494 xmlXPathFreeValueTree(obj->nodesetval);
5495 } else {
5496 if (obj->nodesetval != NULL)
5497 xmlXPathFreeNodeSet(obj->nodesetval);
5498 }
5499#ifdef LIBXML_XPTR_ENABLED
5500 } else if (obj->type == XPATH_LOCATIONSET) {
5501 if (obj->user != NULL)
5502 xmlXPtrFreeLocationSet(obj->user);
5503#endif
5504 } else if (obj->type == XPATH_STRING) {
5505 if (obj->stringval != NULL)
5506 xmlFree(obj->stringval);
5507 }
5508#ifdef XP_DEBUG_OBJ_USAGE
5509 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5510#endif
5511 xmlFree(obj);
5512}
5513
5514/**
5515 * xmlXPathReleaseObject:
5516 * @obj: the xmlXPathObjectPtr to free or to cache
5517 *
5518 * Depending on the state of the cache this frees the given
5519 * XPath object or stores it in the cache.
5520 */
5521static void
5522xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5523{
5524#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5525 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5526 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5527
5528#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5529
5530 if (obj == NULL)
5531 return;
5532 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5533 xmlXPathFreeObject(obj);
5534 } else {
5535 xmlXPathContextCachePtr cache =
5536 (xmlXPathContextCachePtr) ctxt->cache;
5537
5538 switch (obj->type) {
5539 case XPATH_NODESET:
5540 case XPATH_XSLT_TREE:
5541 if (obj->nodesetval != NULL) {
5542 if (obj->boolval) {
5543 /*
5544 * It looks like the @boolval is used for
5545 * evaluation if this an XSLT Result Tree Fragment.
5546 * TODO: Check if this assumption is correct.
5547 */
5548 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5549 xmlXPathFreeValueTree(obj->nodesetval);
5550 obj->nodesetval = NULL;
5551 } else if ((obj->nodesetval->nodeMax <= 40) &&
5552 (XP_CACHE_WANTS(cache->nodesetObjs,
5553 cache->maxNodeset)))
5554 {
5555 XP_CACHE_ADD(cache->nodesetObjs, obj);
5556 goto obj_cached;
5557 } else {
5558 xmlXPathFreeNodeSet(obj->nodesetval);
5559 obj->nodesetval = NULL;
5560 }
5561 }
5562 break;
5563 case XPATH_STRING:
5564 if (obj->stringval != NULL)
5565 xmlFree(obj->stringval);
5566
5567 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5568 XP_CACHE_ADD(cache->stringObjs, obj);
5569 goto obj_cached;
5570 }
5571 break;
5572 case XPATH_BOOLEAN:
5573 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5574 XP_CACHE_ADD(cache->booleanObjs, obj);
5575 goto obj_cached;
5576 }
5577 break;
5578 case XPATH_NUMBER:
5579 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5580 XP_CACHE_ADD(cache->numberObjs, obj);
5581 goto obj_cached;
5582 }
5583 break;
5584#ifdef LIBXML_XPTR_ENABLED
5585 case XPATH_LOCATIONSET:
5586 if (obj->user != NULL) {
5587 xmlXPtrFreeLocationSet(obj->user);
5588 }
5589 goto free_obj;
5590#endif
5591 default:
5592 goto free_obj;
5593 }
5594
5595 /*
5596 * Fallback to adding to the misc-objects slot.
5597 */
5598 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5599 XP_CACHE_ADD(cache->miscObjs, obj);
5600 } else
5601 goto free_obj;
5602
5603obj_cached:
5604
5605#ifdef XP_DEBUG_OBJ_USAGE
5606 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5607#endif
5608
5609 if (obj->nodesetval != NULL) {
5610 xmlNodeSetPtr tmpset = obj->nodesetval;
5611
5612 /*
5613 * TODO: Due to those nasty ns-nodes, we need to traverse
5614 * the list and free the ns-nodes.
5615 * URGENT TODO: Check if it's actually slowing things down.
5616 * Maybe we shouldn't try to preserve the list.
5617 */
5618 if (tmpset->nodeNr > 1) {
5619 int i;
5620 xmlNodePtr node;
5621
5622 for (i = 0; i < tmpset->nodeNr; i++) {
5623 node = tmpset->nodeTab[i];
5624 if ((node != NULL) &&
5625 (node->type == XML_NAMESPACE_DECL))
5626 {
5627 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5628 }
5629 }
5630 } else if (tmpset->nodeNr == 1) {
5631 if ((tmpset->nodeTab[0] != NULL) &&
5632 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5633 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5634 }
5635 tmpset->nodeNr = 0;
5636 memset(obj, 0, sizeof(xmlXPathObject));
5637 obj->nodesetval = tmpset;
5638 } else
5639 memset(obj, 0, sizeof(xmlXPathObject));
5640
5641 return;
5642
5643free_obj:
5644 /*
5645 * Cache is full; free the object.
5646 */
5647 if (obj->nodesetval != NULL)
5648 xmlXPathFreeNodeSet(obj->nodesetval);
5649#ifdef XP_DEBUG_OBJ_USAGE
5650 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5651#endif
5652 xmlFree(obj);
5653 }
5654 return;
5655}
5656
5657
5658/************************************************************************
5659 * *
5660 * Type Casting Routines *
5661 * *
5662 ************************************************************************/
5663
5664/**
5665 * xmlXPathCastBooleanToString:
5666 * @val: a boolean
5667 *
5668 * Converts a boolean to its string value.
5669 *
5670 * Returns a newly allocated string.
5671 */
5672xmlChar *
5673xmlXPathCastBooleanToString (int val) {
5674 xmlChar *ret;
5675 if (val)
5676 ret = xmlStrdup((const xmlChar *) "true");
5677 else
5678 ret = xmlStrdup((const xmlChar *) "false");
5679 return(ret);
5680}
5681
5682/**
5683 * xmlXPathCastNumberToString:
5684 * @val: a number
5685 *
5686 * Converts a number to its string value.
5687 *
5688 * Returns a newly allocated string.
5689 */
5690xmlChar *
5691xmlXPathCastNumberToString (double val) {
5692 xmlChar *ret;
5693 switch (xmlXPathIsInf(val)) {
5694 case 1:
5695 ret = xmlStrdup((const xmlChar *) "Infinity");
5696 break;
5697 case -1:
5698 ret = xmlStrdup((const xmlChar *) "-Infinity");
5699 break;
5700 default:
5701 if (xmlXPathIsNaN(val)) {
5702 ret = xmlStrdup((const xmlChar *) "NaN");
5703 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5704 ret = xmlStrdup((const xmlChar *) "0");
5705 } else {
5706 /* could be improved */
5707 char buf[100];
5708 xmlXPathFormatNumber(val, buf, 99);
5709 buf[99] = 0;
5710 ret = xmlStrdup((const xmlChar *) buf);
5711 }
5712 }
5713 return(ret);
5714}
5715
5716/**
5717 * xmlXPathCastNodeToString:
5718 * @node: a node
5719 *
5720 * Converts a node to its string value.
5721 *
5722 * Returns a newly allocated string.
5723 */
5724xmlChar *
5725xmlXPathCastNodeToString (xmlNodePtr node) {
5726xmlChar *ret;
5727 if ((ret = xmlNodeGetContent(node)) == NULL)
5728 ret = xmlStrdup((const xmlChar *) "");
5729 return(ret);
5730}
5731
5732/**
5733 * xmlXPathCastNodeSetToString:
5734 * @ns: a node-set
5735 *
5736 * Converts a node-set to its string value.
5737 *
5738 * Returns a newly allocated string.
5739 */
5740xmlChar *
5741xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5742 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5743 return(xmlStrdup((const xmlChar *) ""));
5744
5745 if (ns->nodeNr > 1)
5746 xmlXPathNodeSetSort(ns);
5747 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5748}
5749
5750/**
5751 * xmlXPathCastToString:
5752 * @val: an XPath object
5753 *
5754 * Converts an existing object to its string() equivalent
5755 *
5756 * Returns the allocated string value of the object, NULL in case of error.
5757 * It's up to the caller to free the string memory with xmlFree().
5758 */
5759xmlChar *
5760xmlXPathCastToString(xmlXPathObjectPtr val) {
5761 xmlChar *ret = NULL;
5762
5763 if (val == NULL)
5764 return(xmlStrdup((const xmlChar *) ""));
5765 switch (val->type) {
5766 case XPATH_UNDEFINED:
5767#ifdef DEBUG_EXPR
5768 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5769#endif
5770 ret = xmlStrdup((const xmlChar *) "");
5771 break;
5772 case XPATH_NODESET:
5773 case XPATH_XSLT_TREE:
5774 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5775 break;
5776 case XPATH_STRING:
5777 return(xmlStrdup(val->stringval));
5778 case XPATH_BOOLEAN:
5779 ret = xmlXPathCastBooleanToString(val->boolval);
5780 break;
5781 case XPATH_NUMBER: {
5782 ret = xmlXPathCastNumberToString(val->floatval);
5783 break;
5784 }
5785 case XPATH_USERS:
5786 case XPATH_POINT:
5787 case XPATH_RANGE:
5788 case XPATH_LOCATIONSET:
5789 TODO
5790 ret = xmlStrdup((const xmlChar *) "");
5791 break;
5792 }
5793 return(ret);
5794}
5795
5796/**
5797 * xmlXPathConvertString:
5798 * @val: an XPath object
5799 *
5800 * Converts an existing object to its string() equivalent
5801 *
5802 * Returns the new object, the old one is freed (or the operation
5803 * is done directly on @val)
5804 */
5805xmlXPathObjectPtr
5806xmlXPathConvertString(xmlXPathObjectPtr val) {
5807 xmlChar *res = NULL;
5808
5809 if (val == NULL)
5810 return(xmlXPathNewCString(""));
5811
5812 switch (val->type) {
5813 case XPATH_UNDEFINED:
5814#ifdef DEBUG_EXPR
5815 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5816#endif
5817 break;
5818 case XPATH_NODESET:
5819 case XPATH_XSLT_TREE:
5820 res = xmlXPathCastNodeSetToString(val->nodesetval);
5821 break;
5822 case XPATH_STRING:
5823 return(val);
5824 case XPATH_BOOLEAN:
5825 res = xmlXPathCastBooleanToString(val->boolval);
5826 break;
5827 case XPATH_NUMBER:
5828 res = xmlXPathCastNumberToString(val->floatval);
5829 break;
5830 case XPATH_USERS:
5831 case XPATH_POINT:
5832 case XPATH_RANGE:
5833 case XPATH_LOCATIONSET:
5834 TODO;
5835 break;
5836 }
5837 xmlXPathFreeObject(val);
5838 if (res == NULL)
5839 return(xmlXPathNewCString(""));
5840 return(xmlXPathWrapString(res));
5841}
5842
5843/**
5844 * xmlXPathCastBooleanToNumber:
5845 * @val: a boolean
5846 *
5847 * Converts a boolean to its number value
5848 *
5849 * Returns the number value
5850 */
5851double
5852xmlXPathCastBooleanToNumber(int val) {
5853 if (val)
5854 return(1.0);
5855 return(0.0);
5856}
5857
5858/**
5859 * xmlXPathCastStringToNumber:
5860 * @val: a string
5861 *
5862 * Converts a string to its number value
5863 *
5864 * Returns the number value
5865 */
5866double
5867xmlXPathCastStringToNumber(const xmlChar * val) {
5868 return(xmlXPathStringEvalNumber(val));
5869}
5870
5871/**
5872 * xmlXPathCastNodeToNumber:
5873 * @node: a node
5874 *
5875 * Converts a node to its number value
5876 *
5877 * Returns the number value
5878 */
5879double
5880xmlXPathCastNodeToNumber (xmlNodePtr node) {
5881 xmlChar *strval;
5882 double ret;
5883
5884 if (node == NULL)
5885 return(xmlXPathNAN);
5886 strval = xmlXPathCastNodeToString(node);
5887 if (strval == NULL)
5888 return(xmlXPathNAN);
5889 ret = xmlXPathCastStringToNumber(strval);
5890 xmlFree(strval);
5891
5892 return(ret);
5893}
5894
5895/**
5896 * xmlXPathCastNodeSetToNumber:
5897 * @ns: a node-set
5898 *
5899 * Converts a node-set to its number value
5900 *
5901 * Returns the number value
5902 */
5903double
5904xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5905 xmlChar *str;
5906 double ret;
5907
5908 if (ns == NULL)
5909 return(xmlXPathNAN);
5910 str = xmlXPathCastNodeSetToString(ns);
5911 ret = xmlXPathCastStringToNumber(str);
5912 xmlFree(str);
5913 return(ret);
5914}
5915
5916/**
5917 * xmlXPathCastToNumber:
5918 * @val: an XPath object
5919 *
5920 * Converts an XPath object to its number value
5921 *
5922 * Returns the number value
5923 */
5924double
5925xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5926 double ret = 0.0;
5927
5928 if (val == NULL)
5929 return(xmlXPathNAN);
5930 switch (val->type) {
5931 case XPATH_UNDEFINED:
5932#ifdef DEGUB_EXPR
5933 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5934#endif
5935 ret = xmlXPathNAN;
5936 break;
5937 case XPATH_NODESET:
5938 case XPATH_XSLT_TREE:
5939 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5940 break;
5941 case XPATH_STRING:
5942 ret = xmlXPathCastStringToNumber(val->stringval);
5943 break;
5944 case XPATH_NUMBER:
5945 ret = val->floatval;
5946 break;
5947 case XPATH_BOOLEAN:
5948 ret = xmlXPathCastBooleanToNumber(val->boolval);
5949 break;
5950 case XPATH_USERS:
5951 case XPATH_POINT:
5952 case XPATH_RANGE:
5953 case XPATH_LOCATIONSET:
5954 TODO;
5955 ret = xmlXPathNAN;
5956 break;
5957 }
5958 return(ret);
5959}
5960
5961/**
5962 * xmlXPathConvertNumber:
5963 * @val: an XPath object
5964 *
5965 * Converts an existing object to its number() equivalent
5966 *
5967 * Returns the new object, the old one is freed (or the operation
5968 * is done directly on @val)
5969 */
5970xmlXPathObjectPtr
5971xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5972 xmlXPathObjectPtr ret;
5973
5974 if (val == NULL)
5975 return(xmlXPathNewFloat(0.0));
5976 if (val->type == XPATH_NUMBER)
5977 return(val);
5978 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5979 xmlXPathFreeObject(val);
5980 return(ret);
5981}
5982
5983/**
5984 * xmlXPathCastNumberToBoolean:
5985 * @val: a number
5986 *
5987 * Converts a number to its boolean value
5988 *
5989 * Returns the boolean value
5990 */
5991int
5992xmlXPathCastNumberToBoolean (double val) {
5993 if (xmlXPathIsNaN(val) || (val == 0.0))
5994 return(0);
5995 return(1);
5996}
5997
5998/**
5999 * xmlXPathCastStringToBoolean:
6000 * @val: a string
6001 *
6002 * Converts a string to its boolean value
6003 *
6004 * Returns the boolean value
6005 */
6006int
6007xmlXPathCastStringToBoolean (const xmlChar *val) {
6008 if ((val == NULL) || (xmlStrlen(val) == 0))
6009 return(0);
6010 return(1);
6011}
6012
6013/**
6014 * xmlXPathCastNodeSetToBoolean:
6015 * @ns: a node-set
6016 *
6017 * Converts a node-set to its boolean value
6018 *
6019 * Returns the boolean value
6020 */
6021int
6022xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6023 if ((ns == NULL) || (ns->nodeNr == 0))
6024 return(0);
6025 return(1);
6026}
6027
6028/**
6029 * xmlXPathCastToBoolean:
6030 * @val: an XPath object
6031 *
6032 * Converts an XPath object to its boolean value
6033 *
6034 * Returns the boolean value
6035 */
6036int
6037xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6038 int ret = 0;
6039
6040 if (val == NULL)
6041 return(0);
6042 switch (val->type) {
6043 case XPATH_UNDEFINED:
6044#ifdef DEBUG_EXPR
6045 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6046#endif
6047 ret = 0;
6048 break;
6049 case XPATH_NODESET:
6050 case XPATH_XSLT_TREE:
6051 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6052 break;
6053 case XPATH_STRING:
6054 ret = xmlXPathCastStringToBoolean(val->stringval);
6055 break;
6056 case XPATH_NUMBER:
6057 ret = xmlXPathCastNumberToBoolean(val->floatval);
6058 break;
6059 case XPATH_BOOLEAN:
6060 ret = val->boolval;
6061 break;
6062 case XPATH_USERS:
6063 case XPATH_POINT:
6064 case XPATH_RANGE:
6065 case XPATH_LOCATIONSET:
6066 TODO;
6067 ret = 0;
6068 break;
6069 }
6070 return(ret);
6071}
6072
6073
6074/**
6075 * xmlXPathConvertBoolean:
6076 * @val: an XPath object
6077 *
6078 * Converts an existing object to its boolean() equivalent
6079 *
6080 * Returns the new object, the old one is freed (or the operation
6081 * is done directly on @val)
6082 */
6083xmlXPathObjectPtr
6084xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6085 xmlXPathObjectPtr ret;
6086
6087 if (val == NULL)
6088 return(xmlXPathNewBoolean(0));
6089 if (val->type == XPATH_BOOLEAN)
6090 return(val);
6091 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6092 xmlXPathFreeObject(val);
6093 return(ret);
6094}
6095
6096/************************************************************************
6097 * *
6098 * Routines to handle XPath contexts *
6099 * *
6100 ************************************************************************/
6101
6102/**
6103 * xmlXPathNewContext:
6104 * @doc: the XML document
6105 *
6106 * Create a new xmlXPathContext
6107 *
6108 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6109 */
6110xmlXPathContextPtr
6111xmlXPathNewContext(xmlDocPtr doc) {
6112 xmlXPathContextPtr ret;
6113
6114 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6115 if (ret == NULL) {
6116 xmlXPathErrMemory(NULL, "creating context\n");
6117 return(NULL);
6118 }
6119 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6120 ret->doc = doc;
6121 ret->node = NULL;
6122
6123 ret->varHash = NULL;
6124
6125 ret->nb_types = 0;
6126 ret->max_types = 0;
6127 ret->types = NULL;
6128
6129 ret->funcHash = xmlHashCreate(0);
6130
6131 ret->nb_axis = 0;
6132 ret->max_axis = 0;
6133 ret->axis = NULL;
6134
6135 ret->nsHash = NULL;
6136 ret->user = NULL;
6137
6138 ret->contextSize = -1;
6139 ret->proximityPosition = -1;
6140
6141#ifdef XP_DEFAULT_CACHE_ON
6142 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6143 xmlXPathFreeContext(ret);
6144 return(NULL);
6145 }
6146#endif
6147
6148 xmlXPathRegisterAllFunctions(ret);
6149
6150 return(ret);
6151}
6152
6153/**
6154 * xmlXPathFreeContext:
6155 * @ctxt: the context to free
6156 *
6157 * Free up an xmlXPathContext
6158 */
6159void
6160xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6161 if (ctxt == NULL) return;
6162
6163 if (ctxt->cache != NULL)
6164 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6165 xmlXPathRegisteredNsCleanup(ctxt);
6166 xmlXPathRegisteredFuncsCleanup(ctxt);
6167 xmlXPathRegisteredVariablesCleanup(ctxt);
6168 xmlResetError(&ctxt->lastError);
6169 xmlFree(ctxt);
6170}
6171
6172/************************************************************************
6173 * *
6174 * Routines to handle XPath parser contexts *
6175 * *
6176 ************************************************************************/
6177
6178#define CHECK_CTXT(ctxt) \
6179 if (ctxt == NULL) { \
6180 __xmlRaiseError(NULL, NULL, NULL, \
6181 NULL, NULL, XML_FROM_XPATH, \
6182 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6183 __FILE__, __LINE__, \
6184 NULL, NULL, NULL, 0, 0, \
6185 "NULL context pointer\n"); \
6186 return(NULL); \
6187 } \
6188
6189#define CHECK_CTXT_NEG(ctxt) \
6190 if (ctxt == NULL) { \
6191 __xmlRaiseError(NULL, NULL, NULL, \
6192 NULL, NULL, XML_FROM_XPATH, \
6193 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6194 __FILE__, __LINE__, \
6195 NULL, NULL, NULL, 0, 0, \
6196 "NULL context pointer\n"); \
6197 return(-1); \
6198 } \
6199
6200
6201#define CHECK_CONTEXT(ctxt) \
6202 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6203 (ctxt->doc->children == NULL)) { \
6204 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6205 return(NULL); \
6206 }
6207
6208
6209/**
6210 * xmlXPathNewParserContext:
6211 * @str: the XPath expression
6212 * @ctxt: the XPath context
6213 *
6214 * Create a new xmlXPathParserContext
6215 *
6216 * Returns the xmlXPathParserContext just allocated.
6217 */
6218xmlXPathParserContextPtr
6219xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6220 xmlXPathParserContextPtr ret;
6221
6222 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6223 if (ret == NULL) {
6224 xmlXPathErrMemory(ctxt, "creating parser context\n");
6225 return(NULL);
6226 }
6227 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6228 ret->cur = ret->base = str;
6229 ret->context = ctxt;
6230
6231 ret->comp = xmlXPathNewCompExpr();
6232 if (ret->comp == NULL) {
6233 xmlFree(ret->valueTab);
6234 xmlFree(ret);
6235 return(NULL);
6236 }
6237 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6238 ret->comp->dict = ctxt->dict;
6239 xmlDictReference(ret->comp->dict);
6240 }
6241
6242 return(ret);
6243}
6244
6245/**
6246 * xmlXPathCompParserContext:
6247 * @comp: the XPath compiled expression
6248 * @ctxt: the XPath context
6249 *
6250 * Create a new xmlXPathParserContext when processing a compiled expression
6251 *
6252 * Returns the xmlXPathParserContext just allocated.
6253 */
6254static xmlXPathParserContextPtr
6255xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6256 xmlXPathParserContextPtr ret;
6257
6258 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6259 if (ret == NULL) {
6260 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6261 return(NULL);
6262 }
6263 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6264
6265 /* Allocate the value stack */
6266 ret->valueTab = (xmlXPathObjectPtr *)
6267 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6268 if (ret->valueTab == NULL) {
6269 xmlFree(ret);
6270 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6271 return(NULL);
6272 }
6273 ret->valueNr = 0;
6274 ret->valueMax = 10;
6275 ret->value = NULL;
6276 ret->valueFrame = 0;
6277
6278 ret->context = ctxt;
6279 ret->comp = comp;
6280
6281 return(ret);
6282}
6283
6284/**
6285 * xmlXPathFreeParserContext:
6286 * @ctxt: the context to free
6287 *
6288 * Free up an xmlXPathParserContext
6289 */
6290void
6291xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6292 if (ctxt->valueTab != NULL) {
6293 xmlFree(ctxt->valueTab);
6294 }
6295 if (ctxt->comp != NULL) {
6296#ifdef XPATH_STREAMING
6297 if (ctxt->comp->stream != NULL) {
6298 xmlFreePatternList(ctxt->comp->stream);
6299 ctxt->comp->stream = NULL;
6300 }
6301#endif
6302 xmlXPathFreeCompExpr(ctxt->comp);
6303 }
6304 xmlFree(ctxt);
6305}
6306
6307/************************************************************************
6308 * *
6309 * The implicit core function library *
6310 * *
6311 ************************************************************************/
6312
6313/**
6314 * xmlXPathNodeValHash:
6315 * @node: a node pointer
6316 *
6317 * Function computing the beginning of the string value of the node,
6318 * used to speed up comparisons
6319 *
6320 * Returns an int usable as a hash
6321 */
6322static unsigned int
6323xmlXPathNodeValHash(xmlNodePtr node) {
6324 int len = 2;
6325 const xmlChar * string = NULL;
6326 xmlNodePtr tmp = NULL;
6327 unsigned int ret = 0;
6328
6329 if (node == NULL)
6330 return(0);
6331
6332 if (node->type == XML_DOCUMENT_NODE) {
6333 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6334 if (tmp == NULL)
6335 node = node->children;
6336 else
6337 node = tmp;
6338
6339 if (node == NULL)
6340 return(0);
6341 }
6342
6343 switch (node->type) {
6344 case XML_COMMENT_NODE:
6345 case XML_PI_NODE:
6346 case XML_CDATA_SECTION_NODE:
6347 case XML_TEXT_NODE:
6348 string = node->content;
6349 if (string == NULL)
6350 return(0);
6351 if (string[0] == 0)
6352 return(0);
6353 return(((unsigned int) string[0]) +
6354 (((unsigned int) string[1]) << 8));
6355 case XML_NAMESPACE_DECL:
6356 string = ((xmlNsPtr)node)->href;
6357 if (string == NULL)
6358 return(0);
6359 if (string[0] == 0)
6360 return(0);
6361 return(((unsigned int) string[0]) +
6362 (((unsigned int) string[1]) << 8));
6363 case XML_ATTRIBUTE_NODE:
6364 tmp = ((xmlAttrPtr) node)->children;
6365 break;
6366 case XML_ELEMENT_NODE:
6367 tmp = node->children;
6368 break;
6369 default:
6370 return(0);
6371 }
6372 while (tmp != NULL) {
6373 switch (tmp->type) {
6374 case XML_COMMENT_NODE:
6375 case XML_PI_NODE:
6376 case XML_CDATA_SECTION_NODE:
6377 case XML_TEXT_NODE:
6378 string = tmp->content;
6379 break;
6380 case XML_NAMESPACE_DECL:
6381 string = ((xmlNsPtr)tmp)->href;
6382 break;
6383 default:
6384 break;
6385 }
6386 if ((string != NULL) && (string[0] != 0)) {
6387 if (len == 1) {
6388 return(ret + (((unsigned int) string[0]) << 8));
6389 }
6390 if (string[1] == 0) {
6391 len = 1;
6392 ret = (unsigned int) string[0];
6393 } else {
6394 return(((unsigned int) string[0]) +
6395 (((unsigned int) string[1]) << 8));
6396 }
6397 }
6398 /*
6399 * Skip to next node
6400 */
6401 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6402 if (tmp->children->type != XML_ENTITY_DECL) {
6403 tmp = tmp->children;
6404 continue;
6405 }
6406 }
6407 if (tmp == node)
6408 break;
6409
6410 if (tmp->next != NULL) {
6411 tmp = tmp->next;
6412 continue;
6413 }
6414
6415 do {
6416 tmp = tmp->parent;
6417 if (tmp == NULL)
6418 break;
6419 if (tmp == node) {
6420 tmp = NULL;
6421 break;
6422 }
6423 if (tmp->next != NULL) {
6424 tmp = tmp->next;
6425 break;
6426 }
6427 } while (tmp != NULL);
6428 }
6429 return(ret);
6430}
6431
6432/**
6433 * xmlXPathStringHash:
6434 * @string: a string
6435 *
6436 * Function computing the beginning of the string value of the node,
6437 * used to speed up comparisons
6438 *
6439 * Returns an int usable as a hash
6440 */
6441static unsigned int
6442xmlXPathStringHash(const xmlChar * string) {
6443 if (string == NULL)
6444 return((unsigned int) 0);
6445 if (string[0] == 0)
6446 return(0);
6447 return(((unsigned int) string[0]) +
6448 (((unsigned int) string[1]) << 8));
6449}
6450
6451/**
6452 * xmlXPathCompareNodeSetFloat:
6453 * @ctxt: the XPath Parser context
6454 * @inf: less than (1) or greater than (0)
6455 * @strict: is the comparison strict
6456 * @arg: the node set
6457 * @f: the value
6458 *
6459 * Implement the compare operation between a nodeset and a number
6460 * @ns < @val (1, 1, ...
6461 * @ns <= @val (1, 0, ...
6462 * @ns > @val (0, 1, ...
6463 * @ns >= @val (0, 0, ...
6464 *
6465 * If one object to be compared is a node-set and the other is a number,
6466 * then the comparison will be true if and only if there is a node in the
6467 * node-set such that the result of performing the comparison on the number
6468 * to be compared and on the result of converting the string-value of that
6469 * node to a number using the number function is true.
6470 *
6471 * Returns 0 or 1 depending on the results of the test.
6472 */
6473static int
6474xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6475 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6476 int i, ret = 0;
6477 xmlNodeSetPtr ns;
6478 xmlChar *str2;
6479
6480 if ((f == NULL) || (arg == NULL) ||
6481 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6482 xmlXPathReleaseObject(ctxt->context, arg);
6483 xmlXPathReleaseObject(ctxt->context, f);
6484 return(0);
6485 }
6486 ns = arg->nodesetval;
6487 if (ns != NULL) {
6488 for (i = 0;i < ns->nodeNr;i++) {
6489 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6490 if (str2 != NULL) {
6491 valuePush(ctxt,
6492 xmlXPathCacheNewString(ctxt->context, str2));
6493 xmlFree(str2);
6494 xmlXPathNumberFunction(ctxt, 1);
6495 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6496 ret = xmlXPathCompareValues(ctxt, inf, strict);
6497 if (ret)
6498 break;
6499 }
6500 }
6501 }
6502 xmlXPathReleaseObject(ctxt->context, arg);
6503 xmlXPathReleaseObject(ctxt->context, f);
6504 return(ret);
6505}
6506
6507/**
6508 * xmlXPathCompareNodeSetString:
6509 * @ctxt: the XPath Parser context
6510 * @inf: less than (1) or greater than (0)
6511 * @strict: is the comparison strict
6512 * @arg: the node set
6513 * @s: the value
6514 *
6515 * Implement the compare operation between a nodeset and a string
6516 * @ns < @val (1, 1, ...
6517 * @ns <= @val (1, 0, ...
6518 * @ns > @val (0, 1, ...
6519 * @ns >= @val (0, 0, ...
6520 *
6521 * If one object to be compared is a node-set and the other is a string,
6522 * then the comparison will be true if and only if there is a node in
6523 * the node-set such that the result of performing the comparison on the
6524 * string-value of the node and the other string is true.
6525 *
6526 * Returns 0 or 1 depending on the results of the test.
6527 */
6528static int
6529xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6530 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6531 int i, ret = 0;
6532 xmlNodeSetPtr ns;
6533 xmlChar *str2;
6534
6535 if ((s == NULL) || (arg == NULL) ||
6536 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6537 xmlXPathReleaseObject(ctxt->context, arg);
6538 xmlXPathReleaseObject(ctxt->context, s);
6539 return(0);
6540 }
6541 ns = arg->nodesetval;
6542 if (ns != NULL) {
6543 for (i = 0;i < ns->nodeNr;i++) {
6544 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6545 if (str2 != NULL) {
6546 valuePush(ctxt,
6547 xmlXPathCacheNewString(ctxt->context, str2));
6548 xmlFree(str2);
6549 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6550 ret = xmlXPathCompareValues(ctxt, inf, strict);
6551 if (ret)
6552 break;
6553 }
6554 }
6555 }
6556 xmlXPathReleaseObject(ctxt->context, arg);
6557 xmlXPathReleaseObject(ctxt->context, s);
6558 return(ret);
6559}
6560
6561/**
6562 * xmlXPathCompareNodeSets:
6563 * @inf: less than (1) or greater than (0)
6564 * @strict: is the comparison strict
6565 * @arg1: the first node set object
6566 * @arg2: the second node set object
6567 *
6568 * Implement the compare operation on nodesets:
6569 *
6570 * If both objects to be compared are node-sets, then the comparison
6571 * will be true if and only if there is a node in the first node-set
6572 * and a node in the second node-set such that the result of performing
6573 * the comparison on the string-values of the two nodes is true.
6574 * ....
6575 * When neither object to be compared is a node-set and the operator
6576 * is <=, <, >= or >, then the objects are compared by converting both
6577 * objects to numbers and comparing the numbers according to IEEE 754.
6578 * ....
6579 * The number function converts its argument to a number as follows:
6580 * - a string that consists of optional whitespace followed by an
6581 * optional minus sign followed by a Number followed by whitespace
6582 * is converted to the IEEE 754 number that is nearest (according
6583 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6584 * represented by the string; any other string is converted to NaN
6585 *
6586 * Conclusion all nodes need to be converted first to their string value
6587 * and then the comparison must be done when possible
6588 */
6589static int
6590xmlXPathCompareNodeSets(int inf, int strict,
6591 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6592 int i, j, init = 0;
6593 double val1;
6594 double *values2;
6595 int ret = 0;
6596 xmlNodeSetPtr ns1;
6597 xmlNodeSetPtr ns2;
6598
6599 if ((arg1 == NULL) ||
6600 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6601 xmlXPathFreeObject(arg2);
6602 return(0);
6603 }
6604 if ((arg2 == NULL) ||
6605 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6606 xmlXPathFreeObject(arg1);
6607 xmlXPathFreeObject(arg2);
6608 return(0);
6609 }
6610
6611 ns1 = arg1->nodesetval;
6612 ns2 = arg2->nodesetval;
6613
6614 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6615 xmlXPathFreeObject(arg1);
6616 xmlXPathFreeObject(arg2);
6617 return(0);
6618 }
6619 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6620 xmlXPathFreeObject(arg1);
6621 xmlXPathFreeObject(arg2);
6622 return(0);
6623 }
6624
6625 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6626 if (values2 == NULL) {
6627 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6628 xmlXPathFreeObject(arg1);
6629 xmlXPathFreeObject(arg2);
6630 return(0);
6631 }
6632 for (i = 0;i < ns1->nodeNr;i++) {
6633 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6634 if (xmlXPathIsNaN(val1))
6635 continue;
6636 for (j = 0;j < ns2->nodeNr;j++) {
6637 if (init == 0) {
6638 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6639 }
6640 if (xmlXPathIsNaN(values2[j]))
6641 continue;
6642 if (inf && strict)
6643 ret = (val1 < values2[j]);
6644 else if (inf && !strict)
6645 ret = (val1 <= values2[j]);
6646 else if (!inf && strict)
6647 ret = (val1 > values2[j]);
6648 else if (!inf && !strict)
6649 ret = (val1 >= values2[j]);
6650 if (ret)
6651 break;
6652 }
6653 if (ret)
6654 break;
6655 init = 1;
6656 }
6657 xmlFree(values2);
6658 xmlXPathFreeObject(arg1);
6659 xmlXPathFreeObject(arg2);
6660 return(ret);
6661}
6662
6663/**
6664 * xmlXPathCompareNodeSetValue:
6665 * @ctxt: the XPath Parser context
6666 * @inf: less than (1) or greater than (0)
6667 * @strict: is the comparison strict
6668 * @arg: the node set
6669 * @val: the value
6670 *
6671 * Implement the compare operation between a nodeset and a value
6672 * @ns < @val (1, 1, ...
6673 * @ns <= @val (1, 0, ...
6674 * @ns > @val (0, 1, ...
6675 * @ns >= @val (0, 0, ...
6676 *
6677 * If one object to be compared is a node-set and the other is a boolean,
6678 * then the comparison will be true if and only if the result of performing
6679 * the comparison on the boolean and on the result of converting
6680 * the node-set to a boolean using the boolean function is true.
6681 *
6682 * Returns 0 or 1 depending on the results of the test.
6683 */
6684static int
6685xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6686 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6687 if ((val == NULL) || (arg == NULL) ||
6688 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6689 return(0);
6690
6691 switch(val->type) {
6692 case XPATH_NUMBER:
6693 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6694 case XPATH_NODESET:
6695 case XPATH_XSLT_TREE:
6696 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6697 case XPATH_STRING:
6698 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6699 case XPATH_BOOLEAN:
6700 valuePush(ctxt, arg);
6701 xmlXPathBooleanFunction(ctxt, 1);
6702 valuePush(ctxt, val);
6703 return(xmlXPathCompareValues(ctxt, inf, strict));
6704 default:
6705 TODO
6706 }
6707 return(0);
6708}
6709
6710/**
6711 * xmlXPathEqualNodeSetString:
6712 * @arg: the nodeset object argument
6713 * @str: the string to compare to.
6714 * @neq: flag to show whether for '=' (0) or '!=' (1)
6715 *
6716 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6717 * If one object to be compared is a node-set and the other is a string,
6718 * then the comparison will be true if and only if there is a node in
6719 * the node-set such that the result of performing the comparison on the
6720 * string-value of the node and the other string is true.
6721 *
6722 * Returns 0 or 1 depending on the results of the test.
6723 */
6724static int
6725xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6726{
6727 int i;
6728 xmlNodeSetPtr ns;
6729 xmlChar *str2;
6730 unsigned int hash;
6731
6732 if ((str == NULL) || (arg == NULL) ||
6733 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6734 return (0);
6735 ns = arg->nodesetval;
6736 /*
6737 * A NULL nodeset compared with a string is always false
6738 * (since there is no node equal, and no node not equal)
6739 */
6740 if ((ns == NULL) || (ns->nodeNr <= 0) )
6741 return (0);
6742 hash = xmlXPathStringHash(str);
6743 for (i = 0; i < ns->nodeNr; i++) {
6744 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6745 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6746 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6747 xmlFree(str2);
6748 if (neq)
6749 continue;
6750 return (1);
6751 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6752 if (neq)
6753 continue;
6754 return (1);
6755 } else if (neq) {
6756 if (str2 != NULL)
6757 xmlFree(str2);
6758 return (1);
6759 }
6760 if (str2 != NULL)
6761 xmlFree(str2);
6762 } else if (neq)
6763 return (1);
6764 }
6765 return (0);
6766}
6767
6768/**
6769 * xmlXPathEqualNodeSetFloat:
6770 * @arg: the nodeset object argument
6771 * @f: the float to compare to
6772 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6773 *
6774 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6775 * If one object to be compared is a node-set and the other is a number,
6776 * then the comparison will be true if and only if there is a node in
6777 * the node-set such that the result of performing the comparison on the
6778 * number to be compared and on the result of converting the string-value
6779 * of that node to a number using the number function is true.
6780 *
6781 * Returns 0 or 1 depending on the results of the test.
6782 */
6783static int
6784xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6785 xmlXPathObjectPtr arg, double f, int neq) {
6786 int i, ret=0;
6787 xmlNodeSetPtr ns;
6788 xmlChar *str2;
6789 xmlXPathObjectPtr val;
6790 double v;
6791
6792 if ((arg == NULL) ||
6793 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6794 return(0);
6795
6796 ns = arg->nodesetval;
6797 if (ns != NULL) {
6798 for (i=0;i<ns->nodeNr;i++) {
6799 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6800 if (str2 != NULL) {
6801 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6802 xmlFree(str2);
6803 xmlXPathNumberFunction(ctxt, 1);
6804 val = valuePop(ctxt);
6805 v = val->floatval;
6806 xmlXPathReleaseObject(ctxt->context, val);
6807 if (!xmlXPathIsNaN(v)) {
6808 if ((!neq) && (v==f)) {
6809 ret = 1;
6810 break;
6811 } else if ((neq) && (v!=f)) {
6812 ret = 1;
6813 break;
6814 }
6815 } else { /* NaN is unequal to any value */
6816 if (neq)
6817 ret = 1;
6818 }
6819 }
6820 }
6821 }
6822
6823 return(ret);
6824}
6825
6826
6827/**
6828 * xmlXPathEqualNodeSets:
6829 * @arg1: first nodeset object argument
6830 * @arg2: second nodeset object argument
6831 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6832 *
6833 * Implement the equal / not equal operation on XPath nodesets:
6834 * @arg1 == @arg2 or @arg1 != @arg2
6835 * If both objects to be compared are node-sets, then the comparison
6836 * will be true if and only if there is a node in the first node-set and
6837 * a node in the second node-set such that the result of performing the
6838 * comparison on the string-values of the two nodes is true.
6839 *
6840 * (needless to say, this is a costly operation)
6841 *
6842 * Returns 0 or 1 depending on the results of the test.
6843 */
6844static int
6845xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6846 int i, j;
6847 unsigned int *hashs1;
6848 unsigned int *hashs2;
6849 xmlChar **values1;
6850 xmlChar **values2;
6851 int ret = 0;
6852 xmlNodeSetPtr ns1;
6853 xmlNodeSetPtr ns2;
6854
6855 if ((arg1 == NULL) ||
6856 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6857 return(0);
6858 if ((arg2 == NULL) ||
6859 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6860 return(0);
6861
6862 ns1 = arg1->nodesetval;
6863 ns2 = arg2->nodesetval;
6864
6865 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6866 return(0);
6867 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6868 return(0);
6869
6870 /*
6871 * for equal, check if there is a node pertaining to both sets
6872 */
6873 if (neq == 0)
6874 for (i = 0;i < ns1->nodeNr;i++)
6875 for (j = 0;j < ns2->nodeNr;j++)
6876 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6877 return(1);
6878
6879 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6880 if (values1 == NULL) {
6881 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6882 return(0);
6883 }
6884 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6885 if (hashs1 == NULL) {
6886 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6887 xmlFree(values1);
6888 return(0);
6889 }
6890 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6891 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6892 if (values2 == NULL) {
6893 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6894 xmlFree(hashs1);
6895 xmlFree(values1);
6896 return(0);
6897 }
6898 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6899 if (hashs2 == NULL) {
6900 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6901 xmlFree(hashs1);
6902 xmlFree(values1);
6903 xmlFree(values2);
6904 return(0);
6905 }
6906 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6907 for (i = 0;i < ns1->nodeNr;i++) {
6908 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6909 for (j = 0;j < ns2->nodeNr;j++) {
6910 if (i == 0)
6911 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6912 if (hashs1[i] != hashs2[j]) {
6913 if (neq) {
6914 ret = 1;
6915 break;
6916 }
6917 }
6918 else {
6919 if (values1[i] == NULL)
6920 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6921 if (values2[j] == NULL)
6922 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6923 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6924 if (ret)
6925 break;
6926 }
6927 }
6928 if (ret)
6929 break;
6930 }
6931 for (i = 0;i < ns1->nodeNr;i++)
6932 if (values1[i] != NULL)
6933 xmlFree(values1[i]);
6934 for (j = 0;j < ns2->nodeNr;j++)
6935 if (values2[j] != NULL)
6936 xmlFree(values2[j]);
6937 xmlFree(values1);
6938 xmlFree(values2);
6939 xmlFree(hashs1);
6940 xmlFree(hashs2);
6941 return(ret);
6942}
6943
6944static int
6945xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6946 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6947 int ret = 0;
6948 /*
6949 *At this point we are assured neither arg1 nor arg2
6950 *is a nodeset, so we can just pick the appropriate routine.
6951 */
6952 switch (arg1->type) {
6953 case XPATH_UNDEFINED:
6954#ifdef DEBUG_EXPR
6955 xmlGenericError(xmlGenericErrorContext,
6956 "Equal: undefined\n");
6957#endif
6958 break;
6959 case XPATH_BOOLEAN:
6960 switch (arg2->type) {
6961 case XPATH_UNDEFINED:
6962#ifdef DEBUG_EXPR
6963 xmlGenericError(xmlGenericErrorContext,
6964 "Equal: undefined\n");
6965#endif
6966 break;
6967 case XPATH_BOOLEAN:
6968#ifdef DEBUG_EXPR
6969 xmlGenericError(xmlGenericErrorContext,
6970 "Equal: %d boolean %d \n",
6971 arg1->boolval, arg2->boolval);
6972#endif
6973 ret = (arg1->boolval == arg2->boolval);
6974 break;
6975 case XPATH_NUMBER:
6976 ret = (arg1->boolval ==
6977 xmlXPathCastNumberToBoolean(arg2->floatval));
6978 break;
6979 case XPATH_STRING:
6980 if ((arg2->stringval == NULL) ||
6981 (arg2->stringval[0] == 0)) ret = 0;
6982 else
6983 ret = 1;
6984 ret = (arg1->boolval == ret);
6985 break;
6986 case XPATH_USERS:
6987 case XPATH_POINT:
6988 case XPATH_RANGE:
6989 case XPATH_LOCATIONSET:
6990 TODO
6991 break;
6992 case XPATH_NODESET:
6993 case XPATH_XSLT_TREE:
6994 break;
6995 }
6996 break;
6997 case XPATH_NUMBER:
6998 switch (arg2->type) {
6999 case XPATH_UNDEFINED:
7000#ifdef DEBUG_EXPR
7001 xmlGenericError(xmlGenericErrorContext,
7002 "Equal: undefined\n");
7003#endif
7004 break;
7005 case XPATH_BOOLEAN:
7006 ret = (arg2->boolval==
7007 xmlXPathCastNumberToBoolean(arg1->floatval));
7008 break;
7009 case XPATH_STRING:
7010 valuePush(ctxt, arg2);
7011 xmlXPathNumberFunction(ctxt, 1);
7012 arg2 = valuePop(ctxt);
7013 /* no break on purpose */
7014 case XPATH_NUMBER:
7015 /* Hand check NaN and Infinity equalities */
7016 if (xmlXPathIsNaN(arg1->floatval) ||
7017 xmlXPathIsNaN(arg2->floatval)) {
7018 ret = 0;
7019 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7020 if (xmlXPathIsInf(arg2->floatval) == 1)
7021 ret = 1;
7022 else
7023 ret = 0;
7024 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7025 if (xmlXPathIsInf(arg2->floatval) == -1)
7026 ret = 1;
7027 else
7028 ret = 0;
7029 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7030 if (xmlXPathIsInf(arg1->floatval) == 1)
7031 ret = 1;
7032 else
7033 ret = 0;
7034 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7035 if (xmlXPathIsInf(arg1->floatval) == -1)
7036 ret = 1;
7037 else
7038 ret = 0;
7039 } else {
7040 ret = (arg1->floatval == arg2->floatval);
7041 }
7042 break;
7043 case XPATH_USERS:
7044 case XPATH_POINT:
7045 case XPATH_RANGE:
7046 case XPATH_LOCATIONSET:
7047 TODO
7048 break;
7049 case XPATH_NODESET:
7050 case XPATH_XSLT_TREE:
7051 break;
7052 }
7053 break;
7054 case XPATH_STRING:
7055 switch (arg2->type) {
7056 case XPATH_UNDEFINED:
7057#ifdef DEBUG_EXPR
7058 xmlGenericError(xmlGenericErrorContext,
7059 "Equal: undefined\n");
7060#endif
7061 break;
7062 case XPATH_BOOLEAN:
7063 if ((arg1->stringval == NULL) ||
7064 (arg1->stringval[0] == 0)) ret = 0;
7065 else
7066 ret = 1;
7067 ret = (arg2->boolval == ret);
7068 break;
7069 case XPATH_STRING:
7070 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7071 break;
7072 case XPATH_NUMBER:
7073 valuePush(ctxt, arg1);
7074 xmlXPathNumberFunction(ctxt, 1);
7075 arg1 = valuePop(ctxt);
7076 /* Hand check NaN and Infinity equalities */
7077 if (xmlXPathIsNaN(arg1->floatval) ||
7078 xmlXPathIsNaN(arg2->floatval)) {
7079 ret = 0;
7080 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7081 if (xmlXPathIsInf(arg2->floatval) == 1)
7082 ret = 1;
7083 else
7084 ret = 0;
7085 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7086 if (xmlXPathIsInf(arg2->floatval) == -1)
7087 ret = 1;
7088 else
7089 ret = 0;
7090 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7091 if (xmlXPathIsInf(arg1->floatval) == 1)
7092 ret = 1;
7093 else
7094 ret = 0;
7095 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7096 if (xmlXPathIsInf(arg1->floatval) == -1)
7097 ret = 1;
7098 else
7099 ret = 0;
7100 } else {
7101 ret = (arg1->floatval == arg2->floatval);
7102 }
7103 break;
7104 case XPATH_USERS:
7105 case XPATH_POINT:
7106 case XPATH_RANGE:
7107 case XPATH_LOCATIONSET:
7108 TODO
7109 break;
7110 case XPATH_NODESET:
7111 case XPATH_XSLT_TREE:
7112 break;
7113 }
7114 break;
7115 case XPATH_USERS:
7116 case XPATH_POINT:
7117 case XPATH_RANGE:
7118 case XPATH_LOCATIONSET:
7119 TODO
7120 break;
7121 case XPATH_NODESET:
7122 case XPATH_XSLT_TREE:
7123 break;
7124 }
7125 xmlXPathReleaseObject(ctxt->context, arg1);
7126 xmlXPathReleaseObject(ctxt->context, arg2);
7127 return(ret);
7128}
7129
7130/**
7131 * xmlXPathEqualValues:
7132 * @ctxt: the XPath Parser context
7133 *
7134 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7135 *
7136 * Returns 0 or 1 depending on the results of the test.
7137 */
7138int
7139xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7140 xmlXPathObjectPtr arg1, arg2, argtmp;
7141 int ret = 0;
7142
7143 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7144 arg2 = valuePop(ctxt);
7145 arg1 = valuePop(ctxt);
7146 if ((arg1 == NULL) || (arg2 == NULL)) {
7147 if (arg1 != NULL)
7148 xmlXPathReleaseObject(ctxt->context, arg1);
7149 else
7150 xmlXPathReleaseObject(ctxt->context, arg2);
7151 XP_ERROR0(XPATH_INVALID_OPERAND);
7152 }
7153
7154 if (arg1 == arg2) {
7155#ifdef DEBUG_EXPR
7156 xmlGenericError(xmlGenericErrorContext,
7157 "Equal: by pointer\n");
7158#endif
7159 xmlXPathFreeObject(arg1);
7160 return(1);
7161 }
7162
7163 /*
7164 *If either argument is a nodeset, it's a 'special case'
7165 */
7166 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7167 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7168 /*
7169 *Hack it to assure arg1 is the nodeset
7170 */
7171 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7172 argtmp = arg2;
7173 arg2 = arg1;
7174 arg1 = argtmp;
7175 }
7176 switch (arg2->type) {
7177 case XPATH_UNDEFINED:
7178#ifdef DEBUG_EXPR
7179 xmlGenericError(xmlGenericErrorContext,
7180 "Equal: undefined\n");
7181#endif
7182 break;
7183 case XPATH_NODESET:
7184 case XPATH_XSLT_TREE:
7185 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7186 break;
7187 case XPATH_BOOLEAN:
7188 if ((arg1->nodesetval == NULL) ||
7189 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7190 else
7191 ret = 1;
7192 ret = (ret == arg2->boolval);
7193 break;
7194 case XPATH_NUMBER:
7195 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7196 break;
7197 case XPATH_STRING:
7198 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7199 break;
7200 case XPATH_USERS:
7201 case XPATH_POINT:
7202 case XPATH_RANGE:
7203 case XPATH_LOCATIONSET:
7204 TODO
7205 break;
7206 }
7207 xmlXPathReleaseObject(ctxt->context, arg1);
7208 xmlXPathReleaseObject(ctxt->context, arg2);
7209 return(ret);
7210 }
7211
7212 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7213}
7214
7215/**
7216 * xmlXPathNotEqualValues:
7217 * @ctxt: the XPath Parser context
7218 *
7219 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7220 *
7221 * Returns 0 or 1 depending on the results of the test.
7222 */
7223int
7224xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7225 xmlXPathObjectPtr arg1, arg2, argtmp;
7226 int ret = 0;
7227
7228 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7229 arg2 = valuePop(ctxt);
7230 arg1 = valuePop(ctxt);
7231 if ((arg1 == NULL) || (arg2 == NULL)) {
7232 if (arg1 != NULL)
7233 xmlXPathReleaseObject(ctxt->context, arg1);
7234 else
7235 xmlXPathReleaseObject(ctxt->context, arg2);
7236 XP_ERROR0(XPATH_INVALID_OPERAND);
7237 }
7238
7239 if (arg1 == arg2) {
7240#ifdef DEBUG_EXPR
7241 xmlGenericError(xmlGenericErrorContext,
7242 "NotEqual: by pointer\n");
7243#endif
7244 xmlXPathReleaseObject(ctxt->context, arg1);
7245 return(0);
7246 }
7247
7248 /*
7249 *If either argument is a nodeset, it's a 'special case'
7250 */
7251 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7252 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7253 /*
7254 *Hack it to assure arg1 is the nodeset
7255 */
7256 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7257 argtmp = arg2;
7258 arg2 = arg1;
7259 arg1 = argtmp;
7260 }
7261 switch (arg2->type) {
7262 case XPATH_UNDEFINED:
7263#ifdef DEBUG_EXPR
7264 xmlGenericError(xmlGenericErrorContext,
7265 "NotEqual: undefined\n");
7266#endif
7267 break;
7268 case XPATH_NODESET:
7269 case XPATH_XSLT_TREE:
7270 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7271 break;
7272 case XPATH_BOOLEAN:
7273 if ((arg1->nodesetval == NULL) ||
7274 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7275 else
7276 ret = 1;
7277 ret = (ret != arg2->boolval);
7278 break;
7279 case XPATH_NUMBER:
7280 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7281 break;
7282 case XPATH_STRING:
7283 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7284 break;
7285 case XPATH_USERS:
7286 case XPATH_POINT:
7287 case XPATH_RANGE:
7288 case XPATH_LOCATIONSET:
7289 TODO
7290 break;
7291 }
7292 xmlXPathReleaseObject(ctxt->context, arg1);
7293 xmlXPathReleaseObject(ctxt->context, arg2);
7294 return(ret);
7295 }
7296
7297 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7298}
7299
7300/**
7301 * xmlXPathCompareValues:
7302 * @ctxt: the XPath Parser context
7303 * @inf: less than (1) or greater than (0)
7304 * @strict: is the comparison strict
7305 *
7306 * Implement the compare operation on XPath objects:
7307 * @arg1 < @arg2 (1, 1, ...
7308 * @arg1 <= @arg2 (1, 0, ...
7309 * @arg1 > @arg2 (0, 1, ...
7310 * @arg1 >= @arg2 (0, 0, ...
7311 *
7312 * When neither object to be compared is a node-set and the operator is
7313 * <=, <, >=, >, then the objects are compared by converted both objects
7314 * to numbers and comparing the numbers according to IEEE 754. The <
7315 * comparison will be true if and only if the first number is less than the
7316 * second number. The <= comparison will be true if and only if the first
7317 * number is less than or equal to the second number. The > comparison
7318 * will be true if and only if the first number is greater than the second
7319 * number. The >= comparison will be true if and only if the first number
7320 * is greater than or equal to the second number.
7321 *
7322 * Returns 1 if the comparison succeeded, 0 if it failed
7323 */
7324int
7325xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7326 int ret = 0, arg1i = 0, arg2i = 0;
7327 xmlXPathObjectPtr arg1, arg2;
7328
7329 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7330 arg2 = valuePop(ctxt);
7331 arg1 = valuePop(ctxt);
7332 if ((arg1 == NULL) || (arg2 == NULL)) {
7333 if (arg1 != NULL)
7334 xmlXPathReleaseObject(ctxt->context, arg1);
7335 else
7336 xmlXPathReleaseObject(ctxt->context, arg2);
7337 XP_ERROR0(XPATH_INVALID_OPERAND);
7338 }
7339
7340 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7341 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7342 /*
7343 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7344 * are not freed from within this routine; they will be freed from the
7345 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7346 */
7347 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7348 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7349 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7350 } else {
7351 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7352 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7353 arg1, arg2);
7354 } else {
7355 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7356 arg2, arg1);
7357 }
7358 }
7359 return(ret);
7360 }
7361
7362 if (arg1->type != XPATH_NUMBER) {
7363 valuePush(ctxt, arg1);
7364 xmlXPathNumberFunction(ctxt, 1);
7365 arg1 = valuePop(ctxt);
7366 }
7367 if (arg1->type != XPATH_NUMBER) {
7368 xmlXPathFreeObject(arg1);
7369 xmlXPathFreeObject(arg2);
7370 XP_ERROR0(XPATH_INVALID_OPERAND);
7371 }
7372 if (arg2->type != XPATH_NUMBER) {
7373 valuePush(ctxt, arg2);
7374 xmlXPathNumberFunction(ctxt, 1);
7375 arg2 = valuePop(ctxt);
7376 }
7377 if (arg2->type != XPATH_NUMBER) {
7378 xmlXPathReleaseObject(ctxt->context, arg1);
7379 xmlXPathReleaseObject(ctxt->context, arg2);
7380 XP_ERROR0(XPATH_INVALID_OPERAND);
7381 }
7382 /*
7383 * Add tests for infinity and nan
7384 * => feedback on 3.4 for Inf and NaN
7385 */
7386 /* Hand check NaN and Infinity comparisons */
7387 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7388 ret=0;
7389 } else {
7390 arg1i=xmlXPathIsInf(arg1->floatval);
7391 arg2i=xmlXPathIsInf(arg2->floatval);
7392 if (inf && strict) {
7393 if ((arg1i == -1 && arg2i != -1) ||
7394 (arg2i == 1 && arg1i != 1)) {
7395 ret = 1;
7396 } else if (arg1i == 0 && arg2i == 0) {
7397 ret = (arg1->floatval < arg2->floatval);
7398 } else {
7399 ret = 0;
7400 }
7401 }
7402 else if (inf && !strict) {
7403 if (arg1i == -1 || arg2i == 1) {
7404 ret = 1;
7405 } else if (arg1i == 0 && arg2i == 0) {
7406 ret = (arg1->floatval <= arg2->floatval);
7407 } else {
7408 ret = 0;
7409 }
7410 }
7411 else if (!inf && strict) {
7412 if ((arg1i == 1 && arg2i != 1) ||
7413 (arg2i == -1 && arg1i != -1)) {
7414 ret = 1;
7415 } else if (arg1i == 0 && arg2i == 0) {
7416 ret = (arg1->floatval > arg2->floatval);
7417 } else {
7418 ret = 0;
7419 }
7420 }
7421 else if (!inf && !strict) {
7422 if (arg1i == 1 || arg2i == -1) {
7423 ret = 1;
7424 } else if (arg1i == 0 && arg2i == 0) {
7425 ret = (arg1->floatval >= arg2->floatval);
7426 } else {
7427 ret = 0;
7428 }
7429 }
7430 }
7431 xmlXPathReleaseObject(ctxt->context, arg1);
7432 xmlXPathReleaseObject(ctxt->context, arg2);
7433 return(ret);
7434}
7435
7436/**
7437 * xmlXPathValueFlipSign:
7438 * @ctxt: the XPath Parser context
7439 *
7440 * Implement the unary - operation on an XPath object
7441 * The numeric operators convert their operands to numbers as if
7442 * by calling the number function.
7443 */
7444void
7445xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7446 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7447 CAST_TO_NUMBER;
7448 CHECK_TYPE(XPATH_NUMBER);
7449 if (xmlXPathIsNaN(ctxt->value->floatval))
7450 ctxt->value->floatval=xmlXPathNAN;
7451 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7452 ctxt->value->floatval=xmlXPathNINF;
7453 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7454 ctxt->value->floatval=xmlXPathPINF;
7455 else if (ctxt->value->floatval == 0) {
7456 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7457 ctxt->value->floatval = xmlXPathNZERO;
7458 else
7459 ctxt->value->floatval = 0;
7460 }
7461 else
7462 ctxt->value->floatval = - ctxt->value->floatval;
7463}
7464
7465/**
7466 * xmlXPathAddValues:
7467 * @ctxt: the XPath Parser context
7468 *
7469 * Implement the add operation on XPath objects:
7470 * The numeric operators convert their operands to numbers as if
7471 * by calling the number function.
7472 */
7473void
7474xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7475 xmlXPathObjectPtr arg;
7476 double val;
7477
7478 arg = valuePop(ctxt);
7479 if (arg == NULL)
7480 XP_ERROR(XPATH_INVALID_OPERAND);
7481 val = xmlXPathCastToNumber(arg);
7482 xmlXPathReleaseObject(ctxt->context, arg);
7483 CAST_TO_NUMBER;
7484 CHECK_TYPE(XPATH_NUMBER);
7485 ctxt->value->floatval += val;
7486}
7487
7488/**
7489 * xmlXPathSubValues:
7490 * @ctxt: the XPath Parser context
7491 *
7492 * Implement the subtraction operation on XPath objects:
7493 * The numeric operators convert their operands to numbers as if
7494 * by calling the number function.
7495 */
7496void
7497xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7498 xmlXPathObjectPtr arg;
7499 double val;
7500
7501 arg = valuePop(ctxt);
7502 if (arg == NULL)
7503 XP_ERROR(XPATH_INVALID_OPERAND);
7504 val = xmlXPathCastToNumber(arg);
7505 xmlXPathReleaseObject(ctxt->context, arg);
7506 CAST_TO_NUMBER;
7507 CHECK_TYPE(XPATH_NUMBER);
7508 ctxt->value->floatval -= val;
7509}
7510
7511/**
7512 * xmlXPathMultValues:
7513 * @ctxt: the XPath Parser context
7514 *
7515 * Implement the multiply operation on XPath objects:
7516 * The numeric operators convert their operands to numbers as if
7517 * by calling the number function.
7518 */
7519void
7520xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7521 xmlXPathObjectPtr arg;
7522 double val;
7523
7524 arg = valuePop(ctxt);
7525 if (arg == NULL)
7526 XP_ERROR(XPATH_INVALID_OPERAND);
7527 val = xmlXPathCastToNumber(arg);
7528 xmlXPathReleaseObject(ctxt->context, arg);
7529 CAST_TO_NUMBER;
7530 CHECK_TYPE(XPATH_NUMBER);
7531 ctxt->value->floatval *= val;
7532}
7533
7534/**
7535 * xmlXPathDivValues:
7536 * @ctxt: the XPath Parser context
7537 *
7538 * Implement the div operation on XPath objects @arg1 / @arg2:
7539 * The numeric operators convert their operands to numbers as if
7540 * by calling the number function.
7541 */
7542void
7543xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7544 xmlXPathObjectPtr arg;
7545 double val;
7546
7547 arg = valuePop(ctxt);
7548 if (arg == NULL)
7549 XP_ERROR(XPATH_INVALID_OPERAND);
7550 val = xmlXPathCastToNumber(arg);
7551 xmlXPathReleaseObject(ctxt->context, arg);
7552 CAST_TO_NUMBER;
7553 CHECK_TYPE(XPATH_NUMBER);
7554 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7555 ctxt->value->floatval = xmlXPathNAN;
7556 else if (val == 0 && xmlXPathGetSign(val) != 0) {
7557 if (ctxt->value->floatval == 0)
7558 ctxt->value->floatval = xmlXPathNAN;
7559 else if (ctxt->value->floatval > 0)
7560 ctxt->value->floatval = xmlXPathNINF;
7561 else if (ctxt->value->floatval < 0)
7562 ctxt->value->floatval = xmlXPathPINF;
7563 }
7564 else if (val == 0) {
7565 if (ctxt->value->floatval == 0)
7566 ctxt->value->floatval = xmlXPathNAN;
7567 else if (ctxt->value->floatval > 0)
7568 ctxt->value->floatval = xmlXPathPINF;
7569 else if (ctxt->value->floatval < 0)
7570 ctxt->value->floatval = xmlXPathNINF;
7571 } else
7572 ctxt->value->floatval /= val;
7573}
7574
7575/**
7576 * xmlXPathModValues:
7577 * @ctxt: the XPath Parser context
7578 *
7579 * Implement the mod operation on XPath objects: @arg1 / @arg2
7580 * The numeric operators convert their operands to numbers as if
7581 * by calling the number function.
7582 */
7583void
7584xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7585 xmlXPathObjectPtr arg;
7586 double arg1, arg2;
7587
7588 arg = valuePop(ctxt);
7589 if (arg == NULL)
7590 XP_ERROR(XPATH_INVALID_OPERAND);
7591 arg2 = xmlXPathCastToNumber(arg);
7592 xmlXPathReleaseObject(ctxt->context, arg);
7593 CAST_TO_NUMBER;
7594 CHECK_TYPE(XPATH_NUMBER);
7595 arg1 = ctxt->value->floatval;
7596 if (arg2 == 0)
7597 ctxt->value->floatval = xmlXPathNAN;
7598 else {
7599 ctxt->value->floatval = fmod(arg1, arg2);
7600 }
7601}
7602
7603/************************************************************************
7604 * *
7605 * The traversal functions *
7606 * *
7607 ************************************************************************/
7608
7609/*
7610 * A traversal function enumerates nodes along an axis.
7611 * Initially it must be called with NULL, and it indicates
7612 * termination on the axis by returning NULL.
7613 */
7614typedef xmlNodePtr (*xmlXPathTraversalFunction)
7615 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7616
7617/*
7618 * xmlXPathTraversalFunctionExt:
7619 * A traversal function enumerates nodes along an axis.
7620 * Initially it must be called with NULL, and it indicates
7621 * termination on the axis by returning NULL.
7622 * The context node of the traversal is specified via @contextNode.
7623 */
7624typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7625 (xmlNodePtr cur, xmlNodePtr contextNode);
7626
7627/*
7628 * xmlXPathNodeSetMergeFunction:
7629 * Used for merging node sets in xmlXPathCollectAndTest().
7630 */
7631typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7632 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7633
7634
7635/**
7636 * xmlXPathNextSelf:
7637 * @ctxt: the XPath Parser context
7638 * @cur: the current node in the traversal
7639 *
7640 * Traversal function for the "self" direction
7641 * The self axis contains just the context node itself
7642 *
7643 * Returns the next element following that axis
7644 */
7645xmlNodePtr
7646xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7647 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7648 if (cur == NULL)
7649 return(ctxt->context->node);
7650 return(NULL);
7651}
7652
7653/**
7654 * xmlXPathNextChild:
7655 * @ctxt: the XPath Parser context
7656 * @cur: the current node in the traversal
7657 *
7658 * Traversal function for the "child" direction
7659 * The child axis contains the children of the context node in document order.
7660 *
7661 * Returns the next element following that axis
7662 */
7663xmlNodePtr
7664xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7665 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7666 if (cur == NULL) {
7667 if (ctxt->context->node == NULL) return(NULL);
7668 switch (ctxt->context->node->type) {
7669 case XML_ELEMENT_NODE:
7670 case XML_TEXT_NODE:
7671 case XML_CDATA_SECTION_NODE:
7672 case XML_ENTITY_REF_NODE:
7673 case XML_ENTITY_NODE:
7674 case XML_PI_NODE:
7675 case XML_COMMENT_NODE:
7676 case XML_NOTATION_NODE:
7677 case XML_DTD_NODE:
7678 return(ctxt->context->node->children);
7679 case XML_DOCUMENT_NODE:
7680 case XML_DOCUMENT_TYPE_NODE:
7681 case XML_DOCUMENT_FRAG_NODE:
7682 case XML_HTML_DOCUMENT_NODE:
7683#ifdef LIBXML_DOCB_ENABLED
7684 case XML_DOCB_DOCUMENT_NODE:
7685#endif
7686 return(((xmlDocPtr) ctxt->context->node)->children);
7687 case XML_ELEMENT_DECL:
7688 case XML_ATTRIBUTE_DECL:
7689 case XML_ENTITY_DECL:
7690 case XML_ATTRIBUTE_NODE:
7691 case XML_NAMESPACE_DECL:
7692 case XML_XINCLUDE_START:
7693 case XML_XINCLUDE_END:
7694 return(NULL);
7695 }
7696 return(NULL);
7697 }
7698 if ((cur->type == XML_DOCUMENT_NODE) ||
7699 (cur->type == XML_HTML_DOCUMENT_NODE))
7700 return(NULL);
7701 return(cur->next);
7702}
7703
7704/**
7705 * xmlXPathNextChildElement:
7706 * @ctxt: the XPath Parser context
7707 * @cur: the current node in the traversal
7708 *
7709 * Traversal function for the "child" direction and nodes of type element.
7710 * The child axis contains the children of the context node in document order.
7711 *
7712 * Returns the next element following that axis
7713 */
7714static xmlNodePtr
7715xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7716 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7717 if (cur == NULL) {
7718 cur = ctxt->context->node;
7719 if (cur == NULL) return(NULL);
7720 /*
7721 * Get the first element child.
7722 */
7723 switch (cur->type) {
7724 case XML_ELEMENT_NODE:
7725 case XML_DOCUMENT_FRAG_NODE:
7726 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7727 case XML_ENTITY_NODE:
7728 cur = cur->children;
7729 if (cur != NULL) {
7730 if (cur->type == XML_ELEMENT_NODE)
7731 return(cur);
7732 do {
7733 cur = cur->next;
7734 } while ((cur != NULL) &&
7735 (cur->type != XML_ELEMENT_NODE));
7736 return(cur);
7737 }
7738 return(NULL);
7739 case XML_DOCUMENT_NODE:
7740 case XML_HTML_DOCUMENT_NODE:
7741#ifdef LIBXML_DOCB_ENABLED
7742 case XML_DOCB_DOCUMENT_NODE:
7743#endif
7744 return(xmlDocGetRootElement((xmlDocPtr) cur));
7745 default:
7746 return(NULL);
7747 }
7748 return(NULL);
7749 }
7750 /*
7751 * Get the next sibling element node.
7752 */
7753 switch (cur->type) {
7754 case XML_ELEMENT_NODE:
7755 case XML_TEXT_NODE:
7756 case XML_ENTITY_REF_NODE:
7757 case XML_ENTITY_NODE:
7758 case XML_CDATA_SECTION_NODE:
7759 case XML_PI_NODE:
7760 case XML_COMMENT_NODE:
7761 case XML_XINCLUDE_END:
7762 break;
7763 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7764 default:
7765 return(NULL);
7766 }
7767 if (cur->next != NULL) {
7768 if (cur->next->type == XML_ELEMENT_NODE)
7769 return(cur->next);
7770 cur = cur->next;
7771 do {
7772 cur = cur->next;
7773 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7774 return(cur);
7775 }
7776 return(NULL);
7777}
7778
7779#if 0
7780/**
7781 * xmlXPathNextDescendantOrSelfElemParent:
7782 * @ctxt: the XPath Parser context
7783 * @cur: the current node in the traversal
7784 *
7785 * Traversal function for the "descendant-or-self" axis.
7786 * Additionally it returns only nodes which can be parents of
7787 * element nodes.
7788 *
7789 *
7790 * Returns the next element following that axis
7791 */
7792static xmlNodePtr
7793xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7794 xmlNodePtr contextNode)
7795{
7796 if (cur == NULL) {
7797 if (contextNode == NULL)
7798 return(NULL);
7799 switch (contextNode->type) {
7800 case XML_ELEMENT_NODE:
7801 case XML_XINCLUDE_START:
7802 case XML_DOCUMENT_FRAG_NODE:
7803 case XML_DOCUMENT_NODE:
7804#ifdef LIBXML_DOCB_ENABLED
7805 case XML_DOCB_DOCUMENT_NODE:
7806#endif
7807 case XML_HTML_DOCUMENT_NODE:
7808 return(contextNode);
7809 default:
7810 return(NULL);
7811 }
7812 return(NULL);
7813 } else {
7814 xmlNodePtr start = cur;
7815
7816 while (cur != NULL) {
7817 switch (cur->type) {
7818 case XML_ELEMENT_NODE:
7819 /* TODO: OK to have XInclude here? */
7820 case XML_XINCLUDE_START:
7821 case XML_DOCUMENT_FRAG_NODE:
7822 if (cur != start)
7823 return(cur);
7824 if (cur->children != NULL) {
7825 cur = cur->children;
7826 continue;
7827 }
7828 break;
7829 /* Not sure if we need those here. */
7830 case XML_DOCUMENT_NODE:
7831#ifdef LIBXML_DOCB_ENABLED
7832 case XML_DOCB_DOCUMENT_NODE:
7833#endif
7834 case XML_HTML_DOCUMENT_NODE:
7835 if (cur != start)
7836 return(cur);
7837 return(xmlDocGetRootElement((xmlDocPtr) cur));
7838 default:
7839 break;
7840 }
7841
7842next_sibling:
7843 if ((cur == NULL) || (cur == contextNode))
7844 return(NULL);
7845 if (cur->next != NULL) {
7846 cur = cur->next;
7847 } else {
7848 cur = cur->parent;
7849 goto next_sibling;
7850 }
7851 }
7852 }
7853 return(NULL);
7854}
7855#endif
7856
7857/**
7858 * xmlXPathNextDescendant:
7859 * @ctxt: the XPath Parser context
7860 * @cur: the current node in the traversal
7861 *
7862 * Traversal function for the "descendant" direction
7863 * the descendant axis contains the descendants of the context node in document
7864 * order; a descendant is a child or a child of a child and so on.
7865 *
7866 * Returns the next element following that axis
7867 */
7868xmlNodePtr
7869xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7870 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7871 if (cur == NULL) {
7872 if (ctxt->context->node == NULL)
7873 return(NULL);
7874 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7875 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7876 return(NULL);
7877
7878 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7879 return(ctxt->context->doc->children);
7880 return(ctxt->context->node->children);
7881 }
7882
7883 if (cur->type == XML_NAMESPACE_DECL)
7884 return(NULL);
7885 if (cur->children != NULL) {
7886 /*
7887 * Do not descend on entities declarations
7888 */
7889 if (cur->children->type != XML_ENTITY_DECL) {
7890 cur = cur->children;
7891 /*
7892 * Skip DTDs
7893 */
7894 if (cur->type != XML_DTD_NODE)
7895 return(cur);
7896 }
7897 }
7898
7899 if (cur == ctxt->context->node) return(NULL);
7900
7901 while (cur->next != NULL) {
7902 cur = cur->next;
7903 if ((cur->type != XML_ENTITY_DECL) &&
7904 (cur->type != XML_DTD_NODE))
7905 return(cur);
7906 }
7907
7908 do {
7909 cur = cur->parent;
7910 if (cur == NULL) break;
7911 if (cur == ctxt->context->node) return(NULL);
7912 if (cur->next != NULL) {
7913 cur = cur->next;
7914 return(cur);
7915 }
7916 } while (cur != NULL);
7917 return(cur);
7918}
7919
7920/**
7921 * xmlXPathNextDescendantOrSelf:
7922 * @ctxt: the XPath Parser context
7923 * @cur: the current node in the traversal
7924 *
7925 * Traversal function for the "descendant-or-self" direction
7926 * the descendant-or-self axis contains the context node and the descendants
7927 * of the context node in document order; thus the context node is the first
7928 * node on the axis, and the first child of the context node is the second node
7929 * on the axis
7930 *
7931 * Returns the next element following that axis
7932 */
7933xmlNodePtr
7934xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7935 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7936 if (cur == NULL) {
7937 if (ctxt->context->node == NULL)
7938 return(NULL);
7939 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7940 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7941 return(NULL);
7942 return(ctxt->context->node);
7943 }
7944
7945 return(xmlXPathNextDescendant(ctxt, cur));
7946}
7947
7948/**
7949 * xmlXPathNextParent:
7950 * @ctxt: the XPath Parser context
7951 * @cur: the current node in the traversal
7952 *
7953 * Traversal function for the "parent" direction
7954 * The parent axis contains the parent of the context node, if there is one.
7955 *
7956 * Returns the next element following that axis
7957 */
7958xmlNodePtr
7959xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7960 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7961 /*
7962 * the parent of an attribute or namespace node is the element
7963 * to which the attribute or namespace node is attached
7964 * Namespace handling !!!
7965 */
7966 if (cur == NULL) {
7967 if (ctxt->context->node == NULL) return(NULL);
7968 switch (ctxt->context->node->type) {
7969 case XML_ELEMENT_NODE:
7970 case XML_TEXT_NODE:
7971 case XML_CDATA_SECTION_NODE:
7972 case XML_ENTITY_REF_NODE:
7973 case XML_ENTITY_NODE:
7974 case XML_PI_NODE:
7975 case XML_COMMENT_NODE:
7976 case XML_NOTATION_NODE:
7977 case XML_DTD_NODE:
7978 case XML_ELEMENT_DECL:
7979 case XML_ATTRIBUTE_DECL:
7980 case XML_XINCLUDE_START:
7981 case XML_XINCLUDE_END:
7982 case XML_ENTITY_DECL:
7983 if (ctxt->context->node->parent == NULL)
7984 return((xmlNodePtr) ctxt->context->doc);
7985 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7986 ((ctxt->context->node->parent->name[0] == ' ') ||
7987 (xmlStrEqual(ctxt->context->node->parent->name,
7988 BAD_CAST "fake node libxslt"))))
7989 return(NULL);
7990 return(ctxt->context->node->parent);
7991 case XML_ATTRIBUTE_NODE: {
7992 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7993
7994 return(att->parent);
7995 }
7996 case XML_DOCUMENT_NODE:
7997 case XML_DOCUMENT_TYPE_NODE:
7998 case XML_DOCUMENT_FRAG_NODE:
7999 case XML_HTML_DOCUMENT_NODE:
8000#ifdef LIBXML_DOCB_ENABLED
8001 case XML_DOCB_DOCUMENT_NODE:
8002#endif
8003 return(NULL);
8004 case XML_NAMESPACE_DECL: {
8005 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8006
8007 if ((ns->next != NULL) &&
8008 (ns->next->type != XML_NAMESPACE_DECL))
8009 return((xmlNodePtr) ns->next);
8010 return(NULL);
8011 }
8012 }
8013 }
8014 return(NULL);
8015}
8016
8017/**
8018 * xmlXPathNextAncestor:
8019 * @ctxt: the XPath Parser context
8020 * @cur: the current node in the traversal
8021 *
8022 * Traversal function for the "ancestor" direction
8023 * the ancestor axis contains the ancestors of the context node; the ancestors
8024 * of the context node consist of the parent of context node and the parent's
8025 * parent and so on; the nodes are ordered in reverse document order; thus the
8026 * parent is the first node on the axis, and the parent's parent is the second
8027 * node on the axis
8028 *
8029 * Returns the next element following that axis
8030 */
8031xmlNodePtr
8032xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8033 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8034 /*
8035 * the parent of an attribute or namespace node is the element
8036 * to which the attribute or namespace node is attached
8037 * !!!!!!!!!!!!!
8038 */
8039 if (cur == NULL) {
8040 if (ctxt->context->node == NULL) return(NULL);
8041 switch (ctxt->context->node->type) {
8042 case XML_ELEMENT_NODE:
8043 case XML_TEXT_NODE:
8044 case XML_CDATA_SECTION_NODE:
8045 case XML_ENTITY_REF_NODE:
8046 case XML_ENTITY_NODE:
8047 case XML_PI_NODE:
8048 case XML_COMMENT_NODE:
8049 case XML_DTD_NODE:
8050 case XML_ELEMENT_DECL:
8051 case XML_ATTRIBUTE_DECL:
8052 case XML_ENTITY_DECL:
8053 case XML_NOTATION_NODE:
8054 case XML_XINCLUDE_START:
8055 case XML_XINCLUDE_END:
8056 if (ctxt->context->node->parent == NULL)
8057 return((xmlNodePtr) ctxt->context->doc);
8058 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8059 ((ctxt->context->node->parent->name[0] == ' ') ||
8060 (xmlStrEqual(ctxt->context->node->parent->name,
8061 BAD_CAST "fake node libxslt"))))
8062 return(NULL);
8063 return(ctxt->context->node->parent);
8064 case XML_ATTRIBUTE_NODE: {
8065 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8066
8067 return(tmp->parent);
8068 }
8069 case XML_DOCUMENT_NODE:
8070 case XML_DOCUMENT_TYPE_NODE:
8071 case XML_DOCUMENT_FRAG_NODE:
8072 case XML_HTML_DOCUMENT_NODE:
8073#ifdef LIBXML_DOCB_ENABLED
8074 case XML_DOCB_DOCUMENT_NODE:
8075#endif
8076 return(NULL);
8077 case XML_NAMESPACE_DECL: {
8078 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8079
8080 if ((ns->next != NULL) &&
8081 (ns->next->type != XML_NAMESPACE_DECL))
8082 return((xmlNodePtr) ns->next);
8083 /* Bad, how did that namespace end up here ? */
8084 return(NULL);
8085 }
8086 }
8087 return(NULL);
8088 }
8089 if (cur == ctxt->context->doc->children)
8090 return((xmlNodePtr) ctxt->context->doc);
8091 if (cur == (xmlNodePtr) ctxt->context->doc)
8092 return(NULL);
8093 switch (cur->type) {
8094 case XML_ELEMENT_NODE:
8095 case XML_TEXT_NODE:
8096 case XML_CDATA_SECTION_NODE:
8097 case XML_ENTITY_REF_NODE:
8098 case XML_ENTITY_NODE:
8099 case XML_PI_NODE:
8100 case XML_COMMENT_NODE:
8101 case XML_NOTATION_NODE:
8102 case XML_DTD_NODE:
8103 case XML_ELEMENT_DECL:
8104 case XML_ATTRIBUTE_DECL:
8105 case XML_ENTITY_DECL:
8106 case XML_XINCLUDE_START:
8107 case XML_XINCLUDE_END:
8108 if (cur->parent == NULL)
8109 return(NULL);
8110 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8111 ((cur->parent->name[0] == ' ') ||
8112 (xmlStrEqual(cur->parent->name,
8113 BAD_CAST "fake node libxslt"))))
8114 return(NULL);
8115 return(cur->parent);
8116 case XML_ATTRIBUTE_NODE: {
8117 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8118
8119 return(att->parent);
8120 }
8121 case XML_NAMESPACE_DECL: {
8122 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8123
8124 if ((ns->next != NULL) &&
8125 (ns->next->type != XML_NAMESPACE_DECL))
8126 return((xmlNodePtr) ns->next);
8127 /* Bad, how did that namespace end up here ? */
8128 return(NULL);
8129 }
8130 case XML_DOCUMENT_NODE:
8131 case XML_DOCUMENT_TYPE_NODE:
8132 case XML_DOCUMENT_FRAG_NODE:
8133 case XML_HTML_DOCUMENT_NODE:
8134#ifdef LIBXML_DOCB_ENABLED
8135 case XML_DOCB_DOCUMENT_NODE:
8136#endif
8137 return(NULL);
8138 }
8139 return(NULL);
8140}
8141
8142/**
8143 * xmlXPathNextAncestorOrSelf:
8144 * @ctxt: the XPath Parser context
8145 * @cur: the current node in the traversal
8146 *
8147 * Traversal function for the "ancestor-or-self" direction
8148 * he ancestor-or-self axis contains the context node and ancestors of
8149 * the context node in reverse document order; thus the context node is
8150 * the first node on the axis, and the context node's parent the second;
8151 * parent here is defined the same as with the parent axis.
8152 *
8153 * Returns the next element following that axis
8154 */
8155xmlNodePtr
8156xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8157 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8158 if (cur == NULL)
8159 return(ctxt->context->node);
8160 return(xmlXPathNextAncestor(ctxt, cur));
8161}
8162
8163/**
8164 * xmlXPathNextFollowingSibling:
8165 * @ctxt: the XPath Parser context
8166 * @cur: the current node in the traversal
8167 *
8168 * Traversal function for the "following-sibling" direction
8169 * The following-sibling axis contains the following siblings of the context
8170 * node in document order.
8171 *
8172 * Returns the next element following that axis
8173 */
8174xmlNodePtr
8175xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8176 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8177 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8178 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8179 return(NULL);
8180 if (cur == (xmlNodePtr) ctxt->context->doc)
8181 return(NULL);
8182 if (cur == NULL)
8183 return(ctxt->context->node->next);
8184 return(cur->next);
8185}
8186
8187/**
8188 * xmlXPathNextPrecedingSibling:
8189 * @ctxt: the XPath Parser context
8190 * @cur: the current node in the traversal
8191 *
8192 * Traversal function for the "preceding-sibling" direction
8193 * The preceding-sibling axis contains the preceding siblings of the context
8194 * node in reverse document order; the first preceding sibling is first on the
8195 * axis; the sibling preceding that node is the second on the axis and so on.
8196 *
8197 * Returns the next element following that axis
8198 */
8199xmlNodePtr
8200xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8201 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8202 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8203 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8204 return(NULL);
8205 if (cur == (xmlNodePtr) ctxt->context->doc)
8206 return(NULL);
8207 if (cur == NULL)
8208 return(ctxt->context->node->prev);
8209 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8210 cur = cur->prev;
8211 if (cur == NULL)
8212 return(ctxt->context->node->prev);
8213 }
8214 return(cur->prev);
8215}
8216
8217/**
8218 * xmlXPathNextFollowing:
8219 * @ctxt: the XPath Parser context
8220 * @cur: the current node in the traversal
8221 *
8222 * Traversal function for the "following" direction
8223 * The following axis contains all nodes in the same document as the context
8224 * node that are after the context node in document order, excluding any
8225 * descendants and excluding attribute nodes and namespace nodes; the nodes
8226 * are ordered in document order
8227 *
8228 * Returns the next element following that axis
8229 */
8230xmlNodePtr
8231xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8232 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8233 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8234 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8235 return(cur->children);
8236
8237 if (cur == NULL) {
8238 cur = ctxt->context->node;
8239 if (cur->type == XML_NAMESPACE_DECL)
8240 return(NULL);
8241 if (cur->type == XML_ATTRIBUTE_NODE)
8242 cur = cur->parent;
8243 }
8244 if (cur == NULL) return(NULL) ; /* ERROR */
8245 if (cur->next != NULL) return(cur->next) ;
8246 do {
8247 cur = cur->parent;
8248 if (cur == NULL) break;
8249 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8250 if (cur->next != NULL) return(cur->next);
8251 } while (cur != NULL);
8252 return(cur);
8253}
8254
8255/*
8256 * xmlXPathIsAncestor:
8257 * @ancestor: the ancestor node
8258 * @node: the current node
8259 *
8260 * Check that @ancestor is a @node's ancestor
8261 *
8262 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8263 */
8264static int
8265xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8266 if ((ancestor == NULL) || (node == NULL)) return(0);
8267 if (node->type == XML_NAMESPACE_DECL)
8268 return(0);
8269 if (ancestor->type == XML_NAMESPACE_DECL)
8270 return(0);
8271 /* nodes need to be in the same document */
8272 if (ancestor->doc != node->doc) return(0);
8273 /* avoid searching if ancestor or node is the root node */
8274 if (ancestor == (xmlNodePtr) node->doc) return(1);
8275 if (node == (xmlNodePtr) ancestor->doc) return(0);
8276 while (node->parent != NULL) {
8277 if (node->parent == ancestor)
8278 return(1);
8279 node = node->parent;
8280 }
8281 return(0);
8282}
8283
8284/**
8285 * xmlXPathNextPreceding:
8286 * @ctxt: the XPath Parser context
8287 * @cur: the current node in the traversal
8288 *
8289 * Traversal function for the "preceding" direction
8290 * the preceding axis contains all nodes in the same document as the context
8291 * node that are before the context node in document order, excluding any
8292 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8293 * ordered in reverse document order
8294 *
8295 * Returns the next element following that axis
8296 */
8297xmlNodePtr
8298xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8299{
8300 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8301 if (cur == NULL) {
8302 cur = ctxt->context->node;
8303 if (cur->type == XML_NAMESPACE_DECL)
8304 return(NULL);
8305 if (cur->type == XML_ATTRIBUTE_NODE)
8306 return(cur->parent);
8307 }
8308 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8309 return (NULL);
8310 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8311 cur = cur->prev;
8312 do {
8313 if (cur->prev != NULL) {
8314 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8315 return (cur);
8316 }
8317
8318 cur = cur->parent;
8319 if (cur == NULL)
8320 return (NULL);
8321 if (cur == ctxt->context->doc->children)
8322 return (NULL);
8323 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8324 return (cur);
8325}
8326
8327/**
8328 * xmlXPathNextPrecedingInternal:
8329 * @ctxt: the XPath Parser context
8330 * @cur: the current node in the traversal
8331 *
8332 * Traversal function for the "preceding" direction
8333 * the preceding axis contains all nodes in the same document as the context
8334 * node that are before the context node in document order, excluding any
8335 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8336 * ordered in reverse document order
8337 * This is a faster implementation but internal only since it requires a
8338 * state kept in the parser context: ctxt->ancestor.
8339 *
8340 * Returns the next element following that axis
8341 */
8342static xmlNodePtr
8343xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8344 xmlNodePtr cur)
8345{
8346 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8347 if (cur == NULL) {
8348 cur = ctxt->context->node;
8349 if (cur == NULL)
8350 return (NULL);
8351 if (cur->type == XML_NAMESPACE_DECL)
8352 return (NULL);
8353 ctxt->ancestor = cur->parent;
8354 }
8355 if (cur->type == XML_NAMESPACE_DECL)
8356 return(NULL);
8357 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8358 cur = cur->prev;
8359 while (cur->prev == NULL) {
8360 cur = cur->parent;
8361 if (cur == NULL)
8362 return (NULL);
8363 if (cur == ctxt->context->doc->children)
8364 return (NULL);
8365 if (cur != ctxt->ancestor)
8366 return (cur);
8367 ctxt->ancestor = cur->parent;
8368 }
8369 cur = cur->prev;
8370 while (cur->last != NULL)
8371 cur = cur->last;
8372 return (cur);
8373}
8374
8375/**
8376 * xmlXPathNextNamespace:
8377 * @ctxt: the XPath Parser context
8378 * @cur: the current attribute in the traversal
8379 *
8380 * Traversal function for the "namespace" direction
8381 * the namespace axis contains the namespace nodes of the context node;
8382 * the order of nodes on this axis is implementation-defined; the axis will
8383 * be empty unless the context node is an element
8384 *
8385 * We keep the XML namespace node at the end of the list.
8386 *
8387 * Returns the next element following that axis
8388 */
8389xmlNodePtr
8390xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8391 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8392 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8393 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8394 if (ctxt->context->tmpNsList != NULL)
8395 xmlFree(ctxt->context->tmpNsList);
8396 ctxt->context->tmpNsList =
8397 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8398 ctxt->context->tmpNsNr = 0;
8399 if (ctxt->context->tmpNsList != NULL) {
8400 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8401 ctxt->context->tmpNsNr++;
8402 }
8403 }
8404 return((xmlNodePtr) xmlXPathXMLNamespace);
8405 }
8406 if (ctxt->context->tmpNsNr > 0) {
8407 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8408 } else {
8409 if (ctxt->context->tmpNsList != NULL)
8410 xmlFree(ctxt->context->tmpNsList);
8411 ctxt->context->tmpNsList = NULL;
8412 return(NULL);
8413 }
8414}
8415
8416/**
8417 * xmlXPathNextAttribute:
8418 * @ctxt: the XPath Parser context
8419 * @cur: the current attribute in the traversal
8420 *
8421 * Traversal function for the "attribute" direction
8422 * TODO: support DTD inherited default attributes
8423 *
8424 * Returns the next element following that axis
8425 */
8426xmlNodePtr
8427xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8428 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8429 if (ctxt->context->node == NULL)
8430 return(NULL);
8431 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8432 return(NULL);
8433 if (cur == NULL) {
8434 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8435 return(NULL);
8436 return((xmlNodePtr)ctxt->context->node->properties);
8437 }
8438 return((xmlNodePtr)cur->next);
8439}
8440
8441/************************************************************************
8442 * *
8443 * NodeTest Functions *
8444 * *
8445 ************************************************************************/
8446
8447#define IS_FUNCTION 200
8448
8449
8450/************************************************************************
8451 * *
8452 * Implicit tree core function library *
8453 * *
8454 ************************************************************************/
8455
8456/**
8457 * xmlXPathRoot:
8458 * @ctxt: the XPath Parser context
8459 *
8460 * Initialize the context to the root of the document
8461 */
8462void
8463xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8464 if ((ctxt == NULL) || (ctxt->context == NULL))
8465 return;
8466 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8467 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8468 ctxt->context->node));
8469}
8470
8471/************************************************************************
8472 * *
8473 * The explicit core function library *
8474 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8475 * *
8476 ************************************************************************/
8477
8478
8479/**
8480 * xmlXPathLastFunction:
8481 * @ctxt: the XPath Parser context
8482 * @nargs: the number of arguments
8483 *
8484 * Implement the last() XPath function
8485 * number last()
8486 * The last function returns the number of nodes in the context node list.
8487 */
8488void
8489xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8490 CHECK_ARITY(0);
8491 if (ctxt->context->contextSize >= 0) {
8492 valuePush(ctxt,
8493 xmlXPathCacheNewFloat(ctxt->context,
8494 (double) ctxt->context->contextSize));
8495#ifdef DEBUG_EXPR
8496 xmlGenericError(xmlGenericErrorContext,
8497 "last() : %d\n", ctxt->context->contextSize);
8498#endif
8499 } else {
8500 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8501 }
8502}
8503
8504/**
8505 * xmlXPathPositionFunction:
8506 * @ctxt: the XPath Parser context
8507 * @nargs: the number of arguments
8508 *
8509 * Implement the position() XPath function
8510 * number position()
8511 * The position function returns the position of the context node in the
8512 * context node list. The first position is 1, and so the last position
8513 * will be equal to last().
8514 */
8515void
8516xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8517 CHECK_ARITY(0);
8518 if (ctxt->context->proximityPosition >= 0) {
8519 valuePush(ctxt,
8520 xmlXPathCacheNewFloat(ctxt->context,
8521 (double) ctxt->context->proximityPosition));
8522#ifdef DEBUG_EXPR
8523 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8524 ctxt->context->proximityPosition);
8525#endif
8526 } else {
8527 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8528 }
8529}
8530
8531/**
8532 * xmlXPathCountFunction:
8533 * @ctxt: the XPath Parser context
8534 * @nargs: the number of arguments
8535 *
8536 * Implement the count() XPath function
8537 * number count(node-set)
8538 */
8539void
8540xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8541 xmlXPathObjectPtr cur;
8542
8543 CHECK_ARITY(1);
8544 if ((ctxt->value == NULL) ||
8545 ((ctxt->value->type != XPATH_NODESET) &&
8546 (ctxt->value->type != XPATH_XSLT_TREE)))
8547 XP_ERROR(XPATH_INVALID_TYPE);
8548 cur = valuePop(ctxt);
8549
8550 if ((cur == NULL) || (cur->nodesetval == NULL))
8551 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8552 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8553 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8554 (double) cur->nodesetval->nodeNr));
8555 } else {
8556 if ((cur->nodesetval->nodeNr != 1) ||
8557 (cur->nodesetval->nodeTab == NULL)) {
8558 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8559 } else {
8560 xmlNodePtr tmp;
8561 int i = 0;
8562
8563 tmp = cur->nodesetval->nodeTab[0];
8564 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8565 tmp = tmp->children;
8566 while (tmp != NULL) {
8567 tmp = tmp->next;
8568 i++;
8569 }
8570 }
8571 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8572 }
8573 }
8574 xmlXPathReleaseObject(ctxt->context, cur);
8575}
8576
8577/**
8578 * xmlXPathGetElementsByIds:
8579 * @doc: the document
8580 * @ids: a whitespace separated list of IDs
8581 *
8582 * Selects elements by their unique ID.
8583 *
8584 * Returns a node-set of selected elements.
8585 */
8586static xmlNodeSetPtr
8587xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8588 xmlNodeSetPtr ret;
8589 const xmlChar *cur = ids;
8590 xmlChar *ID;
8591 xmlAttrPtr attr;
8592 xmlNodePtr elem = NULL;
8593
8594 if (ids == NULL) return(NULL);
8595
8596 ret = xmlXPathNodeSetCreate(NULL);
8597 if (ret == NULL)
8598 return(ret);
8599
8600 while (IS_BLANK_CH(*cur)) cur++;
8601 while (*cur != 0) {
8602 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8603 cur++;
8604
8605 ID = xmlStrndup(ids, cur - ids);
8606 if (ID != NULL) {
8607 /*
8608 * We used to check the fact that the value passed
8609 * was an NCName, but this generated much troubles for
8610 * me and Aleksey Sanin, people blatantly violated that
8611 * constaint, like Visa3D spec.
8612 * if (xmlValidateNCName(ID, 1) == 0)
8613 */
8614 attr = xmlGetID(doc, ID);
8615 if (attr != NULL) {
8616 if (attr->type == XML_ATTRIBUTE_NODE)
8617 elem = attr->parent;
8618 else if (attr->type == XML_ELEMENT_NODE)
8619 elem = (xmlNodePtr) attr;
8620 else
8621 elem = NULL;
8622 if (elem != NULL)
8623 xmlXPathNodeSetAdd(ret, elem);
8624 }
8625 xmlFree(ID);
8626 }
8627
8628 while (IS_BLANK_CH(*cur)) cur++;
8629 ids = cur;
8630 }
8631 return(ret);
8632}
8633
8634/**
8635 * xmlXPathIdFunction:
8636 * @ctxt: the XPath Parser context
8637 * @nargs: the number of arguments
8638 *
8639 * Implement the id() XPath function
8640 * node-set id(object)
8641 * The id function selects elements by their unique ID
8642 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8643 * then the result is the union of the result of applying id to the
8644 * string value of each of the nodes in the argument node-set. When the
8645 * argument to id is of any other type, the argument is converted to a
8646 * string as if by a call to the string function; the string is split
8647 * into a whitespace-separated list of tokens (whitespace is any sequence
8648 * of characters matching the production S); the result is a node-set
8649 * containing the elements in the same document as the context node that
8650 * have a unique ID equal to any of the tokens in the list.
8651 */
8652void
8653xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8654 xmlChar *tokens;
8655 xmlNodeSetPtr ret;
8656 xmlXPathObjectPtr obj;
8657
8658 CHECK_ARITY(1);
8659 obj = valuePop(ctxt);
8660 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8661 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8662 xmlNodeSetPtr ns;
8663 int i;
8664
8665 ret = xmlXPathNodeSetCreate(NULL);
8666 /*
8667 * FIXME -- in an out-of-memory condition this will behave badly.
8668 * The solution is not clear -- we already popped an item from
8669 * ctxt, so the object is in a corrupt state.
8670 */
8671
8672 if (obj->nodesetval != NULL) {
8673 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8674 tokens =
8675 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8676 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8677 ret = xmlXPathNodeSetMerge(ret, ns);
8678 xmlXPathFreeNodeSet(ns);
8679 if (tokens != NULL)
8680 xmlFree(tokens);
8681 }
8682 }
8683 xmlXPathReleaseObject(ctxt->context, obj);
8684 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8685 return;
8686 }
8687 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8688 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8689 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8690 xmlXPathReleaseObject(ctxt->context, obj);
8691 return;
8692}
8693
8694/**
8695 * xmlXPathLocalNameFunction:
8696 * @ctxt: the XPath Parser context
8697 * @nargs: the number of arguments
8698 *
8699 * Implement the local-name() XPath function
8700 * string local-name(node-set?)
8701 * The local-name function returns a string containing the local part
8702 * of the name of the node in the argument node-set that is first in
8703 * document order. If the node-set is empty or the first node has no
8704 * name, an empty string is returned. If the argument is omitted it
8705 * defaults to the context node.
8706 */
8707void
8708xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8709 xmlXPathObjectPtr cur;
8710
8711 if (ctxt == NULL) return;
8712
8713 if (nargs == 0) {
8714 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8715 ctxt->context->node));
8716 nargs = 1;
8717 }
8718
8719 CHECK_ARITY(1);
8720 if ((ctxt->value == NULL) ||
8721 ((ctxt->value->type != XPATH_NODESET) &&
8722 (ctxt->value->type != XPATH_XSLT_TREE)))
8723 XP_ERROR(XPATH_INVALID_TYPE);
8724 cur = valuePop(ctxt);
8725
8726 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8727 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8728 } else {
8729 int i = 0; /* Should be first in document order !!!!! */
8730 switch (cur->nodesetval->nodeTab[i]->type) {
8731 case XML_ELEMENT_NODE:
8732 case XML_ATTRIBUTE_NODE:
8733 case XML_PI_NODE:
8734 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8735 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8736 else
8737 valuePush(ctxt,
8738 xmlXPathCacheNewString(ctxt->context,
8739 cur->nodesetval->nodeTab[i]->name));
8740 break;
8741 case XML_NAMESPACE_DECL:
8742 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8743 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8744 break;
8745 default:
8746 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8747 }
8748 }
8749 xmlXPathReleaseObject(ctxt->context, cur);
8750}
8751
8752/**
8753 * xmlXPathNamespaceURIFunction:
8754 * @ctxt: the XPath Parser context
8755 * @nargs: the number of arguments
8756 *
8757 * Implement the namespace-uri() XPath function
8758 * string namespace-uri(node-set?)
8759 * The namespace-uri function returns a string containing the
8760 * namespace URI of the expanded name of the node in the argument
8761 * node-set that is first in document order. If the node-set is empty,
8762 * the first node has no name, or the expanded name has no namespace
8763 * URI, an empty string is returned. If the argument is omitted it
8764 * defaults to the context node.
8765 */
8766void
8767xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8768 xmlXPathObjectPtr cur;
8769
8770 if (ctxt == NULL) return;
8771
8772 if (nargs == 0) {
8773 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8774 ctxt->context->node));
8775 nargs = 1;
8776 }
8777 CHECK_ARITY(1);
8778 if ((ctxt->value == NULL) ||
8779 ((ctxt->value->type != XPATH_NODESET) &&
8780 (ctxt->value->type != XPATH_XSLT_TREE)))
8781 XP_ERROR(XPATH_INVALID_TYPE);
8782 cur = valuePop(ctxt);
8783
8784 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8785 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8786 } else {
8787 int i = 0; /* Should be first in document order !!!!! */
8788 switch (cur->nodesetval->nodeTab[i]->type) {
8789 case XML_ELEMENT_NODE:
8790 case XML_ATTRIBUTE_NODE:
8791 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8792 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8793 else
8794 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8795 cur->nodesetval->nodeTab[i]->ns->href));
8796 break;
8797 default:
8798 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799 }
8800 }
8801 xmlXPathReleaseObject(ctxt->context, cur);
8802}
8803
8804/**
8805 * xmlXPathNameFunction:
8806 * @ctxt: the XPath Parser context
8807 * @nargs: the number of arguments
8808 *
8809 * Implement the name() XPath function
8810 * string name(node-set?)
8811 * The name function returns a string containing a QName representing
8812 * the name of the node in the argument node-set that is first in document
8813 * order. The QName must represent the name with respect to the namespace
8814 * declarations in effect on the node whose name is being represented.
8815 * Typically, this will be the form in which the name occurred in the XML
8816 * source. This need not be the case if there are namespace declarations
8817 * in effect on the node that associate multiple prefixes with the same
8818 * namespace. However, an implementation may include information about
8819 * the original prefix in its representation of nodes; in this case, an
8820 * implementation can ensure that the returned string is always the same
8821 * as the QName used in the XML source. If the argument it omitted it
8822 * defaults to the context node.
8823 * Libxml keep the original prefix so the "real qualified name" used is
8824 * returned.
8825 */
8826static void
8827xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8828{
8829 xmlXPathObjectPtr cur;
8830
8831 if (nargs == 0) {
8832 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8833 ctxt->context->node));
8834 nargs = 1;
8835 }
8836
8837 CHECK_ARITY(1);
8838 if ((ctxt->value == NULL) ||
8839 ((ctxt->value->type != XPATH_NODESET) &&
8840 (ctxt->value->type != XPATH_XSLT_TREE)))
8841 XP_ERROR(XPATH_INVALID_TYPE);
8842 cur = valuePop(ctxt);
8843
8844 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8845 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8846 } else {
8847 int i = 0; /* Should be first in document order !!!!! */
8848
8849 switch (cur->nodesetval->nodeTab[i]->type) {
8850 case XML_ELEMENT_NODE:
8851 case XML_ATTRIBUTE_NODE:
8852 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8853 valuePush(ctxt,
8854 xmlXPathCacheNewCString(ctxt->context, ""));
8855 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8856 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8857 valuePush(ctxt,
8858 xmlXPathCacheNewString(ctxt->context,
8859 cur->nodesetval->nodeTab[i]->name));
8860 } else {
8861 xmlChar *fullname;
8862
8863 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8864 cur->nodesetval->nodeTab[i]->ns->prefix,
8865 NULL, 0);
8866 if (fullname == cur->nodesetval->nodeTab[i]->name)
8867 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8868 if (fullname == NULL) {
8869 XP_ERROR(XPATH_MEMORY_ERROR);
8870 }
8871 valuePush(ctxt, xmlXPathCacheWrapString(
8872 ctxt->context, fullname));
8873 }
8874 break;
8875 default:
8876 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8877 cur->nodesetval->nodeTab[i]));
8878 xmlXPathLocalNameFunction(ctxt, 1);
8879 }
8880 }
8881 xmlXPathReleaseObject(ctxt->context, cur);
8882}
8883
8884
8885/**
8886 * xmlXPathStringFunction:
8887 * @ctxt: the XPath Parser context
8888 * @nargs: the number of arguments
8889 *
8890 * Implement the string() XPath function
8891 * string string(object?)
8892 * The string function converts an object to a string as follows:
8893 * - A node-set is converted to a string by returning the value of
8894 * the node in the node-set that is first in document order.
8895 * If the node-set is empty, an empty string is returned.
8896 * - A number is converted to a string as follows
8897 * + NaN is converted to the string NaN
8898 * + positive zero is converted to the string 0
8899 * + negative zero is converted to the string 0
8900 * + positive infinity is converted to the string Infinity
8901 * + negative infinity is converted to the string -Infinity
8902 * + if the number is an integer, the number is represented in
8903 * decimal form as a Number with no decimal point and no leading
8904 * zeros, preceded by a minus sign (-) if the number is negative
8905 * + otherwise, the number is represented in decimal form as a
8906 * Number including a decimal point with at least one digit
8907 * before the decimal point and at least one digit after the
8908 * decimal point, preceded by a minus sign (-) if the number
8909 * is negative; there must be no leading zeros before the decimal
8910 * point apart possibly from the one required digit immediately
8911 * before the decimal point; beyond the one required digit
8912 * after the decimal point there must be as many, but only as
8913 * many, more digits as are needed to uniquely distinguish the
8914 * number from all other IEEE 754 numeric values.
8915 * - The boolean false value is converted to the string false.
8916 * The boolean true value is converted to the string true.
8917 *
8918 * If the argument is omitted, it defaults to a node-set with the
8919 * context node as its only member.
8920 */
8921void
8922xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8923 xmlXPathObjectPtr cur;
8924
8925 if (ctxt == NULL) return;
8926 if (nargs == 0) {
8927 valuePush(ctxt,
8928 xmlXPathCacheWrapString(ctxt->context,
8929 xmlXPathCastNodeToString(ctxt->context->node)));
8930 return;
8931 }
8932
8933 CHECK_ARITY(1);
8934 cur = valuePop(ctxt);
8935 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8936 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8937}
8938
8939/**
8940 * xmlXPathStringLengthFunction:
8941 * @ctxt: the XPath Parser context
8942 * @nargs: the number of arguments
8943 *
8944 * Implement the string-length() XPath function
8945 * number string-length(string?)
8946 * The string-length returns the number of characters in the string
8947 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8948 * the context node converted to a string, in other words the value
8949 * of the context node.
8950 */
8951void
8952xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8953 xmlXPathObjectPtr cur;
8954
8955 if (nargs == 0) {
8956 if ((ctxt == NULL) || (ctxt->context == NULL))
8957 return;
8958 if (ctxt->context->node == NULL) {
8959 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8960 } else {
8961 xmlChar *content;
8962
8963 content = xmlXPathCastNodeToString(ctxt->context->node);
8964 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8965 xmlUTF8Strlen(content)));
8966 xmlFree(content);
8967 }
8968 return;
8969 }
8970 CHECK_ARITY(1);
8971 CAST_TO_STRING;
8972 CHECK_TYPE(XPATH_STRING);
8973 cur = valuePop(ctxt);
8974 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8975 xmlUTF8Strlen(cur->stringval)));
8976 xmlXPathReleaseObject(ctxt->context, cur);
8977}
8978
8979/**
8980 * xmlXPathConcatFunction:
8981 * @ctxt: the XPath Parser context
8982 * @nargs: the number of arguments
8983 *
8984 * Implement the concat() XPath function
8985 * string concat(string, string, string*)
8986 * The concat function returns the concatenation of its arguments.
8987 */
8988void
8989xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8990 xmlXPathObjectPtr cur, newobj;
8991 xmlChar *tmp;
8992
8993 if (ctxt == NULL) return;
8994 if (nargs < 2) {
8995 CHECK_ARITY(2);
8996 }
8997
8998 CAST_TO_STRING;
8999 cur = valuePop(ctxt);
9000 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9001 xmlXPathReleaseObject(ctxt->context, cur);
9002 return;
9003 }
9004 nargs--;
9005
9006 while (nargs > 0) {
9007 CAST_TO_STRING;
9008 newobj = valuePop(ctxt);
9009 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9010 xmlXPathReleaseObject(ctxt->context, newobj);
9011 xmlXPathReleaseObject(ctxt->context, cur);
9012 XP_ERROR(XPATH_INVALID_TYPE);
9013 }
9014 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9015 newobj->stringval = cur->stringval;
9016 cur->stringval = tmp;
9017 xmlXPathReleaseObject(ctxt->context, newobj);
9018 nargs--;
9019 }
9020 valuePush(ctxt, cur);
9021}
9022
9023/**
9024 * xmlXPathContainsFunction:
9025 * @ctxt: the XPath Parser context
9026 * @nargs: the number of arguments
9027 *
9028 * Implement the contains() XPath function
9029 * boolean contains(string, string)
9030 * The contains function returns true if the first argument string
9031 * contains the second argument string, and otherwise returns false.
9032 */
9033void
9034xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9035 xmlXPathObjectPtr hay, needle;
9036
9037 CHECK_ARITY(2);
9038 CAST_TO_STRING;
9039 CHECK_TYPE(XPATH_STRING);
9040 needle = valuePop(ctxt);
9041 CAST_TO_STRING;
9042 hay = valuePop(ctxt);
9043
9044 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9045 xmlXPathReleaseObject(ctxt->context, hay);
9046 xmlXPathReleaseObject(ctxt->context, needle);
9047 XP_ERROR(XPATH_INVALID_TYPE);
9048 }
9049 if (xmlStrstr(hay->stringval, needle->stringval))
9050 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9051 else
9052 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9053 xmlXPathReleaseObject(ctxt->context, hay);
9054 xmlXPathReleaseObject(ctxt->context, needle);
9055}
9056
9057/**
9058 * xmlXPathStartsWithFunction:
9059 * @ctxt: the XPath Parser context
9060 * @nargs: the number of arguments
9061 *
9062 * Implement the starts-with() XPath function
9063 * boolean starts-with(string, string)
9064 * The starts-with function returns true if the first argument string
9065 * starts with the second argument string, and otherwise returns false.
9066 */
9067void
9068xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9069 xmlXPathObjectPtr hay, needle;
9070 int n;
9071
9072 CHECK_ARITY(2);
9073 CAST_TO_STRING;
9074 CHECK_TYPE(XPATH_STRING);
9075 needle = valuePop(ctxt);
9076 CAST_TO_STRING;
9077 hay = valuePop(ctxt);
9078
9079 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9080 xmlXPathReleaseObject(ctxt->context, hay);
9081 xmlXPathReleaseObject(ctxt->context, needle);
9082 XP_ERROR(XPATH_INVALID_TYPE);
9083 }
9084 n = xmlStrlen(needle->stringval);
9085 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9086 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9087 else
9088 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9089 xmlXPathReleaseObject(ctxt->context, hay);
9090 xmlXPathReleaseObject(ctxt->context, needle);
9091}
9092
9093/**
9094 * xmlXPathSubstringFunction:
9095 * @ctxt: the XPath Parser context
9096 * @nargs: the number of arguments
9097 *
9098 * Implement the substring() XPath function
9099 * string substring(string, number, number?)
9100 * The substring function returns the substring of the first argument
9101 * starting at the position specified in the second argument with
9102 * length specified in the third argument. For example,
9103 * substring("12345",2,3) returns "234". If the third argument is not
9104 * specified, it returns the substring starting at the position specified
9105 * in the second argument and continuing to the end of the string. For
9106 * example, substring("12345",2) returns "2345". More precisely, each
9107 * character in the string (see [3.6 Strings]) is considered to have a
9108 * numeric position: the position of the first character is 1, the position
9109 * of the second character is 2 and so on. The returned substring contains
9110 * those characters for which the position of the character is greater than
9111 * or equal to the second argument and, if the third argument is specified,
9112 * less than the sum of the second and third arguments; the comparisons
9113 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9114 * - substring("12345", 1.5, 2.6) returns "234"
9115 * - substring("12345", 0, 3) returns "12"
9116 * - substring("12345", 0 div 0, 3) returns ""
9117 * - substring("12345", 1, 0 div 0) returns ""
9118 * - substring("12345", -42, 1 div 0) returns "12345"
9119 * - substring("12345", -1 div 0, 1 div 0) returns ""
9120 */
9121void
9122xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9123 xmlXPathObjectPtr str, start, len;
9124 double le=0, in;
9125 int i, l, m;
9126 xmlChar *ret;
9127
9128 if (nargs < 2) {
9129 CHECK_ARITY(2);
9130 }
9131 if (nargs > 3) {
9132 CHECK_ARITY(3);
9133 }
9134 /*
9135 * take care of possible last (position) argument
9136 */
9137 if (nargs == 3) {
9138 CAST_TO_NUMBER;
9139 CHECK_TYPE(XPATH_NUMBER);
9140 len = valuePop(ctxt);
9141 le = len->floatval;
9142 xmlXPathReleaseObject(ctxt->context, len);
9143 }
9144
9145 CAST_TO_NUMBER;
9146 CHECK_TYPE(XPATH_NUMBER);
9147 start = valuePop(ctxt);
9148 in = start->floatval;
9149 xmlXPathReleaseObject(ctxt->context, start);
9150 CAST_TO_STRING;
9151 CHECK_TYPE(XPATH_STRING);
9152 str = valuePop(ctxt);
9153 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9154
9155 /*
9156 * If last pos not present, calculate last position
9157 */
9158 if (nargs != 3) {
9159 le = (double)m;
9160 if (in < 1.0)
9161 in = 1.0;
9162 }
9163
9164 /* Need to check for the special cases where either
9165 * the index is NaN, the length is NaN, or both
9166 * arguments are infinity (relying on Inf + -Inf = NaN)
9167 */
9168 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9169 /*
9170 * To meet the requirements of the spec, the arguments
9171 * must be converted to integer format before
9172 * initial index calculations are done
9173 *
9174 * First we go to integer form, rounding up
9175 * and checking for special cases
9176 */
9177 i = (int) in;
9178 if (((double)i)+0.5 <= in) i++;
9179
9180 if (xmlXPathIsInf(le) == 1) {
9181 l = m;
9182 if (i < 1)
9183 i = 1;
9184 }
9185 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9186 l = 0;
9187 else {
9188 l = (int) le;
9189 if (((double)l)+0.5 <= le) l++;
9190 }
9191
9192 /* Now we normalize inidices */
9193 i -= 1;
9194 l += i;
9195 if (i < 0)
9196 i = 0;
9197 if (l > m)
9198 l = m;
9199
9200 /* number of chars to copy */
9201 l -= i;
9202
9203 ret = xmlUTF8Strsub(str->stringval, i, l);
9204 }
9205 else {
9206 ret = NULL;
9207 }
9208 if (ret == NULL)
9209 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9210 else {
9211 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9212 xmlFree(ret);
9213 }
9214 xmlXPathReleaseObject(ctxt->context, str);
9215}
9216
9217/**
9218 * xmlXPathSubstringBeforeFunction:
9219 * @ctxt: the XPath Parser context
9220 * @nargs: the number of arguments
9221 *
9222 * Implement the substring-before() XPath function
9223 * string substring-before(string, string)
9224 * The substring-before function returns the substring of the first
9225 * argument string that precedes the first occurrence of the second
9226 * argument string in the first argument string, or the empty string
9227 * if the first argument string does not contain the second argument
9228 * string. For example, substring-before("1999/04/01","/") returns 1999.
9229 */
9230void
9231xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9232 xmlXPathObjectPtr str;
9233 xmlXPathObjectPtr find;
9234 xmlBufPtr target;
9235 const xmlChar *point;
9236 int offset;
9237
9238 CHECK_ARITY(2);
9239 CAST_TO_STRING;
9240 find = valuePop(ctxt);
9241 CAST_TO_STRING;
9242 str = valuePop(ctxt);
9243
9244 target = xmlBufCreate();
9245 if (target) {
9246 point = xmlStrstr(str->stringval, find->stringval);
9247 if (point) {
9248 offset = (int)(point - str->stringval);
9249 xmlBufAdd(target, str->stringval, offset);
9250 }
9251 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9252 xmlBufContent(target)));
9253 xmlBufFree(target);
9254 }
9255 xmlXPathReleaseObject(ctxt->context, str);
9256 xmlXPathReleaseObject(ctxt->context, find);
9257}
9258
9259/**
9260 * xmlXPathSubstringAfterFunction:
9261 * @ctxt: the XPath Parser context
9262 * @nargs: the number of arguments
9263 *
9264 * Implement the substring-after() XPath function
9265 * string substring-after(string, string)
9266 * The substring-after function returns the substring of the first
9267 * argument string that follows the first occurrence of the second
9268 * argument string in the first argument string, or the empty stringi
9269 * if the first argument string does not contain the second argument
9270 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9271 * and substring-after("1999/04/01","19") returns 99/04/01.
9272 */
9273void
9274xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9275 xmlXPathObjectPtr str;
9276 xmlXPathObjectPtr find;
9277 xmlBufPtr target;
9278 const xmlChar *point;
9279 int offset;
9280
9281 CHECK_ARITY(2);
9282 CAST_TO_STRING;
9283 find = valuePop(ctxt);
9284 CAST_TO_STRING;
9285 str = valuePop(ctxt);
9286
9287 target = xmlBufCreate();
9288 if (target) {
9289 point = xmlStrstr(str->stringval, find->stringval);
9290 if (point) {
9291 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9292 xmlBufAdd(target, &str->stringval[offset],
9293 xmlStrlen(str->stringval) - offset);
9294 }
9295 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9296 xmlBufContent(target)));
9297 xmlBufFree(target);
9298 }
9299 xmlXPathReleaseObject(ctxt->context, str);
9300 xmlXPathReleaseObject(ctxt->context, find);
9301}
9302
9303/**
9304 * xmlXPathNormalizeFunction:
9305 * @ctxt: the XPath Parser context
9306 * @nargs: the number of arguments
9307 *
9308 * Implement the normalize-space() XPath function
9309 * string normalize-space(string?)
9310 * The normalize-space function returns the argument string with white
9311 * space normalized by stripping leading and trailing whitespace
9312 * and replacing sequences of whitespace characters by a single
9313 * space. Whitespace characters are the same allowed by the S production
9314 * in XML. If the argument is omitted, it defaults to the context
9315 * node converted to a string, in other words the value of the context node.
9316 */
9317void
9318xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9319 xmlXPathObjectPtr obj = NULL;
9320 xmlChar *source = NULL;
9321 xmlBufPtr target;
9322 xmlChar blank;
9323
9324 if (ctxt == NULL) return;
9325 if (nargs == 0) {
9326 /* Use current context node */
9327 valuePush(ctxt,
9328 xmlXPathCacheWrapString(ctxt->context,
9329 xmlXPathCastNodeToString(ctxt->context->node)));
9330 nargs = 1;
9331 }
9332
9333 CHECK_ARITY(1);
9334 CAST_TO_STRING;
9335 CHECK_TYPE(XPATH_STRING);
9336 obj = valuePop(ctxt);
9337 source = obj->stringval;
9338
9339 target = xmlBufCreate();
9340 if (target && source) {
9341
9342 /* Skip leading whitespaces */
9343 while (IS_BLANK_CH(*source))
9344 source++;
9345
9346 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9347 blank = 0;
9348 while (*source) {
9349 if (IS_BLANK_CH(*source)) {
9350 blank = 0x20;
9351 } else {
9352 if (blank) {
9353 xmlBufAdd(target, &blank, 1);
9354 blank = 0;
9355 }
9356 xmlBufAdd(target, source, 1);
9357 }
9358 source++;
9359 }
9360 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9361 xmlBufContent(target)));
9362 xmlBufFree(target);
9363 }
9364 xmlXPathReleaseObject(ctxt->context, obj);
9365}
9366
9367/**
9368 * xmlXPathTranslateFunction:
9369 * @ctxt: the XPath Parser context
9370 * @nargs: the number of arguments
9371 *
9372 * Implement the translate() XPath function
9373 * string translate(string, string, string)
9374 * The translate function returns the first argument string with
9375 * occurrences of characters in the second argument string replaced
9376 * by the character at the corresponding position in the third argument
9377 * string. For example, translate("bar","abc","ABC") returns the string
9378 * BAr. If there is a character in the second argument string with no
9379 * character at a corresponding position in the third argument string
9380 * (because the second argument string is longer than the third argument
9381 * string), then occurrences of that character in the first argument
9382 * string are removed. For example, translate("--aaa--","abc-","ABC")
9383 * returns "AAA". If a character occurs more than once in second
9384 * argument string, then the first occurrence determines the replacement
9385 * character. If the third argument string is longer than the second
9386 * argument string, then excess characters are ignored.
9387 */
9388void
9389xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9390 xmlXPathObjectPtr str;
9391 xmlXPathObjectPtr from;
9392 xmlXPathObjectPtr to;
9393 xmlBufPtr target;
9394 int offset, max;
9395 xmlChar ch;
9396 const xmlChar *point;
9397 xmlChar *cptr;
9398
9399 CHECK_ARITY(3);
9400
9401 CAST_TO_STRING;
9402 to = valuePop(ctxt);
9403 CAST_TO_STRING;
9404 from = valuePop(ctxt);
9405 CAST_TO_STRING;
9406 str = valuePop(ctxt);
9407
9408 target = xmlBufCreate();
9409 if (target) {
9410 max = xmlUTF8Strlen(to->stringval);
9411 for (cptr = str->stringval; (ch=*cptr); ) {
9412 offset = xmlUTF8Strloc(from->stringval, cptr);
9413 if (offset >= 0) {
9414 if (offset < max) {
9415 point = xmlUTF8Strpos(to->stringval, offset);
9416 if (point)
9417 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9418 }
9419 } else
9420 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9421
9422 /* Step to next character in input */
9423 cptr++;
9424 if ( ch & 0x80 ) {
9425 /* if not simple ascii, verify proper format */
9426 if ( (ch & 0xc0) != 0xc0 ) {
9427 xmlGenericError(xmlGenericErrorContext,
9428 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9429 /* not asserting an XPath error is probably better */
9430 break;
9431 }
9432 /* then skip over remaining bytes for this char */
9433 while ( (ch <<= 1) & 0x80 )
9434 if ( (*cptr++ & 0xc0) != 0x80 ) {
9435 xmlGenericError(xmlGenericErrorContext,
9436 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9437 /* not asserting an XPath error is probably better */
9438 break;
9439 }
9440 if (ch & 0x80) /* must have had error encountered */
9441 break;
9442 }
9443 }
9444 }
9445 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9446 xmlBufContent(target)));
9447 xmlBufFree(target);
9448 xmlXPathReleaseObject(ctxt->context, str);
9449 xmlXPathReleaseObject(ctxt->context, from);
9450 xmlXPathReleaseObject(ctxt->context, to);
9451}
9452
9453/**
9454 * xmlXPathBooleanFunction:
9455 * @ctxt: the XPath Parser context
9456 * @nargs: the number of arguments
9457 *
9458 * Implement the boolean() XPath function
9459 * boolean boolean(object)
9460 * The boolean function converts its argument to a boolean as follows:
9461 * - a number is true if and only if it is neither positive or
9462 * negative zero nor NaN
9463 * - a node-set is true if and only if it is non-empty
9464 * - a string is true if and only if its length is non-zero
9465 */
9466void
9467xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9468 xmlXPathObjectPtr cur;
9469
9470 CHECK_ARITY(1);
9471 cur = valuePop(ctxt);
9472 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9473 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9474 valuePush(ctxt, cur);
9475}
9476
9477/**
9478 * xmlXPathNotFunction:
9479 * @ctxt: the XPath Parser context
9480 * @nargs: the number of arguments
9481 *
9482 * Implement the not() XPath function
9483 * boolean not(boolean)
9484 * The not function returns true if its argument is false,
9485 * and false otherwise.
9486 */
9487void
9488xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9489 CHECK_ARITY(1);
9490 CAST_TO_BOOLEAN;
9491 CHECK_TYPE(XPATH_BOOLEAN);
9492 ctxt->value->boolval = ! ctxt->value->boolval;
9493}
9494
9495/**
9496 * xmlXPathTrueFunction:
9497 * @ctxt: the XPath Parser context
9498 * @nargs: the number of arguments
9499 *
9500 * Implement the true() XPath function
9501 * boolean true()
9502 */
9503void
9504xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9505 CHECK_ARITY(0);
9506 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9507}
9508
9509/**
9510 * xmlXPathFalseFunction:
9511 * @ctxt: the XPath Parser context
9512 * @nargs: the number of arguments
9513 *
9514 * Implement the false() XPath function
9515 * boolean false()
9516 */
9517void
9518xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9519 CHECK_ARITY(0);
9520 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9521}
9522
9523/**
9524 * xmlXPathLangFunction:
9525 * @ctxt: the XPath Parser context
9526 * @nargs: the number of arguments
9527 *
9528 * Implement the lang() XPath function
9529 * boolean lang(string)
9530 * The lang function returns true or false depending on whether the
9531 * language of the context node as specified by xml:lang attributes
9532 * is the same as or is a sublanguage of the language specified by
9533 * the argument string. The language of the context node is determined
9534 * by the value of the xml:lang attribute on the context node, or, if
9535 * the context node has no xml:lang attribute, by the value of the
9536 * xml:lang attribute on the nearest ancestor of the context node that
9537 * has an xml:lang attribute. If there is no such attribute, then lang
9538 * returns false. If there is such an attribute, then lang returns
9539 * true if the attribute value is equal to the argument ignoring case,
9540 * or if there is some suffix starting with - such that the attribute
9541 * value is equal to the argument ignoring that suffix of the attribute
9542 * value and ignoring case.
9543 */
9544void
9545xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9546 xmlXPathObjectPtr val = NULL;
9547 const xmlChar *theLang = NULL;
9548 const xmlChar *lang;
9549 int ret = 0;
9550 int i;
9551
9552 CHECK_ARITY(1);
9553 CAST_TO_STRING;
9554 CHECK_TYPE(XPATH_STRING);
9555 val = valuePop(ctxt);
9556 lang = val->stringval;
9557 theLang = xmlNodeGetLang(ctxt->context->node);
9558 if ((theLang != NULL) && (lang != NULL)) {
9559 for (i = 0;lang[i] != 0;i++)
9560 if (toupper(lang[i]) != toupper(theLang[i]))
9561 goto not_equal;
9562 if ((theLang[i] == 0) || (theLang[i] == '-'))
9563 ret = 1;
9564 }
9565not_equal:
9566 if (theLang != NULL)
9567 xmlFree((void *)theLang);
9568
9569 xmlXPathReleaseObject(ctxt->context, val);
9570 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9571}
9572
9573/**
9574 * xmlXPathNumberFunction:
9575 * @ctxt: the XPath Parser context
9576 * @nargs: the number of arguments
9577 *
9578 * Implement the number() XPath function
9579 * number number(object?)
9580 */
9581void
9582xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9583 xmlXPathObjectPtr cur;
9584 double res;
9585
9586 if (ctxt == NULL) return;
9587 if (nargs == 0) {
9588 if (ctxt->context->node == NULL) {
9589 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9590 } else {
9591 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9592
9593 res = xmlXPathStringEvalNumber(content);
9594 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9595 xmlFree(content);
9596 }
9597 return;
9598 }
9599
9600 CHECK_ARITY(1);
9601 cur = valuePop(ctxt);
9602 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9603}
9604
9605/**
9606 * xmlXPathSumFunction:
9607 * @ctxt: the XPath Parser context
9608 * @nargs: the number of arguments
9609 *
9610 * Implement the sum() XPath function
9611 * number sum(node-set)
9612 * The sum function returns the sum of the values of the nodes in
9613 * the argument node-set.
9614 */
9615void
9616xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9617 xmlXPathObjectPtr cur;
9618 int i;
9619 double res = 0.0;
9620
9621 CHECK_ARITY(1);
9622 if ((ctxt->value == NULL) ||
9623 ((ctxt->value->type != XPATH_NODESET) &&
9624 (ctxt->value->type != XPATH_XSLT_TREE)))
9625 XP_ERROR(XPATH_INVALID_TYPE);
9626 cur = valuePop(ctxt);
9627
9628 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9629 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9630 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9631 }
9632 }
9633 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9634 xmlXPathReleaseObject(ctxt->context, cur);
9635}
9636
9637/*
9638 * To assure working code on multiple platforms, we want to only depend
9639 * upon the characteristic truncation of converting a floating point value
9640 * to an integer. Unfortunately, because of the different storage sizes
9641 * of our internal floating point value (double) and integer (int), we
9642 * can't directly convert (see bug 301162). This macro is a messy
9643 * 'workaround'
9644 */
9645#define XTRUNC(f, v) \
9646 f = fmod((v), INT_MAX); \
9647 f = (v) - (f) + (double)((int)(f));
9648
9649/**
9650 * xmlXPathFloorFunction:
9651 * @ctxt: the XPath Parser context
9652 * @nargs: the number of arguments
9653 *
9654 * Implement the floor() XPath function
9655 * number floor(number)
9656 * The floor function returns the largest (closest to positive infinity)
9657 * number that is not greater than the argument and that is an integer.
9658 */
9659void
9660xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9661 double f;
9662
9663 CHECK_ARITY(1);
9664 CAST_TO_NUMBER;
9665 CHECK_TYPE(XPATH_NUMBER);
9666
9667 XTRUNC(f, ctxt->value->floatval);
9668 if (f != ctxt->value->floatval) {
9669 if (ctxt->value->floatval > 0)
9670 ctxt->value->floatval = f;
9671 else
9672 ctxt->value->floatval = f - 1;
9673 }
9674}
9675
9676/**
9677 * xmlXPathCeilingFunction:
9678 * @ctxt: the XPath Parser context
9679 * @nargs: the number of arguments
9680 *
9681 * Implement the ceiling() XPath function
9682 * number ceiling(number)
9683 * The ceiling function returns the smallest (closest to negative infinity)
9684 * number that is not less than the argument and that is an integer.
9685 */
9686void
9687xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9688 double f;
9689
9690 CHECK_ARITY(1);
9691 CAST_TO_NUMBER;
9692 CHECK_TYPE(XPATH_NUMBER);
9693
9694#if 0
9695 ctxt->value->floatval = ceil(ctxt->value->floatval);
9696#else
9697 XTRUNC(f, ctxt->value->floatval);
9698 if (f != ctxt->value->floatval) {
9699 if (ctxt->value->floatval > 0)
9700 ctxt->value->floatval = f + 1;
9701 else {
9702 if (ctxt->value->floatval < 0 && f == 0)
9703 ctxt->value->floatval = xmlXPathNZERO;
9704 else
9705 ctxt->value->floatval = f;
9706 }
9707
9708 }
9709#endif
9710}
9711
9712/**
9713 * xmlXPathRoundFunction:
9714 * @ctxt: the XPath Parser context
9715 * @nargs: the number of arguments
9716 *
9717 * Implement the round() XPath function
9718 * number round(number)
9719 * The round function returns the number that is closest to the
9720 * argument and that is an integer. If there are two such numbers,
9721 * then the one that is even is returned.
9722 */
9723void
9724xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9725 double f;
9726
9727 CHECK_ARITY(1);
9728 CAST_TO_NUMBER;
9729 CHECK_TYPE(XPATH_NUMBER);
9730
9731 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9732 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9733 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9734 (ctxt->value->floatval == 0.0))
9735 return;
9736
9737 XTRUNC(f, ctxt->value->floatval);
9738 if (ctxt->value->floatval < 0) {
9739 if (ctxt->value->floatval < f - 0.5)
9740 ctxt->value->floatval = f - 1;
9741 else
9742 ctxt->value->floatval = f;
9743 if (ctxt->value->floatval == 0)
9744 ctxt->value->floatval = xmlXPathNZERO;
9745 } else {
9746 if (ctxt->value->floatval < f + 0.5)
9747 ctxt->value->floatval = f;
9748 else
9749 ctxt->value->floatval = f + 1;
9750 }
9751}
9752
9753/************************************************************************
9754 * *
9755 * The Parser *
9756 * *
9757 ************************************************************************/
9758
9759/*
9760 * a few forward declarations since we use a recursive call based
9761 * implementation.
9762 */
9763static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9764static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9765static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9766static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9767static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9768 int qualified);
9769
9770/**
9771 * xmlXPathCurrentChar:
9772 * @ctxt: the XPath parser context
9773 * @cur: pointer to the beginning of the char
9774 * @len: pointer to the length of the char read
9775 *
9776 * The current char value, if using UTF-8 this may actually span multiple
9777 * bytes in the input buffer.
9778 *
9779 * Returns the current char value and its length
9780 */
9781
9782static int
9783xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9784 unsigned char c;
9785 unsigned int val;
9786 const xmlChar *cur;
9787
9788 if (ctxt == NULL)
9789 return(0);
9790 cur = ctxt->cur;
9791
9792 /*
9793 * We are supposed to handle UTF8, check it's valid
9794 * From rfc2044: encoding of the Unicode values on UTF-8:
9795 *
9796 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9797 * 0000 0000-0000 007F 0xxxxxxx
9798 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9799 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9800 *
9801 * Check for the 0x110000 limit too
9802 */
9803 c = *cur;
9804 if (c & 0x80) {
9805 if ((cur[1] & 0xc0) != 0x80)
9806 goto encoding_error;
9807 if ((c & 0xe0) == 0xe0) {
9808
9809 if ((cur[2] & 0xc0) != 0x80)
9810 goto encoding_error;
9811 if ((c & 0xf0) == 0xf0) {
9812 if (((c & 0xf8) != 0xf0) ||
9813 ((cur[3] & 0xc0) != 0x80))
9814 goto encoding_error;
9815 /* 4-byte code */
9816 *len = 4;
9817 val = (cur[0] & 0x7) << 18;
9818 val |= (cur[1] & 0x3f) << 12;
9819 val |= (cur[2] & 0x3f) << 6;
9820 val |= cur[3] & 0x3f;
9821 } else {
9822 /* 3-byte code */
9823 *len = 3;
9824 val = (cur[0] & 0xf) << 12;
9825 val |= (cur[1] & 0x3f) << 6;
9826 val |= cur[2] & 0x3f;
9827 }
9828 } else {
9829 /* 2-byte code */
9830 *len = 2;
9831 val = (cur[0] & 0x1f) << 6;
9832 val |= cur[1] & 0x3f;
9833 }
9834 if (!IS_CHAR(val)) {
9835 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9836 }
9837 return(val);
9838 } else {
9839 /* 1-byte code */
9840 *len = 1;
9841 return((int) *cur);
9842 }
9843encoding_error:
9844 /*
9845 * If we detect an UTF8 error that probably means that the
9846 * input encoding didn't get properly advertised in the
9847 * declaration header. Report the error and switch the encoding
9848 * to ISO-Latin-1 (if you don't like this policy, just declare the
9849 * encoding !)
9850 */
9851 *len = 0;
9852 XP_ERROR0(XPATH_ENCODING_ERROR);
9853}
9854
9855/**
9856 * xmlXPathParseNCName:
9857 * @ctxt: the XPath Parser context
9858 *
9859 * parse an XML namespace non qualified name.
9860 *
9861 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9862 *
9863 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9864 * CombiningChar | Extender
9865 *
9866 * Returns the namespace name or NULL
9867 */
9868
9869xmlChar *
9870xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9871 const xmlChar *in;
9872 xmlChar *ret;
9873 int count = 0;
9874
9875 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9876 /*
9877 * Accelerator for simple ASCII names
9878 */
9879 in = ctxt->cur;
9880 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9881 ((*in >= 0x41) && (*in <= 0x5A)) ||
9882 (*in == '_')) {
9883 in++;
9884 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9885 ((*in >= 0x41) && (*in <= 0x5A)) ||
9886 ((*in >= 0x30) && (*in <= 0x39)) ||
9887 (*in == '_') || (*in == '.') ||
9888 (*in == '-'))
9889 in++;
9890 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9891 (*in == '[') || (*in == ']') || (*in == ':') ||
9892 (*in == '@') || (*in == '*')) {
9893 count = in - ctxt->cur;
9894 if (count == 0)
9895 return(NULL);
9896 ret = xmlStrndup(ctxt->cur, count);
9897 ctxt->cur = in;
9898 return(ret);
9899 }
9900 }
9901 return(xmlXPathParseNameComplex(ctxt, 0));
9902}
9903
9904
9905/**
9906 * xmlXPathParseQName:
9907 * @ctxt: the XPath Parser context
9908 * @prefix: a xmlChar **
9909 *
9910 * parse an XML qualified name
9911 *
9912 * [NS 5] QName ::= (Prefix ':')? LocalPart
9913 *
9914 * [NS 6] Prefix ::= NCName
9915 *
9916 * [NS 7] LocalPart ::= NCName
9917 *
9918 * Returns the function returns the local part, and prefix is updated
9919 * to get the Prefix if any.
9920 */
9921
9922static xmlChar *
9923xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9924 xmlChar *ret = NULL;
9925
9926 *prefix = NULL;
9927 ret = xmlXPathParseNCName(ctxt);
9928 if (ret && CUR == ':') {
9929 *prefix = ret;
9930 NEXT;
9931 ret = xmlXPathParseNCName(ctxt);
9932 }
9933 return(ret);
9934}
9935
9936/**
9937 * xmlXPathParseName:
9938 * @ctxt: the XPath Parser context
9939 *
9940 * parse an XML name
9941 *
9942 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9943 * CombiningChar | Extender
9944 *
9945 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9946 *
9947 * Returns the namespace name or NULL
9948 */
9949
9950xmlChar *
9951xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9952 const xmlChar *in;
9953 xmlChar *ret;
9954 size_t count = 0;
9955
9956 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9957 /*
9958 * Accelerator for simple ASCII names
9959 */
9960 in = ctxt->cur;
9961 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9962 ((*in >= 0x41) && (*in <= 0x5A)) ||
9963 (*in == '_') || (*in == ':')) {
9964 in++;
9965 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9966 ((*in >= 0x41) && (*in <= 0x5A)) ||
9967 ((*in >= 0x30) && (*in <= 0x39)) ||
9968 (*in == '_') || (*in == '-') ||
9969 (*in == ':') || (*in == '.'))
9970 in++;
9971 if ((*in > 0) && (*in < 0x80)) {
9972 count = in - ctxt->cur;
9973 if (count > XML_MAX_NAME_LENGTH) {
9974 ctxt->cur = in;
9975 XP_ERRORNULL(XPATH_EXPR_ERROR);
9976 }
9977 ret = xmlStrndup(ctxt->cur, count);
9978 ctxt->cur = in;
9979 return(ret);
9980 }
9981 }
9982 return(xmlXPathParseNameComplex(ctxt, 1));
9983}
9984
9985static xmlChar *
9986xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9987 xmlChar buf[XML_MAX_NAMELEN + 5];
9988 int len = 0, l;
9989 int c;
9990
9991 /*
9992 * Handler for more complex cases
9993 */
9994 c = CUR_CHAR(l);
9995 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9996 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9997 (c == '*') || /* accelerators */
9998 (!IS_LETTER(c) && (c != '_') &&
9999 ((qualified) && (c != ':')))) {
10000 return(NULL);
10001 }
10002
10003 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10004 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10005 (c == '.') || (c == '-') ||
10006 (c == '_') || ((qualified) && (c == ':')) ||
10007 (IS_COMBINING(c)) ||
10008 (IS_EXTENDER(c)))) {
10009 COPY_BUF(l,buf,len,c);
10010 NEXTL(l);
10011 c = CUR_CHAR(l);
10012 if (len >= XML_MAX_NAMELEN) {
10013 /*
10014 * Okay someone managed to make a huge name, so he's ready to pay
10015 * for the processing speed.
10016 */
10017 xmlChar *buffer;
10018 int max = len * 2;
10019
10020 if (len > XML_MAX_NAME_LENGTH) {
10021 XP_ERRORNULL(XPATH_EXPR_ERROR);
10022 }
10023 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10024 if (buffer == NULL) {
10025 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10026 }
10027 memcpy(buffer, buf, len);
10028 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10029 (c == '.') || (c == '-') ||
10030 (c == '_') || ((qualified) && (c == ':')) ||
10031 (IS_COMBINING(c)) ||
10032 (IS_EXTENDER(c))) {
10033 if (len + 10 > max) {
10034 if (max > XML_MAX_NAME_LENGTH) {
10035 XP_ERRORNULL(XPATH_EXPR_ERROR);
10036 }
10037 max *= 2;
10038 buffer = (xmlChar *) xmlRealloc(buffer,
10039 max * sizeof(xmlChar));
10040 if (buffer == NULL) {
10041 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10042 }
10043 }
10044 COPY_BUF(l,buffer,len,c);
10045 NEXTL(l);
10046 c = CUR_CHAR(l);
10047 }
10048 buffer[len] = 0;
10049 return(buffer);
10050 }
10051 }
10052 if (len == 0)
10053 return(NULL);
10054 return(xmlStrndup(buf, len));
10055}
10056
10057#define MAX_FRAC 20
10058
10059/*
10060 * These are used as divisors for the fractional part of a number.
10061 * Since the table includes 1.0 (representing '0' fractional digits),
10062 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10063 */
10064static double my_pow10[MAX_FRAC+1] = {
10065 1.0, 10.0, 100.0, 1000.0, 10000.0,
10066 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10067 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10068 100000000000000.0,
10069 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
10070 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
10071};
10072
10073/**
10074 * xmlXPathStringEvalNumber:
10075 * @str: A string to scan
10076 *
10077 * [30a] Float ::= Number ('e' Digits?)?
10078 *
10079 * [30] Number ::= Digits ('.' Digits?)?
10080 * | '.' Digits
10081 * [31] Digits ::= [0-9]+
10082 *
10083 * Compile a Number in the string
10084 * In complement of the Number expression, this function also handles
10085 * negative values : '-' Number.
10086 *
10087 * Returns the double value.
10088 */
10089double
10090xmlXPathStringEvalNumber(const xmlChar *str) {
10091 const xmlChar *cur = str;
10092 double ret;
10093 int ok = 0;
10094 int isneg = 0;
10095 int exponent = 0;
10096 int is_exponent_negative = 0;
10097#ifdef __GNUC__
10098 unsigned long tmp = 0;
10099 double temp;
10100#endif
10101 if (cur == NULL) return(0);
10102 while (IS_BLANK_CH(*cur)) cur++;
10103 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10104 return(xmlXPathNAN);
10105 }
10106 if (*cur == '-') {
10107 isneg = 1;
10108 cur++;
10109 }
10110
10111#ifdef __GNUC__
10112 /*
10113 * tmp/temp is a workaround against a gcc compiler bug
10114 * http://veillard.com/gcc.bug
10115 */
10116 ret = 0;
10117 while ((*cur >= '0') && (*cur <= '9')) {
10118 ret = ret * 10;
10119 tmp = (*cur - '0');
10120 ok = 1;
10121 cur++;
10122 temp = (double) tmp;
10123 ret = ret + temp;
10124 }
10125#else
10126 ret = 0;
10127 while ((*cur >= '0') && (*cur <= '9')) {
10128 ret = ret * 10 + (*cur - '0');
10129 ok = 1;
10130 cur++;
10131 }
10132#endif
10133
10134 if (*cur == '.') {
10135 int v, frac = 0;
10136 double fraction = 0;
10137
10138 cur++;
10139 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10140 return(xmlXPathNAN);
10141 }
10142 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10143 v = (*cur - '0');
10144 fraction = fraction * 10 + v;
10145 frac = frac + 1;
10146 cur++;
10147 }
10148 fraction /= my_pow10[frac];
10149 ret = ret + fraction;
10150 while ((*cur >= '0') && (*cur <= '9'))
10151 cur++;
10152 }
10153 if ((*cur == 'e') || (*cur == 'E')) {
10154 cur++;
10155 if (*cur == '-') {
10156 is_exponent_negative = 1;
10157 cur++;
10158 } else if (*cur == '+') {
10159 cur++;
10160 }
10161 while ((*cur >= '0') && (*cur <= '9')) {
10162 exponent = exponent * 10 + (*cur - '0');
10163 cur++;
10164 }
10165 }
10166 while (IS_BLANK_CH(*cur)) cur++;
10167 if (*cur != 0) return(xmlXPathNAN);
10168 if (isneg) ret = -ret;
10169 if (is_exponent_negative) exponent = -exponent;
10170 ret *= pow(10.0, (double)exponent);
10171 return(ret);
10172}
10173
10174/**
10175 * xmlXPathCompNumber:
10176 * @ctxt: the XPath Parser context
10177 *
10178 * [30] Number ::= Digits ('.' Digits?)?
10179 * | '.' Digits
10180 * [31] Digits ::= [0-9]+
10181 *
10182 * Compile a Number, then push it on the stack
10183 *
10184 */
10185static void
10186xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10187{
10188 double ret = 0.0;
10189 int ok = 0;
10190 int exponent = 0;
10191 int is_exponent_negative = 0;
10192#ifdef __GNUC__
10193 unsigned long tmp = 0;
10194 double temp;
10195#endif
10196
10197 CHECK_ERROR;
10198 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10199 XP_ERROR(XPATH_NUMBER_ERROR);
10200 }
10201#ifdef __GNUC__
10202 /*
10203 * tmp/temp is a workaround against a gcc compiler bug
10204 * http://veillard.com/gcc.bug
10205 */
10206 ret = 0;
10207 while ((CUR >= '0') && (CUR <= '9')) {
10208 ret = ret * 10;
10209 tmp = (CUR - '0');
10210 ok = 1;
10211 NEXT;
10212 temp = (double) tmp;
10213 ret = ret + temp;
10214 }
10215#else
10216 ret = 0;
10217 while ((CUR >= '0') && (CUR <= '9')) {
10218 ret = ret * 10 + (CUR - '0');
10219 ok = 1;
10220 NEXT;
10221 }
10222#endif
10223 if (CUR == '.') {
10224 int v, frac = 0;
10225 double fraction = 0;
10226
10227 NEXT;
10228 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10229 XP_ERROR(XPATH_NUMBER_ERROR);
10230 }
10231 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10232 v = (CUR - '0');
10233 fraction = fraction * 10 + v;
10234 frac = frac + 1;
10235 NEXT;
10236 }
10237 fraction /= my_pow10[frac];
10238 ret = ret + fraction;
10239 while ((CUR >= '0') && (CUR <= '9'))
10240 NEXT;
10241 }
10242 if ((CUR == 'e') || (CUR == 'E')) {
10243 NEXT;
10244 if (CUR == '-') {
10245 is_exponent_negative = 1;
10246 NEXT;
10247 } else if (CUR == '+') {
10248 NEXT;
10249 }
10250 while ((CUR >= '0') && (CUR <= '9')) {
10251 exponent = exponent * 10 + (CUR - '0');
10252 NEXT;
10253 }
10254 if (is_exponent_negative)
10255 exponent = -exponent;
10256 ret *= pow(10.0, (double) exponent);
10257 }
10258 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10259 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10260}
10261
10262/**
10263 * xmlXPathParseLiteral:
10264 * @ctxt: the XPath Parser context
10265 *
10266 * Parse a Literal
10267 *
10268 * [29] Literal ::= '"' [^"]* '"'
10269 * | "'" [^']* "'"
10270 *
10271 * Returns the value found or NULL in case of error
10272 */
10273static xmlChar *
10274xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10275 const xmlChar *q;
10276 xmlChar *ret = NULL;
10277
10278 if (CUR == '"') {
10279 NEXT;
10280 q = CUR_PTR;
10281 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10282 NEXT;
10283 if (!IS_CHAR_CH(CUR)) {
10284 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10285 } else {
10286 ret = xmlStrndup(q, CUR_PTR - q);
10287 NEXT;
10288 }
10289 } else if (CUR == '\'') {
10290 NEXT;
10291 q = CUR_PTR;
10292 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10293 NEXT;
10294 if (!IS_CHAR_CH(CUR)) {
10295 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10296 } else {
10297 ret = xmlStrndup(q, CUR_PTR - q);
10298 NEXT;
10299 }
10300 } else {
10301 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10302 }
10303 return(ret);
10304}
10305
10306/**
10307 * xmlXPathCompLiteral:
10308 * @ctxt: the XPath Parser context
10309 *
10310 * Parse a Literal and push it on the stack.
10311 *
10312 * [29] Literal ::= '"' [^"]* '"'
10313 * | "'" [^']* "'"
10314 *
10315 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10316 */
10317static void
10318xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10319 const xmlChar *q;
10320 xmlChar *ret = NULL;
10321
10322 if (CUR == '"') {
10323 NEXT;
10324 q = CUR_PTR;
10325 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10326 NEXT;
10327 if (!IS_CHAR_CH(CUR)) {
10328 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10329 } else {
10330 ret = xmlStrndup(q, CUR_PTR - q);
10331 NEXT;
10332 }
10333 } else if (CUR == '\'') {
10334 NEXT;
10335 q = CUR_PTR;
10336 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10337 NEXT;
10338 if (!IS_CHAR_CH(CUR)) {
10339 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10340 } else {
10341 ret = xmlStrndup(q, CUR_PTR - q);
10342 NEXT;
10343 }
10344 } else {
10345 XP_ERROR(XPATH_START_LITERAL_ERROR);
10346 }
10347 if (ret == NULL) return;
10348 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10349 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10350 xmlFree(ret);
10351}
10352
10353/**
10354 * xmlXPathCompVariableReference:
10355 * @ctxt: the XPath Parser context
10356 *
10357 * Parse a VariableReference, evaluate it and push it on the stack.
10358 *
10359 * The variable bindings consist of a mapping from variable names
10360 * to variable values. The value of a variable is an object, which can be
10361 * of any of the types that are possible for the value of an expression,
10362 * and may also be of additional types not specified here.
10363 *
10364 * Early evaluation is possible since:
10365 * The variable bindings [...] used to evaluate a subexpression are
10366 * always the same as those used to evaluate the containing expression.
10367 *
10368 * [36] VariableReference ::= '$' QName
10369 */
10370static void
10371xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10372 xmlChar *name;
10373 xmlChar *prefix;
10374
10375 SKIP_BLANKS;
10376 if (CUR != '$') {
10377 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378 }
10379 NEXT;
10380 name = xmlXPathParseQName(ctxt, &prefix);
10381 if (name == NULL) {
10382 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10383 }
10384 ctxt->comp->last = -1;
10385 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10386 name, prefix);
10387 SKIP_BLANKS;
10388 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10389 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10390 }
10391}
10392
10393/**
10394 * xmlXPathIsNodeType:
10395 * @name: a name string
10396 *
10397 * Is the name given a NodeType one.
10398 *
10399 * [38] NodeType ::= 'comment'
10400 * | 'text'
10401 * | 'processing-instruction'
10402 * | 'node'
10403 *
10404 * Returns 1 if true 0 otherwise
10405 */
10406int
10407xmlXPathIsNodeType(const xmlChar *name) {
10408 if (name == NULL)
10409 return(0);
10410
10411 if (xmlStrEqual(name, BAD_CAST "node"))
10412 return(1);
10413 if (xmlStrEqual(name, BAD_CAST "text"))
10414 return(1);
10415 if (xmlStrEqual(name, BAD_CAST "comment"))
10416 return(1);
10417 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10418 return(1);
10419 return(0);
10420}
10421
10422/**
10423 * xmlXPathCompFunctionCall:
10424 * @ctxt: the XPath Parser context
10425 *
10426 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10427 * [17] Argument ::= Expr
10428 *
10429 * Compile a function call, the evaluation of all arguments are
10430 * pushed on the stack
10431 */
10432static void
10433xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10434 xmlChar *name;
10435 xmlChar *prefix;
10436 int nbargs = 0;
10437 int sort = 1;
10438
10439 name = xmlXPathParseQName(ctxt, &prefix);
10440 if (name == NULL) {
10441 xmlFree(prefix);
10442 XP_ERROR(XPATH_EXPR_ERROR);
10443 }
10444 SKIP_BLANKS;
10445#ifdef DEBUG_EXPR
10446 if (prefix == NULL)
10447 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10448 name);
10449 else
10450 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10451 prefix, name);
10452#endif
10453
10454 if (CUR != '(') {
10455 XP_ERROR(XPATH_EXPR_ERROR);
10456 }
10457 NEXT;
10458 SKIP_BLANKS;
10459
10460 /*
10461 * Optimization for count(): we don't need the node-set to be sorted.
10462 */
10463 if ((prefix == NULL) && (name[0] == 'c') &&
10464 xmlStrEqual(name, BAD_CAST "count"))
10465 {
10466 sort = 0;
10467 }
10468 ctxt->comp->last = -1;
10469 if (CUR != ')') {
10470 while (CUR != 0) {
10471 int op1 = ctxt->comp->last;
10472 ctxt->comp->last = -1;
10473 xmlXPathCompileExpr(ctxt, sort);
10474 if (ctxt->error != XPATH_EXPRESSION_OK) {
10475 xmlFree(name);
10476 xmlFree(prefix);
10477 return;
10478 }
10479 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10480 nbargs++;
10481 if (CUR == ')') break;
10482 if (CUR != ',') {
10483 XP_ERROR(XPATH_EXPR_ERROR);
10484 }
10485 NEXT;
10486 SKIP_BLANKS;
10487 }
10488 }
10489 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10490 name, prefix);
10491 NEXT;
10492 SKIP_BLANKS;
10493}
10494
10495/**
10496 * xmlXPathCompPrimaryExpr:
10497 * @ctxt: the XPath Parser context
10498 *
10499 * [15] PrimaryExpr ::= VariableReference
10500 * | '(' Expr ')'
10501 * | Literal
10502 * | Number
10503 * | FunctionCall
10504 *
10505 * Compile a primary expression.
10506 */
10507static void
10508xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10509 SKIP_BLANKS;
10510 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10511 else if (CUR == '(') {
10512 NEXT;
10513 SKIP_BLANKS;
10514 xmlXPathCompileExpr(ctxt, 1);
10515 CHECK_ERROR;
10516 if (CUR != ')') {
10517 XP_ERROR(XPATH_EXPR_ERROR);
10518 }
10519 NEXT;
10520 SKIP_BLANKS;
10521 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10522 xmlXPathCompNumber(ctxt);
10523 } else if ((CUR == '\'') || (CUR == '"')) {
10524 xmlXPathCompLiteral(ctxt);
10525 } else {
10526 xmlXPathCompFunctionCall(ctxt);
10527 }
10528 SKIP_BLANKS;
10529}
10530
10531/**
10532 * xmlXPathCompFilterExpr:
10533 * @ctxt: the XPath Parser context
10534 *
10535 * [20] FilterExpr ::= PrimaryExpr
10536 * | FilterExpr Predicate
10537 *
10538 * Compile a filter expression.
10539 * Square brackets are used to filter expressions in the same way that
10540 * they are used in location paths. It is an error if the expression to
10541 * be filtered does not evaluate to a node-set. The context node list
10542 * used for evaluating the expression in square brackets is the node-set
10543 * to be filtered listed in document order.
10544 */
10545
10546static void
10547xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10548 xmlXPathCompPrimaryExpr(ctxt);
10549 CHECK_ERROR;
10550 SKIP_BLANKS;
10551
10552 while (CUR == '[') {
10553 xmlXPathCompPredicate(ctxt, 1);
10554 SKIP_BLANKS;
10555 }
10556
10557
10558}
10559
10560/**
10561 * xmlXPathScanName:
10562 * @ctxt: the XPath Parser context
10563 *
10564 * Trickery: parse an XML name but without consuming the input flow
10565 * Needed to avoid insanity in the parser state.
10566 *
10567 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10568 * CombiningChar | Extender
10569 *
10570 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10571 *
10572 * [6] Names ::= Name (S Name)*
10573 *
10574 * Returns the Name parsed or NULL
10575 */
10576
10577static xmlChar *
10578xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10579 int len = 0, l;
10580 int c;
10581 const xmlChar *cur;
10582 xmlChar *ret;
10583
10584 cur = ctxt->cur;
10585
10586 c = CUR_CHAR(l);
10587 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10588 (!IS_LETTER(c) && (c != '_') &&
10589 (c != ':'))) {
10590 return(NULL);
10591 }
10592
10593 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10594 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10595 (c == '.') || (c == '-') ||
10596 (c == '_') || (c == ':') ||
10597 (IS_COMBINING(c)) ||
10598 (IS_EXTENDER(c)))) {
10599 len += l;
10600 NEXTL(l);
10601 c = CUR_CHAR(l);
10602 }
10603 ret = xmlStrndup(cur, ctxt->cur - cur);
10604 ctxt->cur = cur;
10605 return(ret);
10606}
10607
10608/**
10609 * xmlXPathCompPathExpr:
10610 * @ctxt: the XPath Parser context
10611 *
10612 * [19] PathExpr ::= LocationPath
10613 * | FilterExpr
10614 * | FilterExpr '/' RelativeLocationPath
10615 * | FilterExpr '//' RelativeLocationPath
10616 *
10617 * Compile a path expression.
10618 * The / operator and // operators combine an arbitrary expression
10619 * and a relative location path. It is an error if the expression
10620 * does not evaluate to a node-set.
10621 * The / operator does composition in the same way as when / is
10622 * used in a location path. As in location paths, // is short for
10623 * /descendant-or-self::node()/.
10624 */
10625
10626static void
10627xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10628 int lc = 1; /* Should we branch to LocationPath ? */
10629 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10630
10631 SKIP_BLANKS;
10632 if ((CUR == '$') || (CUR == '(') ||
10633 (IS_ASCII_DIGIT(CUR)) ||
10634 (CUR == '\'') || (CUR == '"') ||
10635 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10636 lc = 0;
10637 } else if (CUR == '*') {
10638 /* relative or absolute location path */
10639 lc = 1;
10640 } else if (CUR == '/') {
10641 /* relative or absolute location path */
10642 lc = 1;
10643 } else if (CUR == '@') {
10644 /* relative abbreviated attribute location path */
10645 lc = 1;
10646 } else if (CUR == '.') {
10647 /* relative abbreviated attribute location path */
10648 lc = 1;
10649 } else {
10650 /*
10651 * Problem is finding if we have a name here whether it's:
10652 * - a nodetype
10653 * - a function call in which case it's followed by '('
10654 * - an axis in which case it's followed by ':'
10655 * - a element name
10656 * We do an a priori analysis here rather than having to
10657 * maintain parsed token content through the recursive function
10658 * calls. This looks uglier but makes the code easier to
10659 * read/write/debug.
10660 */
10661 SKIP_BLANKS;
10662 name = xmlXPathScanName(ctxt);
10663 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10664#ifdef DEBUG_STEP
10665 xmlGenericError(xmlGenericErrorContext,
10666 "PathExpr: Axis\n");
10667#endif
10668 lc = 1;
10669 xmlFree(name);
10670 } else if (name != NULL) {
10671 int len =xmlStrlen(name);
10672
10673
10674 while (NXT(len) != 0) {
10675 if (NXT(len) == '/') {
10676 /* element name */
10677#ifdef DEBUG_STEP
10678 xmlGenericError(xmlGenericErrorContext,
10679 "PathExpr: AbbrRelLocation\n");
10680#endif
10681 lc = 1;
10682 break;
10683 } else if (IS_BLANK_CH(NXT(len))) {
10684 /* ignore blanks */
10685 ;
10686 } else if (NXT(len) == ':') {
10687#ifdef DEBUG_STEP
10688 xmlGenericError(xmlGenericErrorContext,
10689 "PathExpr: AbbrRelLocation\n");
10690#endif
10691 lc = 1;
10692 break;
10693 } else if ((NXT(len) == '(')) {
10694 /* Note Type or Function */
10695 if (xmlXPathIsNodeType(name)) {
10696#ifdef DEBUG_STEP
10697 xmlGenericError(xmlGenericErrorContext,
10698 "PathExpr: Type search\n");
10699#endif
10700 lc = 1;
10701 } else {
10702#ifdef DEBUG_STEP
10703 xmlGenericError(xmlGenericErrorContext,
10704 "PathExpr: function call\n");
10705#endif
10706 lc = 0;
10707 }
10708 break;
10709 } else if ((NXT(len) == '[')) {
10710 /* element name */
10711#ifdef DEBUG_STEP
10712 xmlGenericError(xmlGenericErrorContext,
10713 "PathExpr: AbbrRelLocation\n");
10714#endif
10715 lc = 1;
10716 break;
10717 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10718 (NXT(len) == '=')) {
10719 lc = 1;
10720 break;
10721 } else {
10722 lc = 1;
10723 break;
10724 }
10725 len++;
10726 }
10727 if (NXT(len) == 0) {
10728#ifdef DEBUG_STEP
10729 xmlGenericError(xmlGenericErrorContext,
10730 "PathExpr: AbbrRelLocation\n");
10731#endif
10732 /* element name */
10733 lc = 1;
10734 }
10735 xmlFree(name);
10736 } else {
10737 /* make sure all cases are covered explicitly */
10738 XP_ERROR(XPATH_EXPR_ERROR);
10739 }
10740 }
10741
10742 if (lc) {
10743 if (CUR == '/') {
10744 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10745 } else {
10746 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10747 }
10748 xmlXPathCompLocationPath(ctxt);
10749 } else {
10750 xmlXPathCompFilterExpr(ctxt);
10751 CHECK_ERROR;
10752 if ((CUR == '/') && (NXT(1) == '/')) {
10753 SKIP(2);
10754 SKIP_BLANKS;
10755
10756 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10757 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10758 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10759
10760 xmlXPathCompRelativeLocationPath(ctxt);
10761 } else if (CUR == '/') {
10762 xmlXPathCompRelativeLocationPath(ctxt);
10763 }
10764 }
10765 SKIP_BLANKS;
10766}
10767
10768/**
10769 * xmlXPathCompUnionExpr:
10770 * @ctxt: the XPath Parser context
10771 *
10772 * [18] UnionExpr ::= PathExpr
10773 * | UnionExpr '|' PathExpr
10774 *
10775 * Compile an union expression.
10776 */
10777
10778static void
10779xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10780 xmlXPathCompPathExpr(ctxt);
10781 CHECK_ERROR;
10782 SKIP_BLANKS;
10783 while (CUR == '|') {
10784 int op1 = ctxt->comp->last;
10785 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10786
10787 NEXT;
10788 SKIP_BLANKS;
10789 xmlXPathCompPathExpr(ctxt);
10790
10791 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10792
10793 SKIP_BLANKS;
10794 }
10795}
10796
10797/**
10798 * xmlXPathCompUnaryExpr:
10799 * @ctxt: the XPath Parser context
10800 *
10801 * [27] UnaryExpr ::= UnionExpr
10802 * | '-' UnaryExpr
10803 *
10804 * Compile an unary expression.
10805 */
10806
10807static void
10808xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10809 int minus = 0;
10810 int found = 0;
10811
10812 SKIP_BLANKS;
10813 while (CUR == '-') {
10814 minus = 1 - minus;
10815 found = 1;
10816 NEXT;
10817 SKIP_BLANKS;
10818 }
10819
10820 xmlXPathCompUnionExpr(ctxt);
10821 CHECK_ERROR;
10822 if (found) {
10823 if (minus)
10824 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10825 else
10826 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10827 }
10828}
10829
10830/**
10831 * xmlXPathCompMultiplicativeExpr:
10832 * @ctxt: the XPath Parser context
10833 *
10834 * [26] MultiplicativeExpr ::= UnaryExpr
10835 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10836 * | MultiplicativeExpr 'div' UnaryExpr
10837 * | MultiplicativeExpr 'mod' UnaryExpr
10838 * [34] MultiplyOperator ::= '*'
10839 *
10840 * Compile an Additive expression.
10841 */
10842
10843static void
10844xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10845 xmlXPathCompUnaryExpr(ctxt);
10846 CHECK_ERROR;
10847 SKIP_BLANKS;
10848 while ((CUR == '*') ||
10849 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10850 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10851 int op = -1;
10852 int op1 = ctxt->comp->last;
10853
10854 if (CUR == '*') {
10855 op = 0;
10856 NEXT;
10857 } else if (CUR == 'd') {
10858 op = 1;
10859 SKIP(3);
10860 } else if (CUR == 'm') {
10861 op = 2;
10862 SKIP(3);
10863 }
10864 SKIP_BLANKS;
10865 xmlXPathCompUnaryExpr(ctxt);
10866 CHECK_ERROR;
10867 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10868 SKIP_BLANKS;
10869 }
10870}
10871
10872/**
10873 * xmlXPathCompAdditiveExpr:
10874 * @ctxt: the XPath Parser context
10875 *
10876 * [25] AdditiveExpr ::= MultiplicativeExpr
10877 * | AdditiveExpr '+' MultiplicativeExpr
10878 * | AdditiveExpr '-' MultiplicativeExpr
10879 *
10880 * Compile an Additive expression.
10881 */
10882
10883static void
10884xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10885
10886 xmlXPathCompMultiplicativeExpr(ctxt);
10887 CHECK_ERROR;
10888 SKIP_BLANKS;
10889 while ((CUR == '+') || (CUR == '-')) {
10890 int plus;
10891 int op1 = ctxt->comp->last;
10892
10893 if (CUR == '+') plus = 1;
10894 else plus = 0;
10895 NEXT;
10896 SKIP_BLANKS;
10897 xmlXPathCompMultiplicativeExpr(ctxt);
10898 CHECK_ERROR;
10899 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10900 SKIP_BLANKS;
10901 }
10902}
10903
10904/**
10905 * xmlXPathCompRelationalExpr:
10906 * @ctxt: the XPath Parser context
10907 *
10908 * [24] RelationalExpr ::= AdditiveExpr
10909 * | RelationalExpr '<' AdditiveExpr
10910 * | RelationalExpr '>' AdditiveExpr
10911 * | RelationalExpr '<=' AdditiveExpr
10912 * | RelationalExpr '>=' AdditiveExpr
10913 *
10914 * A <= B > C is allowed ? Answer from James, yes with
10915 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10916 * which is basically what got implemented.
10917 *
10918 * Compile a Relational expression, then push the result
10919 * on the stack
10920 */
10921
10922static void
10923xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10924 xmlXPathCompAdditiveExpr(ctxt);
10925 CHECK_ERROR;
10926 SKIP_BLANKS;
10927 while ((CUR == '<') ||
10928 (CUR == '>') ||
10929 ((CUR == '<') && (NXT(1) == '=')) ||
10930 ((CUR == '>') && (NXT(1) == '='))) {
10931 int inf, strict;
10932 int op1 = ctxt->comp->last;
10933
10934 if (CUR == '<') inf = 1;
10935 else inf = 0;
10936 if (NXT(1) == '=') strict = 0;
10937 else strict = 1;
10938 NEXT;
10939 if (!strict) NEXT;
10940 SKIP_BLANKS;
10941 xmlXPathCompAdditiveExpr(ctxt);
10942 CHECK_ERROR;
10943 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10944 SKIP_BLANKS;
10945 }
10946}
10947
10948/**
10949 * xmlXPathCompEqualityExpr:
10950 * @ctxt: the XPath Parser context
10951 *
10952 * [23] EqualityExpr ::= RelationalExpr
10953 * | EqualityExpr '=' RelationalExpr
10954 * | EqualityExpr '!=' RelationalExpr
10955 *
10956 * A != B != C is allowed ? Answer from James, yes with
10957 * (RelationalExpr = RelationalExpr) = RelationalExpr
10958 * (RelationalExpr != RelationalExpr) != RelationalExpr
10959 * which is basically what got implemented.
10960 *
10961 * Compile an Equality expression.
10962 *
10963 */
10964static void
10965xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10966 xmlXPathCompRelationalExpr(ctxt);
10967 CHECK_ERROR;
10968 SKIP_BLANKS;
10969 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10970 int eq;
10971 int op1 = ctxt->comp->last;
10972
10973 if (CUR == '=') eq = 1;
10974 else eq = 0;
10975 NEXT;
10976 if (!eq) NEXT;
10977 SKIP_BLANKS;
10978 xmlXPathCompRelationalExpr(ctxt);
10979 CHECK_ERROR;
10980 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10981 SKIP_BLANKS;
10982 }
10983}
10984
10985/**
10986 * xmlXPathCompAndExpr:
10987 * @ctxt: the XPath Parser context
10988 *
10989 * [22] AndExpr ::= EqualityExpr
10990 * | AndExpr 'and' EqualityExpr
10991 *
10992 * Compile an AND expression.
10993 *
10994 */
10995static void
10996xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10997 xmlXPathCompEqualityExpr(ctxt);
10998 CHECK_ERROR;
10999 SKIP_BLANKS;
11000 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11001 int op1 = ctxt->comp->last;
11002 SKIP(3);
11003 SKIP_BLANKS;
11004 xmlXPathCompEqualityExpr(ctxt);
11005 CHECK_ERROR;
11006 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11007 SKIP_BLANKS;
11008 }
11009}
11010
11011/**
11012 * xmlXPathCompileExpr:
11013 * @ctxt: the XPath Parser context
11014 *
11015 * [14] Expr ::= OrExpr
11016 * [21] OrExpr ::= AndExpr
11017 * | OrExpr 'or' AndExpr
11018 *
11019 * Parse and compile an expression
11020 */
11021static void
11022xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11023 xmlXPathCompAndExpr(ctxt);
11024 CHECK_ERROR;
11025 SKIP_BLANKS;
11026 while ((CUR == 'o') && (NXT(1) == 'r')) {
11027 int op1 = ctxt->comp->last;
11028 SKIP(2);
11029 SKIP_BLANKS;
11030 xmlXPathCompAndExpr(ctxt);
11031 CHECK_ERROR;
11032 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11033 SKIP_BLANKS;
11034 }
11035 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11036 /* more ops could be optimized too */
11037 /*
11038 * This is the main place to eliminate sorting for
11039 * operations which don't require a sorted node-set.
11040 * E.g. count().
11041 */
11042 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11043 }
11044}
11045
11046/**
11047 * xmlXPathCompPredicate:
11048 * @ctxt: the XPath Parser context
11049 * @filter: act as a filter
11050 *
11051 * [8] Predicate ::= '[' PredicateExpr ']'
11052 * [9] PredicateExpr ::= Expr
11053 *
11054 * Compile a predicate expression
11055 */
11056static void
11057xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11058 int op1 = ctxt->comp->last;
11059
11060 SKIP_BLANKS;
11061 if (CUR != '[') {
11062 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11063 }
11064 NEXT;
11065 SKIP_BLANKS;
11066
11067 ctxt->comp->last = -1;
11068 /*
11069 * This call to xmlXPathCompileExpr() will deactivate sorting
11070 * of the predicate result.
11071 * TODO: Sorting is still activated for filters, since I'm not
11072 * sure if needed. Normally sorting should not be needed, since
11073 * a filter can only diminish the number of items in a sequence,
11074 * but won't change its order; so if the initial sequence is sorted,
11075 * subsequent sorting is not needed.
11076 */
11077 if (! filter)
11078 xmlXPathCompileExpr(ctxt, 0);
11079 else
11080 xmlXPathCompileExpr(ctxt, 1);
11081 CHECK_ERROR;
11082
11083 if (CUR != ']') {
11084 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11085 }
11086
11087 if (filter)
11088 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11089 else
11090 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11091
11092 NEXT;
11093 SKIP_BLANKS;
11094}
11095
11096/**
11097 * xmlXPathCompNodeTest:
11098 * @ctxt: the XPath Parser context
11099 * @test: pointer to a xmlXPathTestVal
11100 * @type: pointer to a xmlXPathTypeVal
11101 * @prefix: placeholder for a possible name prefix
11102 *
11103 * [7] NodeTest ::= NameTest
11104 * | NodeType '(' ')'
11105 * | 'processing-instruction' '(' Literal ')'
11106 *
11107 * [37] NameTest ::= '*'
11108 * | NCName ':' '*'
11109 * | QName
11110 * [38] NodeType ::= 'comment'
11111 * | 'text'
11112 * | 'processing-instruction'
11113 * | 'node'
11114 *
11115 * Returns the name found and updates @test, @type and @prefix appropriately
11116 */
11117static xmlChar *
11118xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11119 xmlXPathTypeVal *type, const xmlChar **prefix,
11120 xmlChar *name) {
11121 int blanks;
11122
11123 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11124 STRANGE;
11125 return(NULL);
11126 }
11127 *type = (xmlXPathTypeVal) 0;
11128 *test = (xmlXPathTestVal) 0;
11129 *prefix = NULL;
11130 SKIP_BLANKS;
11131
11132 if ((name == NULL) && (CUR == '*')) {
11133 /*
11134 * All elements
11135 */
11136 NEXT;
11137 *test = NODE_TEST_ALL;
11138 return(NULL);
11139 }
11140
11141 if (name == NULL)
11142 name = xmlXPathParseNCName(ctxt);
11143 if (name == NULL) {
11144 XP_ERRORNULL(XPATH_EXPR_ERROR);
11145 }
11146
11147 blanks = IS_BLANK_CH(CUR);
11148 SKIP_BLANKS;
11149 if (CUR == '(') {
11150 NEXT;
11151 /*
11152 * NodeType or PI search
11153 */
11154 if (xmlStrEqual(name, BAD_CAST "comment"))
11155 *type = NODE_TYPE_COMMENT;
11156 else if (xmlStrEqual(name, BAD_CAST "node"))
11157 *type = NODE_TYPE_NODE;
11158 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11159 *type = NODE_TYPE_PI;
11160 else if (xmlStrEqual(name, BAD_CAST "text"))
11161 *type = NODE_TYPE_TEXT;
11162 else {
11163 if (name != NULL)
11164 xmlFree(name);
11165 XP_ERRORNULL(XPATH_EXPR_ERROR);
11166 }
11167
11168 *test = NODE_TEST_TYPE;
11169
11170 SKIP_BLANKS;
11171 if (*type == NODE_TYPE_PI) {
11172 /*
11173 * Specific case: search a PI by name.
11174 */
11175 if (name != NULL)
11176 xmlFree(name);
11177 name = NULL;
11178 if (CUR != ')') {
11179 name = xmlXPathParseLiteral(ctxt);
11180 CHECK_ERROR NULL;
11181 *test = NODE_TEST_PI;
11182 SKIP_BLANKS;
11183 }
11184 }
11185 if (CUR != ')') {
11186 if (name != NULL)
11187 xmlFree(name);
11188 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11189 }
11190 NEXT;
11191 return(name);
11192 }
11193 *test = NODE_TEST_NAME;
11194 if ((!blanks) && (CUR == ':')) {
11195 NEXT;
11196
11197 /*
11198 * Since currently the parser context don't have a
11199 * namespace list associated:
11200 * The namespace name for this prefix can be computed
11201 * only at evaluation time. The compilation is done
11202 * outside of any context.
11203 */
11204#if 0
11205 *prefix = xmlXPathNsLookup(ctxt->context, name);
11206 if (name != NULL)
11207 xmlFree(name);
11208 if (*prefix == NULL) {
11209 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11210 }
11211#else
11212 *prefix = name;
11213#endif
11214
11215 if (CUR == '*') {
11216 /*
11217 * All elements
11218 */
11219 NEXT;
11220 *test = NODE_TEST_ALL;
11221 return(NULL);
11222 }
11223
11224 name = xmlXPathParseNCName(ctxt);
11225 if (name == NULL) {
11226 XP_ERRORNULL(XPATH_EXPR_ERROR);
11227 }
11228 }
11229 return(name);
11230}
11231
11232/**
11233 * xmlXPathIsAxisName:
11234 * @name: a preparsed name token
11235 *
11236 * [6] AxisName ::= 'ancestor'
11237 * | 'ancestor-or-self'
11238 * | 'attribute'
11239 * | 'child'
11240 * | 'descendant'
11241 * | 'descendant-or-self'
11242 * | 'following'
11243 * | 'following-sibling'
11244 * | 'namespace'
11245 * | 'parent'
11246 * | 'preceding'
11247 * | 'preceding-sibling'
11248 * | 'self'
11249 *
11250 * Returns the axis or 0
11251 */
11252static xmlXPathAxisVal
11253xmlXPathIsAxisName(const xmlChar *name) {
11254 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11255 switch (name[0]) {
11256 case 'a':
11257 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11258 ret = AXIS_ANCESTOR;
11259 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11260 ret = AXIS_ANCESTOR_OR_SELF;
11261 if (xmlStrEqual(name, BAD_CAST "attribute"))
11262 ret = AXIS_ATTRIBUTE;
11263 break;
11264 case 'c':
11265 if (xmlStrEqual(name, BAD_CAST "child"))
11266 ret = AXIS_CHILD;
11267 break;
11268 case 'd':
11269 if (xmlStrEqual(name, BAD_CAST "descendant"))
11270 ret = AXIS_DESCENDANT;
11271 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11272 ret = AXIS_DESCENDANT_OR_SELF;
11273 break;
11274 case 'f':
11275 if (xmlStrEqual(name, BAD_CAST "following"))
11276 ret = AXIS_FOLLOWING;
11277 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11278 ret = AXIS_FOLLOWING_SIBLING;
11279 break;
11280 case 'n':
11281 if (xmlStrEqual(name, BAD_CAST "namespace"))
11282 ret = AXIS_NAMESPACE;
11283 break;
11284 case 'p':
11285 if (xmlStrEqual(name, BAD_CAST "parent"))
11286 ret = AXIS_PARENT;
11287 if (xmlStrEqual(name, BAD_CAST "preceding"))
11288 ret = AXIS_PRECEDING;
11289 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11290 ret = AXIS_PRECEDING_SIBLING;
11291 break;
11292 case 's':
11293 if (xmlStrEqual(name, BAD_CAST "self"))
11294 ret = AXIS_SELF;
11295 break;
11296 }
11297 return(ret);
11298}
11299
11300/**
11301 * xmlXPathCompStep:
11302 * @ctxt: the XPath Parser context
11303 *
11304 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11305 * | AbbreviatedStep
11306 *
11307 * [12] AbbreviatedStep ::= '.' | '..'
11308 *
11309 * [5] AxisSpecifier ::= AxisName '::'
11310 * | AbbreviatedAxisSpecifier
11311 *
11312 * [13] AbbreviatedAxisSpecifier ::= '@'?
11313 *
11314 * Modified for XPtr range support as:
11315 *
11316 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11317 * | AbbreviatedStep
11318 * | 'range-to' '(' Expr ')' Predicate*
11319 *
11320 * Compile one step in a Location Path
11321 * A location step of . is short for self::node(). This is
11322 * particularly useful in conjunction with //. For example, the
11323 * location path .//para is short for
11324 * self::node()/descendant-or-self::node()/child::para
11325 * and so will select all para descendant elements of the context
11326 * node.
11327 * Similarly, a location step of .. is short for parent::node().
11328 * For example, ../title is short for parent::node()/child::title
11329 * and so will select the title children of the parent of the context
11330 * node.
11331 */
11332static void
11333xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11334#ifdef LIBXML_XPTR_ENABLED
11335 int rangeto = 0;
11336 int op2 = -1;
11337#endif
11338
11339 SKIP_BLANKS;
11340 if ((CUR == '.') && (NXT(1) == '.')) {
11341 SKIP(2);
11342 SKIP_BLANKS;
11343 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11344 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11345 } else if (CUR == '.') {
11346 NEXT;
11347 SKIP_BLANKS;
11348 } else {
11349 xmlChar *name = NULL;
11350 const xmlChar *prefix = NULL;
11351 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11352 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11353 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11354 int op1;
11355
11356 /*
11357 * The modification needed for XPointer change to the production
11358 */
11359#ifdef LIBXML_XPTR_ENABLED
11360 if (ctxt->xptr) {
11361 name = xmlXPathParseNCName(ctxt);
11362 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11363 op2 = ctxt->comp->last;
11364 xmlFree(name);
11365 SKIP_BLANKS;
11366 if (CUR != '(') {
11367 XP_ERROR(XPATH_EXPR_ERROR);
11368 }
11369 NEXT;
11370 SKIP_BLANKS;
11371
11372 xmlXPathCompileExpr(ctxt, 1);
11373 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11374 CHECK_ERROR;
11375
11376 SKIP_BLANKS;
11377 if (CUR != ')') {
11378 XP_ERROR(XPATH_EXPR_ERROR);
11379 }
11380 NEXT;
11381 rangeto = 1;
11382 goto eval_predicates;
11383 }
11384 }
11385#endif
11386 if (CUR == '*') {
11387 axis = AXIS_CHILD;
11388 } else {
11389 if (name == NULL)
11390 name = xmlXPathParseNCName(ctxt);
11391 if (name != NULL) {
11392 axis = xmlXPathIsAxisName(name);
11393 if (axis != 0) {
11394 SKIP_BLANKS;
11395 if ((CUR == ':') && (NXT(1) == ':')) {
11396 SKIP(2);
11397 xmlFree(name);
11398 name = NULL;
11399 } else {
11400 /* an element name can conflict with an axis one :-\ */
11401 axis = AXIS_CHILD;
11402 }
11403 } else {
11404 axis = AXIS_CHILD;
11405 }
11406 } else if (CUR == '@') {
11407 NEXT;
11408 axis = AXIS_ATTRIBUTE;
11409 } else {
11410 axis = AXIS_CHILD;
11411 }
11412 }
11413
11414 if (ctxt->error != XPATH_EXPRESSION_OK) {
11415 xmlFree(name);
11416 return;
11417 }
11418
11419 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11420 if (test == 0)
11421 return;
11422
11423 if ((prefix != NULL) && (ctxt->context != NULL) &&
11424 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11425 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11426 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11427 }
11428 }
11429#ifdef DEBUG_STEP
11430 xmlGenericError(xmlGenericErrorContext,
11431 "Basis : computing new set\n");
11432#endif
11433
11434#ifdef DEBUG_STEP
11435 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11436 if (ctxt->value == NULL)
11437 xmlGenericError(xmlGenericErrorContext, "no value\n");
11438 else if (ctxt->value->nodesetval == NULL)
11439 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11440 else
11441 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11442#endif
11443
11444#ifdef LIBXML_XPTR_ENABLED
11445eval_predicates:
11446#endif
11447 op1 = ctxt->comp->last;
11448 ctxt->comp->last = -1;
11449
11450 SKIP_BLANKS;
11451 while (CUR == '[') {
11452 xmlXPathCompPredicate(ctxt, 0);
11453 }
11454
11455#ifdef LIBXML_XPTR_ENABLED
11456 if (rangeto) {
11457 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11458 } else
11459#endif
11460 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11461 test, type, (void *)prefix, (void *)name);
11462
11463 }
11464#ifdef DEBUG_STEP
11465 xmlGenericError(xmlGenericErrorContext, "Step : ");
11466 if (ctxt->value == NULL)
11467 xmlGenericError(xmlGenericErrorContext, "no value\n");
11468 else if (ctxt->value->nodesetval == NULL)
11469 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11470 else
11471 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11472 ctxt->value->nodesetval);
11473#endif
11474}
11475
11476/**
11477 * xmlXPathCompRelativeLocationPath:
11478 * @ctxt: the XPath Parser context
11479 *
11480 * [3] RelativeLocationPath ::= Step
11481 * | RelativeLocationPath '/' Step
11482 * | AbbreviatedRelativeLocationPath
11483 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11484 *
11485 * Compile a relative location path.
11486 */
11487static void
11488xmlXPathCompRelativeLocationPath
11489(xmlXPathParserContextPtr ctxt) {
11490 SKIP_BLANKS;
11491 if ((CUR == '/') && (NXT(1) == '/')) {
11492 SKIP(2);
11493 SKIP_BLANKS;
11494 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11495 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11496 } else if (CUR == '/') {
11497 NEXT;
11498 SKIP_BLANKS;
11499 }
11500 xmlXPathCompStep(ctxt);
11501 CHECK_ERROR;
11502 SKIP_BLANKS;
11503 while (CUR == '/') {
11504 if ((CUR == '/') && (NXT(1) == '/')) {
11505 SKIP(2);
11506 SKIP_BLANKS;
11507 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11508 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11509 xmlXPathCompStep(ctxt);
11510 } else if (CUR == '/') {
11511 NEXT;
11512 SKIP_BLANKS;
11513 xmlXPathCompStep(ctxt);
11514 }
11515 SKIP_BLANKS;
11516 }
11517}
11518
11519/**
11520 * xmlXPathCompLocationPath:
11521 * @ctxt: the XPath Parser context
11522 *
11523 * [1] LocationPath ::= RelativeLocationPath
11524 * | AbsoluteLocationPath
11525 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11526 * | AbbreviatedAbsoluteLocationPath
11527 * [10] AbbreviatedAbsoluteLocationPath ::=
11528 * '//' RelativeLocationPath
11529 *
11530 * Compile a location path
11531 *
11532 * // is short for /descendant-or-self::node()/. For example,
11533 * //para is short for /descendant-or-self::node()/child::para and
11534 * so will select any para element in the document (even a para element
11535 * that is a document element will be selected by //para since the
11536 * document element node is a child of the root node); div//para is
11537 * short for div/descendant-or-self::node()/child::para and so will
11538 * select all para descendants of div children.
11539 */
11540static void
11541xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11542 SKIP_BLANKS;
11543 if (CUR != '/') {
11544 xmlXPathCompRelativeLocationPath(ctxt);
11545 } else {
11546 while (CUR == '/') {
11547 if ((CUR == '/') && (NXT(1) == '/')) {
11548 SKIP(2);
11549 SKIP_BLANKS;
11550 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11551 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11552 xmlXPathCompRelativeLocationPath(ctxt);
11553 } else if (CUR == '/') {
11554 NEXT;
11555 SKIP_BLANKS;
11556 if ((CUR != 0 ) &&
11557 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11558 (CUR == '@') || (CUR == '*')))
11559 xmlXPathCompRelativeLocationPath(ctxt);
11560 }
11561 CHECK_ERROR;
11562 }
11563 }
11564}
11565
11566/************************************************************************
11567 * *
11568 * XPath precompiled expression evaluation *
11569 * *
11570 ************************************************************************/
11571
11572static int
11573xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11574
11575#ifdef DEBUG_STEP
11576static void
11577xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11578 int nbNodes)
11579{
11580 xmlGenericError(xmlGenericErrorContext, "new step : ");
11581 switch (op->value) {
11582 case AXIS_ANCESTOR:
11583 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11584 break;
11585 case AXIS_ANCESTOR_OR_SELF:
11586 xmlGenericError(xmlGenericErrorContext,
11587 "axis 'ancestors-or-self' ");
11588 break;
11589 case AXIS_ATTRIBUTE:
11590 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11591 break;
11592 case AXIS_CHILD:
11593 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11594 break;
11595 case AXIS_DESCENDANT:
11596 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11597 break;
11598 case AXIS_DESCENDANT_OR_SELF:
11599 xmlGenericError(xmlGenericErrorContext,
11600 "axis 'descendant-or-self' ");
11601 break;
11602 case AXIS_FOLLOWING:
11603 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11604 break;
11605 case AXIS_FOLLOWING_SIBLING:
11606 xmlGenericError(xmlGenericErrorContext,
11607 "axis 'following-siblings' ");
11608 break;
11609 case AXIS_NAMESPACE:
11610 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11611 break;
11612 case AXIS_PARENT:
11613 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11614 break;
11615 case AXIS_PRECEDING:
11616 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11617 break;
11618 case AXIS_PRECEDING_SIBLING:
11619 xmlGenericError(xmlGenericErrorContext,
11620 "axis 'preceding-sibling' ");
11621 break;
11622 case AXIS_SELF:
11623 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11624 break;
11625 }
11626 xmlGenericError(xmlGenericErrorContext,
11627 " context contains %d nodes\n", nbNodes);
11628 switch (op->value2) {
11629 case NODE_TEST_NONE:
11630 xmlGenericError(xmlGenericErrorContext,
11631 " searching for none !!!\n");
11632 break;
11633 case NODE_TEST_TYPE:
11634 xmlGenericError(xmlGenericErrorContext,
11635 " searching for type %d\n", op->value3);
11636 break;
11637 case NODE_TEST_PI:
11638 xmlGenericError(xmlGenericErrorContext,
11639 " searching for PI !!!\n");
11640 break;
11641 case NODE_TEST_ALL:
11642 xmlGenericError(xmlGenericErrorContext,
11643 " searching for *\n");
11644 break;
11645 case NODE_TEST_NS:
11646 xmlGenericError(xmlGenericErrorContext,
11647 " searching for namespace %s\n",
11648 op->value5);
11649 break;
11650 case NODE_TEST_NAME:
11651 xmlGenericError(xmlGenericErrorContext,
11652 " searching for name %s\n", op->value5);
11653 if (op->value4)
11654 xmlGenericError(xmlGenericErrorContext,
11655 " with namespace %s\n", op->value4);
11656 break;
11657 }
11658 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11659}
11660#endif /* DEBUG_STEP */
11661
11662static int
11663xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11664 xmlXPathStepOpPtr op,
11665 xmlNodeSetPtr set,
11666 int contextSize,
11667 int hasNsNodes)
11668{
11669 if (op->ch1 != -1) {
11670 xmlXPathCompExprPtr comp = ctxt->comp;
11671 /*
11672 * Process inner predicates first.
11673 */
11674 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11675 /*
11676 * TODO: raise an internal error.
11677 */
11678 }
11679 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11680 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11681 CHECK_ERROR0;
11682 if (contextSize <= 0)
11683 return(0);
11684 }
11685 if (op->ch2 != -1) {
11686 xmlXPathContextPtr xpctxt = ctxt->context;
11687 xmlNodePtr contextNode, oldContextNode;
11688 xmlDocPtr oldContextDoc;
11689 int i, res, contextPos = 0, newContextSize;
11690 xmlXPathStepOpPtr exprOp;
11691 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11692
11693#ifdef LIBXML_XPTR_ENABLED
11694 /*
11695 * URGENT TODO: Check the following:
11696 * We don't expect location sets if evaluating prediates, right?
11697 * Only filters should expect location sets, right?
11698 */
11699#endif
11700 /*
11701 * SPEC XPath 1.0:
11702 * "For each node in the node-set to be filtered, the
11703 * PredicateExpr is evaluated with that node as the
11704 * context node, with the number of nodes in the
11705 * node-set as the context size, and with the proximity
11706 * position of the node in the node-set with respect to
11707 * the axis as the context position;"
11708 * @oldset is the node-set" to be filtered.
11709 *
11710 * SPEC XPath 1.0:
11711 * "only predicates change the context position and
11712 * context size (see [2.4 Predicates])."
11713 * Example:
11714 * node-set context pos
11715 * nA 1
11716 * nB 2
11717 * nC 3
11718 * After applying predicate [position() > 1] :
11719 * node-set context pos
11720 * nB 1
11721 * nC 2
11722 */
11723 oldContextNode = xpctxt->node;
11724 oldContextDoc = xpctxt->doc;
11725 /*
11726 * Get the expression of this predicate.
11727 */
11728 exprOp = &ctxt->comp->steps[op->ch2];
11729 newContextSize = 0;
11730 for (i = 0; i < set->nodeNr; i++) {
11731 if (set->nodeTab[i] == NULL)
11732 continue;
11733
11734 contextNode = set->nodeTab[i];
11735 xpctxt->node = contextNode;
11736 xpctxt->contextSize = contextSize;
11737 xpctxt->proximityPosition = ++contextPos;
11738
11739 /*
11740 * Also set the xpath document in case things like
11741 * key() are evaluated in the predicate.
11742 */
11743 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11744 (contextNode->doc != NULL))
11745 xpctxt->doc = contextNode->doc;
11746 /*
11747 * Evaluate the predicate expression with 1 context node
11748 * at a time; this node is packaged into a node set; this
11749 * node set is handed over to the evaluation mechanism.
11750 */
11751 if (contextObj == NULL)
11752 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11753 else {
11754 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11755 contextNode) < 0) {
11756 ctxt->error = XPATH_MEMORY_ERROR;
11757 goto evaluation_exit;
11758 }
11759 }
11760
11761 valuePush(ctxt, contextObj);
11762
11763 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11764
11765 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11766 xmlXPathNodeSetClear(set, hasNsNodes);
11767 newContextSize = 0;
11768 goto evaluation_exit;
11769 }
11770
11771 if (res != 0) {
11772 newContextSize++;
11773 } else {
11774 /*
11775 * Remove the entry from the initial node set.
11776 */
11777 set->nodeTab[i] = NULL;
11778 if (contextNode->type == XML_NAMESPACE_DECL)
11779 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11780 }
11781 if (ctxt->value == contextObj) {
11782 /*
11783 * Don't free the temporary XPath object holding the
11784 * context node, in order to avoid massive recreation
11785 * inside this loop.
11786 */
11787 valuePop(ctxt);
11788 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11789 } else {
11790 /*
11791 * TODO: The object was lost in the evaluation machinery.
11792 * Can this happen? Maybe in internal-error cases.
11793 */
11794 contextObj = NULL;
11795 }
11796 }
11797
11798 if (contextObj != NULL) {
11799 if (ctxt->value == contextObj)
11800 valuePop(ctxt);
11801 xmlXPathReleaseObject(xpctxt, contextObj);
11802 }
11803evaluation_exit:
11804 if (exprRes != NULL)
11805 xmlXPathReleaseObject(ctxt->context, exprRes);
11806 /*
11807 * Reset/invalidate the context.
11808 */
11809 xpctxt->node = oldContextNode;
11810 xpctxt->doc = oldContextDoc;
11811 xpctxt->contextSize = -1;
11812 xpctxt->proximityPosition = -1;
11813 return(newContextSize);
11814 }
11815 return(contextSize);
11816}
11817
11818static int
11819xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11820 xmlXPathStepOpPtr op,
11821 xmlNodeSetPtr set,
11822 int contextSize,
11823 int minPos,
11824 int maxPos,
11825 int hasNsNodes)
11826{
11827 if (op->ch1 != -1) {
11828 xmlXPathCompExprPtr comp = ctxt->comp;
11829 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11830 /*
11831 * TODO: raise an internal error.
11832 */
11833 }
11834 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11835 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11836 CHECK_ERROR0;
11837 if (contextSize <= 0)
11838 return(0);
11839 }
11840 /*
11841 * Check if the node set contains a sufficient number of nodes for
11842 * the requested range.
11843 */
11844 if (contextSize < minPos) {
11845 xmlXPathNodeSetClear(set, hasNsNodes);
11846 return(0);
11847 }
11848 if (op->ch2 == -1) {
11849 /*
11850 * TODO: Can this ever happen?
11851 */
11852 return (contextSize);
11853 } else {
11854 xmlDocPtr oldContextDoc;
11855 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11856 xmlXPathStepOpPtr exprOp;
11857 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11858 xmlNodePtr oldContextNode, contextNode = NULL;
11859 xmlXPathContextPtr xpctxt = ctxt->context;
11860 int frame;
11861
11862#ifdef LIBXML_XPTR_ENABLED
11863 /*
11864 * URGENT TODO: Check the following:
11865 * We don't expect location sets if evaluating prediates, right?
11866 * Only filters should expect location sets, right?
11867 */
11868#endif /* LIBXML_XPTR_ENABLED */
11869
11870 /*
11871 * Save old context.
11872 */
11873 oldContextNode = xpctxt->node;
11874 oldContextDoc = xpctxt->doc;
11875 /*
11876 * Get the expression of this predicate.
11877 */
11878 exprOp = &ctxt->comp->steps[op->ch2];
11879 for (i = 0; i < set->nodeNr; i++) {
11880 xmlXPathObjectPtr tmp;
11881
11882 if (set->nodeTab[i] == NULL)
11883 continue;
11884
11885 contextNode = set->nodeTab[i];
11886 xpctxt->node = contextNode;
11887 xpctxt->contextSize = contextSize;
11888 xpctxt->proximityPosition = ++contextPos;
11889
11890 /*
11891 * Initialize the new set.
11892 * Also set the xpath document in case things like
11893 * key() evaluation are attempted on the predicate
11894 */
11895 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11896 (contextNode->doc != NULL))
11897 xpctxt->doc = contextNode->doc;
11898 /*
11899 * Evaluate the predicate expression with 1 context node
11900 * at a time; this node is packaged into a node set; this
11901 * node set is handed over to the evaluation mechanism.
11902 */
11903 if (contextObj == NULL)
11904 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11905 else {
11906 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11907 contextNode) < 0) {
11908 ctxt->error = XPATH_MEMORY_ERROR;
11909 goto evaluation_exit;
11910 }
11911 }
11912
11913 frame = xmlXPathSetFrame(ctxt);
11914 valuePush(ctxt, contextObj);
11915 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11916 tmp = valuePop(ctxt);
11917 xmlXPathPopFrame(ctxt, frame);
11918
11919 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11920 while (tmp != contextObj) {
11921 /*
11922 * Free up the result
11923 * then pop off contextObj, which will be freed later
11924 */
11925 xmlXPathReleaseObject(xpctxt, tmp);
11926 tmp = valuePop(ctxt);
11927 }
11928 goto evaluation_error;
11929 }
11930 /* push the result back onto the stack */
11931 valuePush(ctxt, tmp);
11932
11933 if (res)
11934 pos++;
11935
11936 if (res && (pos >= minPos) && (pos <= maxPos)) {
11937 /*
11938 * Fits in the requested range.
11939 */
11940 newContextSize++;
11941 if (minPos == maxPos) {
11942 /*
11943 * Only 1 node was requested.
11944 */
11945 if (contextNode->type == XML_NAMESPACE_DECL) {
11946 /*
11947 * As always: take care of those nasty
11948 * namespace nodes.
11949 */
11950 set->nodeTab[i] = NULL;
11951 }
11952 xmlXPathNodeSetClear(set, hasNsNodes);
11953 set->nodeNr = 1;
11954 set->nodeTab[0] = contextNode;
11955 goto evaluation_exit;
11956 }
11957 if (pos == maxPos) {
11958 /*
11959 * We are done.
11960 */
11961 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11962 goto evaluation_exit;
11963 }
11964 } else {
11965 /*
11966 * Remove the entry from the initial node set.
11967 */
11968 set->nodeTab[i] = NULL;
11969 if (contextNode->type == XML_NAMESPACE_DECL)
11970 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11971 }
11972 if (exprRes != NULL) {
11973 xmlXPathReleaseObject(ctxt->context, exprRes);
11974 exprRes = NULL;
11975 }
11976 if (ctxt->value == contextObj) {
11977 /*
11978 * Don't free the temporary XPath object holding the
11979 * context node, in order to avoid massive recreation
11980 * inside this loop.
11981 */
11982 valuePop(ctxt);
11983 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11984 } else {
11985 /*
11986 * The object was lost in the evaluation machinery.
11987 * Can this happen? Maybe in case of internal-errors.
11988 */
11989 contextObj = NULL;
11990 }
11991 }
11992 goto evaluation_exit;
11993
11994evaluation_error:
11995 xmlXPathNodeSetClear(set, hasNsNodes);
11996 newContextSize = 0;
11997
11998evaluation_exit:
11999 if (contextObj != NULL) {
12000 if (ctxt->value == contextObj)
12001 valuePop(ctxt);
12002 xmlXPathReleaseObject(xpctxt, contextObj);
12003 }
12004 if (exprRes != NULL)
12005 xmlXPathReleaseObject(ctxt->context, exprRes);
12006 /*
12007 * Reset/invalidate the context.
12008 */
12009 xpctxt->node = oldContextNode;
12010 xpctxt->doc = oldContextDoc;
12011 xpctxt->contextSize = -1;
12012 xpctxt->proximityPosition = -1;
12013 return(newContextSize);
12014 }
12015 return(contextSize);
12016}
12017
12018static int
12019xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12020 xmlXPathStepOpPtr op,
12021 int *maxPos)
12022{
12023
12024 xmlXPathStepOpPtr exprOp;
12025
12026 /*
12027 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12028 */
12029
12030 /*
12031 * If not -1, then ch1 will point to:
12032 * 1) For predicates (XPATH_OP_PREDICATE):
12033 * - an inner predicate operator
12034 * 2) For filters (XPATH_OP_FILTER):
12035 * - an inner filter operater OR
12036 * - an expression selecting the node set.
12037 * E.g. "key('a', 'b')" or "(//foo | //bar)".
12038 */
12039 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12040 return(0);
12041
12042 if (op->ch2 != -1) {
12043 exprOp = &ctxt->comp->steps[op->ch2];
12044 } else
12045 return(0);
12046
12047 if ((exprOp != NULL) &&
12048 (exprOp->op == XPATH_OP_VALUE) &&
12049 (exprOp->value4 != NULL) &&
12050 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12051 {
12052 /*
12053 * We have a "[n]" predicate here.
12054 * TODO: Unfortunately this simplistic test here is not
12055 * able to detect a position() predicate in compound
12056 * expressions like "[@attr = 'a" and position() = 1],
12057 * and even not the usage of position() in
12058 * "[position() = 1]"; thus - obviously - a position-range,
12059 * like it "[position() < 5]", is also not detected.
12060 * Maybe we could rewrite the AST to ease the optimization.
12061 */
12062 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12063
12064 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12065 (float) *maxPos)
12066 {
12067 return(1);
12068 }
12069 }
12070 return(0);
12071}
12072
12073static int
12074xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12075 xmlXPathStepOpPtr op,
12076 xmlNodePtr * first, xmlNodePtr * last,
12077 int toBool)
12078{
12079
12080#define XP_TEST_HIT \
12081 if (hasAxisRange != 0) { \
12082 if (++pos == maxPos) { \
12083 if (addNode(seq, cur) < 0) \
12084 ctxt->error = XPATH_MEMORY_ERROR; \
12085 goto axis_range_end; } \
12086 } else { \
12087 if (addNode(seq, cur) < 0) \
12088 ctxt->error = XPATH_MEMORY_ERROR; \
12089 if (breakOnFirstHit) goto first_hit; }
12090
12091#define XP_TEST_HIT_NS \
12092 if (hasAxisRange != 0) { \
12093 if (++pos == maxPos) { \
12094 hasNsNodes = 1; \
12095 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12096 ctxt->error = XPATH_MEMORY_ERROR; \
12097 goto axis_range_end; } \
12098 } else { \
12099 hasNsNodes = 1; \
12100 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12101 ctxt->error = XPATH_MEMORY_ERROR; \
12102 if (breakOnFirstHit) goto first_hit; }
12103
12104 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12105 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12106 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12107 const xmlChar *prefix = op->value4;
12108 const xmlChar *name = op->value5;
12109 const xmlChar *URI = NULL;
12110
12111#ifdef DEBUG_STEP
12112 int nbMatches = 0, prevMatches = 0;
12113#endif
12114 int total = 0, hasNsNodes = 0;
12115 /* The popped object holding the context nodes */
12116 xmlXPathObjectPtr obj;
12117 /* The set of context nodes for the node tests */
12118 xmlNodeSetPtr contextSeq;
12119 int contextIdx;
12120 xmlNodePtr contextNode;
12121 /* The final resulting node set wrt to all context nodes */
12122 xmlNodeSetPtr outSeq;
12123 /*
12124 * The temporary resulting node set wrt 1 context node.
12125 * Used to feed predicate evaluation.
12126 */
12127 xmlNodeSetPtr seq;
12128 xmlNodePtr cur;
12129 /* First predicate operator */
12130 xmlXPathStepOpPtr predOp;
12131 int maxPos; /* The requested position() (when a "[n]" predicate) */
12132 int hasPredicateRange, hasAxisRange, pos, size, newSize;
12133 int breakOnFirstHit;
12134
12135 xmlXPathTraversalFunction next = NULL;
12136 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12137 xmlXPathNodeSetMergeFunction mergeAndClear;
12138 xmlNodePtr oldContextNode;
12139 xmlXPathContextPtr xpctxt = ctxt->context;
12140
12141
12142 CHECK_TYPE0(XPATH_NODESET);
12143 obj = valuePop(ctxt);
12144 /*
12145 * Setup namespaces.
12146 */
12147 if (prefix != NULL) {
12148 URI = xmlXPathNsLookup(xpctxt, prefix);
12149 if (URI == NULL) {
12150 xmlXPathReleaseObject(xpctxt, obj);
12151 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12152 }
12153 }
12154 /*
12155 * Setup axis.
12156 *
12157 * MAYBE FUTURE TODO: merging optimizations:
12158 * - If the nodes to be traversed wrt to the initial nodes and
12159 * the current axis cannot overlap, then we could avoid searching
12160 * for duplicates during the merge.
12161 * But the question is how/when to evaluate if they cannot overlap.
12162 * Example: if we know that for two initial nodes, the one is
12163 * not in the ancestor-or-self axis of the other, then we could safely
12164 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12165 * the descendant-or-self axis.
12166 */
12167 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12168 switch (axis) {
12169 case AXIS_ANCESTOR:
12170 first = NULL;
12171 next = xmlXPathNextAncestor;
12172 break;
12173 case AXIS_ANCESTOR_OR_SELF:
12174 first = NULL;
12175 next = xmlXPathNextAncestorOrSelf;
12176 break;
12177 case AXIS_ATTRIBUTE:
12178 first = NULL;
12179 last = NULL;
12180 next = xmlXPathNextAttribute;
12181 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12182 break;
12183 case AXIS_CHILD:
12184 last = NULL;
12185 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12186 (type == NODE_TYPE_NODE))
12187 {
12188 /*
12189 * Optimization if an element node type is 'element'.
12190 */
12191 next = xmlXPathNextChildElement;
12192 } else
12193 next = xmlXPathNextChild;
12194 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12195 break;
12196 case AXIS_DESCENDANT:
12197 last = NULL;
12198 next = xmlXPathNextDescendant;
12199 break;
12200 case AXIS_DESCENDANT_OR_SELF:
12201 last = NULL;
12202 next = xmlXPathNextDescendantOrSelf;
12203 break;
12204 case AXIS_FOLLOWING:
12205 last = NULL;
12206 next = xmlXPathNextFollowing;
12207 break;
12208 case AXIS_FOLLOWING_SIBLING:
12209 last = NULL;
12210 next = xmlXPathNextFollowingSibling;
12211 break;
12212 case AXIS_NAMESPACE:
12213 first = NULL;
12214 last = NULL;
12215 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12216 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12217 break;
12218 case AXIS_PARENT:
12219 first = NULL;
12220 next = xmlXPathNextParent;
12221 break;
12222 case AXIS_PRECEDING:
12223 first = NULL;
12224 next = xmlXPathNextPrecedingInternal;
12225 break;
12226 case AXIS_PRECEDING_SIBLING:
12227 first = NULL;
12228 next = xmlXPathNextPrecedingSibling;
12229 break;
12230 case AXIS_SELF:
12231 first = NULL;
12232 last = NULL;
12233 next = xmlXPathNextSelf;
12234 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12235 break;
12236 }
12237
12238#ifdef DEBUG_STEP
12239 xmlXPathDebugDumpStepAxis(op,
12240 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12241#endif
12242
12243 if (next == NULL) {
12244 xmlXPathReleaseObject(xpctxt, obj);
12245 return(0);
12246 }
12247 contextSeq = obj->nodesetval;
12248 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12249 xmlXPathReleaseObject(xpctxt, obj);
12250 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12251 return(0);
12252 }
12253 /*
12254 * Predicate optimization ---------------------------------------------
12255 * If this step has a last predicate, which contains a position(),
12256 * then we'll optimize (although not exactly "position()", but only
12257 * the short-hand form, i.e., "[n]".
12258 *
12259 * Example - expression "/foo[parent::bar][1]":
12260 *
12261 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12262 * ROOT -- op->ch1
12263 * PREDICATE -- op->ch2 (predOp)
12264 * PREDICATE -- predOp->ch1 = [parent::bar]
12265 * SORT
12266 * COLLECT 'parent' 'name' 'node' bar
12267 * NODE
12268 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12269 *
12270 */
12271 maxPos = 0;
12272 predOp = NULL;
12273 hasPredicateRange = 0;
12274 hasAxisRange = 0;
12275 if (op->ch2 != -1) {
12276 /*
12277 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12278 */
12279 predOp = &ctxt->comp->steps[op->ch2];
12280 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12281 if (predOp->ch1 != -1) {
12282 /*
12283 * Use the next inner predicate operator.
12284 */
12285 predOp = &ctxt->comp->steps[predOp->ch1];
12286 hasPredicateRange = 1;
12287 } else {
12288 /*
12289 * There's no other predicate than the [n] predicate.
12290 */
12291 predOp = NULL;
12292 hasAxisRange = 1;
12293 }
12294 }
12295 }
12296 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12297 /*
12298 * Axis traversal -----------------------------------------------------
12299 */
12300 /*
12301 * 2.3 Node Tests
12302 * - For the attribute axis, the principal node type is attribute.
12303 * - For the namespace axis, the principal node type is namespace.
12304 * - For other axes, the principal node type is element.
12305 *
12306 * A node test * is true for any node of the
12307 * principal node type. For example, child::* will
12308 * select all element children of the context node
12309 */
12310 oldContextNode = xpctxt->node;
12311 addNode = xmlXPathNodeSetAddUnique;
12312 outSeq = NULL;
12313 seq = NULL;
12314 contextNode = NULL;
12315 contextIdx = 0;
12316
12317
12318 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12319 (ctxt->error == XPATH_EXPRESSION_OK)) {
12320 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12321
12322 if (seq == NULL) {
12323 seq = xmlXPathNodeSetCreate(NULL);
12324 if (seq == NULL) {
12325 total = 0;
12326 goto error;
12327 }
12328 }
12329 /*
12330 * Traverse the axis and test the nodes.
12331 */
12332 pos = 0;
12333 cur = NULL;
12334 hasNsNodes = 0;
12335 do {
12336 cur = next(ctxt, cur);
12337 if (cur == NULL)
12338 break;
12339
12340 /*
12341 * QUESTION TODO: What does the "first" and "last" stuff do?
12342 */
12343 if ((first != NULL) && (*first != NULL)) {
12344 if (*first == cur)
12345 break;
12346 if (((total % 256) == 0) &&
12347#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12348 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12349#else
12350 (xmlXPathCmpNodes(*first, cur) >= 0))
12351#endif
12352 {
12353 break;
12354 }
12355 }
12356 if ((last != NULL) && (*last != NULL)) {
12357 if (*last == cur)
12358 break;
12359 if (((total % 256) == 0) &&
12360#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12361 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12362#else
12363 (xmlXPathCmpNodes(cur, *last) >= 0))
12364#endif
12365 {
12366 break;
12367 }
12368 }
12369
12370 total++;
12371
12372#ifdef DEBUG_STEP
12373 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12374#endif
12375
12376 switch (test) {
12377 case NODE_TEST_NONE:
12378 total = 0;
12379 STRANGE
12380 goto error;
12381 case NODE_TEST_TYPE:
12382 /*
12383 * TODO: Don't we need to use
12384 * xmlXPathNodeSetAddNs() for namespace nodes here?
12385 * Surprisingly, some c14n tests fail, if we do this.
12386 */
12387 if (type == NODE_TYPE_NODE) {
12388 switch (cur->type) {
12389 case XML_DOCUMENT_NODE:
12390 case XML_HTML_DOCUMENT_NODE:
12391#ifdef LIBXML_DOCB_ENABLED
12392 case XML_DOCB_DOCUMENT_NODE:
12393#endif
12394 case XML_ELEMENT_NODE:
12395 case XML_ATTRIBUTE_NODE:
12396 case XML_PI_NODE:
12397 case XML_COMMENT_NODE:
12398 case XML_CDATA_SECTION_NODE:
12399 case XML_TEXT_NODE:
12400 case XML_NAMESPACE_DECL:
12401 XP_TEST_HIT
12402 break;
12403 default:
12404 break;
12405 }
12406 } else if (cur->type == type) {
12407 if (cur->type == XML_NAMESPACE_DECL)
12408 XP_TEST_HIT_NS
12409 else
12410 XP_TEST_HIT
12411 } else if ((type == NODE_TYPE_TEXT) &&
12412 (cur->type == XML_CDATA_SECTION_NODE))
12413 {
12414 XP_TEST_HIT
12415 }
12416 break;
12417 case NODE_TEST_PI:
12418 if ((cur->type == XML_PI_NODE) &&
12419 ((name == NULL) || xmlStrEqual(name, cur->name)))
12420 {
12421 XP_TEST_HIT
12422 }
12423 break;
12424 case NODE_TEST_ALL:
12425 if (axis == AXIS_ATTRIBUTE) {
12426 if (cur->type == XML_ATTRIBUTE_NODE)
12427 {
12428 if (prefix == NULL)
12429 {
12430 XP_TEST_HIT
12431 } else if ((cur->ns != NULL) &&
12432 (xmlStrEqual(URI, cur->ns->href)))
12433 {
12434 XP_TEST_HIT
12435 }
12436 }
12437 } else if (axis == AXIS_NAMESPACE) {
12438 if (cur->type == XML_NAMESPACE_DECL)
12439 {
12440 XP_TEST_HIT_NS
12441 }
12442 } else {
12443 if (cur->type == XML_ELEMENT_NODE) {
12444 if (prefix == NULL)
12445 {
12446 XP_TEST_HIT
12447
12448 } else if ((cur->ns != NULL) &&
12449 (xmlStrEqual(URI, cur->ns->href)))
12450 {
12451 XP_TEST_HIT
12452 }
12453 }
12454 }
12455 break;
12456 case NODE_TEST_NS:{
12457 TODO;
12458 break;
12459 }
12460 case NODE_TEST_NAME:
12461 if (axis == AXIS_ATTRIBUTE) {
12462 if (cur->type != XML_ATTRIBUTE_NODE)
12463 break;
12464 } else if (axis == AXIS_NAMESPACE) {
12465 if (cur->type != XML_NAMESPACE_DECL)
12466 break;
12467 } else {
12468 if (cur->type != XML_ELEMENT_NODE)
12469 break;
12470 }
12471 switch (cur->type) {
12472 case XML_ELEMENT_NODE:
12473 if (xmlStrEqual(name, cur->name)) {
12474 if (prefix == NULL) {
12475 if (cur->ns == NULL)
12476 {
12477 XP_TEST_HIT
12478 }
12479 } else {
12480 if ((cur->ns != NULL) &&
12481 (xmlStrEqual(URI, cur->ns->href)))
12482 {
12483 XP_TEST_HIT
12484 }
12485 }
12486 }
12487 break;
12488 case XML_ATTRIBUTE_NODE:{
12489 xmlAttrPtr attr = (xmlAttrPtr) cur;
12490
12491 if (xmlStrEqual(name, attr->name)) {
12492 if (prefix == NULL) {
12493 if ((attr->ns == NULL) ||
12494 (attr->ns->prefix == NULL))
12495 {
12496 XP_TEST_HIT
12497 }
12498 } else {
12499 if ((attr->ns != NULL) &&
12500 (xmlStrEqual(URI,
12501 attr->ns->href)))
12502 {
12503 XP_TEST_HIT
12504 }
12505 }
12506 }
12507 break;
12508 }
12509 case XML_NAMESPACE_DECL:
12510 if (cur->type == XML_NAMESPACE_DECL) {
12511 xmlNsPtr ns = (xmlNsPtr) cur;
12512
12513 if ((ns->prefix != NULL) && (name != NULL)
12514 && (xmlStrEqual(ns->prefix, name)))
12515 {
12516 XP_TEST_HIT_NS
12517 }
12518 }
12519 break;
12520 default:
12521 break;
12522 }
12523 break;
12524 } /* switch(test) */
12525 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12526
12527 goto apply_predicates;
12528
12529axis_range_end: /* ----------------------------------------------------- */
12530 /*
12531 * We have a "/foo[n]", and position() = n was reached.
12532 * Note that we can have as well "/foo/::parent::foo[1]", so
12533 * a duplicate-aware merge is still needed.
12534 * Merge with the result.
12535 */
12536 if (outSeq == NULL) {
12537 outSeq = seq;
12538 seq = NULL;
12539 } else
12540 outSeq = mergeAndClear(outSeq, seq, 0);
12541 /*
12542 * Break if only a true/false result was requested.
12543 */
12544 if (toBool)
12545 break;
12546 continue;
12547
12548first_hit: /* ---------------------------------------------------------- */
12549 /*
12550 * Break if only a true/false result was requested and
12551 * no predicates existed and a node test succeeded.
12552 */
12553 if (outSeq == NULL) {
12554 outSeq = seq;
12555 seq = NULL;
12556 } else
12557 outSeq = mergeAndClear(outSeq, seq, 0);
12558 break;
12559
12560#ifdef DEBUG_STEP
12561 if (seq != NULL)
12562 nbMatches += seq->nodeNr;
12563#endif
12564
12565apply_predicates: /* --------------------------------------------------- */
12566 if (ctxt->error != XPATH_EXPRESSION_OK)
12567 goto error;
12568
12569 /*
12570 * Apply predicates.
12571 */
12572 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12573 /*
12574 * E.g. when we have a "/foo[some expression][n]".
12575 */
12576 /*
12577 * QUESTION TODO: The old predicate evaluation took into
12578 * account location-sets.
12579 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12580 * Do we expect such a set here?
12581 * All what I learned now from the evaluation semantics
12582 * does not indicate that a location-set will be processed
12583 * here, so this looks OK.
12584 */
12585 /*
12586 * Iterate over all predicates, starting with the outermost
12587 * predicate.
12588 * TODO: Problem: we cannot execute the inner predicates first
12589 * since we cannot go back *up* the operator tree!
12590 * Options we have:
12591 * 1) Use of recursive functions (like is it currently done
12592 * via xmlXPathCompOpEval())
12593 * 2) Add a predicate evaluation information stack to the
12594 * context struct
12595 * 3) Change the way the operators are linked; we need a
12596 * "parent" field on xmlXPathStepOp
12597 *
12598 * For the moment, I'll try to solve this with a recursive
12599 * function: xmlXPathCompOpEvalPredicate().
12600 */
12601 size = seq->nodeNr;
12602 if (hasPredicateRange != 0)
12603 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12604 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12605 else
12606 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12607 predOp, seq, size, hasNsNodes);
12608
12609 if (ctxt->error != XPATH_EXPRESSION_OK) {
12610 total = 0;
12611 goto error;
12612 }
12613 /*
12614 * Add the filtered set of nodes to the result node set.
12615 */
12616 if (newSize == 0) {
12617 /*
12618 * The predicates filtered all nodes out.
12619 */
12620 xmlXPathNodeSetClear(seq, hasNsNodes);
12621 } else if (seq->nodeNr > 0) {
12622 /*
12623 * Add to result set.
12624 */
12625 if (outSeq == NULL) {
12626 if (size != newSize) {
12627 /*
12628 * We need to merge and clear here, since
12629 * the sequence will contained NULLed entries.
12630 */
12631 outSeq = mergeAndClear(NULL, seq, 1);
12632 } else {
12633 outSeq = seq;
12634 seq = NULL;
12635 }
12636 } else
12637 outSeq = mergeAndClear(outSeq, seq,
12638 (size != newSize) ? 1: 0);
12639 /*
12640 * Break if only a true/false result was requested.
12641 */
12642 if (toBool)
12643 break;
12644 }
12645 } else if (seq->nodeNr > 0) {
12646 /*
12647 * Add to result set.
12648 */
12649 if (outSeq == NULL) {
12650 outSeq = seq;
12651 seq = NULL;
12652 } else {
12653 outSeq = mergeAndClear(outSeq, seq, 0);
12654 }
12655 }
12656 }
12657
12658error:
12659 if ((obj->boolval) && (obj->user != NULL)) {
12660 /*
12661 * QUESTION TODO: What does this do and why?
12662 * TODO: Do we have to do this also for the "error"
12663 * cleanup further down?
12664 */
12665 ctxt->value->boolval = 1;
12666 ctxt->value->user = obj->user;
12667 obj->user = NULL;
12668 obj->boolval = 0;
12669 }
12670 xmlXPathReleaseObject(xpctxt, obj);
12671
12672 /*
12673 * Ensure we return at least an emtpy set.
12674 */
12675 if (outSeq == NULL) {
12676 if ((seq != NULL) && (seq->nodeNr == 0))
12677 outSeq = seq;
12678 else
12679 outSeq = xmlXPathNodeSetCreate(NULL);
12680 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12681 }
12682 if ((seq != NULL) && (seq != outSeq)) {
12683 xmlXPathFreeNodeSet(seq);
12684 }
12685 /*
12686 * Hand over the result. Better to push the set also in
12687 * case of errors.
12688 */
12689 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12690 /*
12691 * Reset the context node.
12692 */
12693 xpctxt->node = oldContextNode;
12694
12695#ifdef DEBUG_STEP
12696 xmlGenericError(xmlGenericErrorContext,
12697 "\nExamined %d nodes, found %d nodes at that step\n",
12698 total, nbMatches);
12699#endif
12700
12701 return(total);
12702}
12703
12704static int
12705xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12706 xmlXPathStepOpPtr op, xmlNodePtr * first);
12707
12708/**
12709 * xmlXPathCompOpEvalFirst:
12710 * @ctxt: the XPath parser context with the compiled expression
12711 * @op: an XPath compiled operation
12712 * @first: the first elem found so far
12713 *
12714 * Evaluate the Precompiled XPath operation searching only the first
12715 * element in document order
12716 *
12717 * Returns the number of examined objects.
12718 */
12719static int
12720xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12721 xmlXPathStepOpPtr op, xmlNodePtr * first)
12722{
12723 int total = 0, cur;
12724 xmlXPathCompExprPtr comp;
12725 xmlXPathObjectPtr arg1, arg2;
12726
12727 CHECK_ERROR0;
12728 comp = ctxt->comp;
12729 switch (op->op) {
12730 case XPATH_OP_END:
12731 return (0);
12732 case XPATH_OP_UNION:
12733 total =
12734 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12735 first);
12736 CHECK_ERROR0;
12737 if ((ctxt->value != NULL)
12738 && (ctxt->value->type == XPATH_NODESET)
12739 && (ctxt->value->nodesetval != NULL)
12740 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12741 /*
12742 * limit tree traversing to first node in the result
12743 */
12744 /*
12745 * OPTIMIZE TODO: This implicitely sorts
12746 * the result, even if not needed. E.g. if the argument
12747 * of the count() function, no sorting is needed.
12748 * OPTIMIZE TODO: How do we know if the node-list wasn't
12749 * aready sorted?
12750 */
12751 if (ctxt->value->nodesetval->nodeNr > 1)
12752 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12753 *first = ctxt->value->nodesetval->nodeTab[0];
12754 }
12755 cur =
12756 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12757 first);
12758 CHECK_ERROR0;
12759 CHECK_TYPE0(XPATH_NODESET);
12760 arg2 = valuePop(ctxt);
12761
12762 CHECK_TYPE0(XPATH_NODESET);
12763 arg1 = valuePop(ctxt);
12764
12765 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12766 arg2->nodesetval);
12767 valuePush(ctxt, arg1);
12768 xmlXPathReleaseObject(ctxt->context, arg2);
12769 /* optimizer */
12770 if (total > cur)
12771 xmlXPathCompSwap(op);
12772 return (total + cur);
12773 case XPATH_OP_ROOT:
12774 xmlXPathRoot(ctxt);
12775 return (0);
12776 case XPATH_OP_NODE:
12777 if (op->ch1 != -1)
12778 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12779 CHECK_ERROR0;
12780 if (op->ch2 != -1)
12781 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12782 CHECK_ERROR0;
12783 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12784 ctxt->context->node));
12785 return (total);
12786 case XPATH_OP_RESET:
12787 if (op->ch1 != -1)
12788 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12789 CHECK_ERROR0;
12790 if (op->ch2 != -1)
12791 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12792 CHECK_ERROR0;
12793 ctxt->context->node = NULL;
12794 return (total);
12795 case XPATH_OP_COLLECT:{
12796 if (op->ch1 == -1)
12797 return (total);
12798
12799 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12800 CHECK_ERROR0;
12801
12802 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12803 return (total);
12804 }
12805 case XPATH_OP_VALUE:
12806 valuePush(ctxt,
12807 xmlXPathCacheObjectCopy(ctxt->context,
12808 (xmlXPathObjectPtr) op->value4));
12809 return (0);
12810 case XPATH_OP_SORT:
12811 if (op->ch1 != -1)
12812 total +=
12813 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12814 first);
12815 CHECK_ERROR0;
12816 if ((ctxt->value != NULL)
12817 && (ctxt->value->type == XPATH_NODESET)
12818 && (ctxt->value->nodesetval != NULL)
12819 && (ctxt->value->nodesetval->nodeNr > 1))
12820 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12821 return (total);
12822#ifdef XP_OPTIMIZED_FILTER_FIRST
12823 case XPATH_OP_FILTER:
12824 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12825 return (total);
12826#endif
12827 default:
12828 return (xmlXPathCompOpEval(ctxt, op));
12829 }
12830}
12831
12832/**
12833 * xmlXPathCompOpEvalLast:
12834 * @ctxt: the XPath parser context with the compiled expression
12835 * @op: an XPath compiled operation
12836 * @last: the last elem found so far
12837 *
12838 * Evaluate the Precompiled XPath operation searching only the last
12839 * element in document order
12840 *
12841 * Returns the number of nodes traversed
12842 */
12843static int
12844xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12845 xmlNodePtr * last)
12846{
12847 int total = 0, cur;
12848 xmlXPathCompExprPtr comp;
12849 xmlXPathObjectPtr arg1, arg2;
12850 xmlNodePtr bak;
12851 xmlDocPtr bakd;
12852 int pp;
12853 int cs;
12854
12855 CHECK_ERROR0;
12856 comp = ctxt->comp;
12857 switch (op->op) {
12858 case XPATH_OP_END:
12859 return (0);
12860 case XPATH_OP_UNION:
12861 bakd = ctxt->context->doc;
12862 bak = ctxt->context->node;
12863 pp = ctxt->context->proximityPosition;
12864 cs = ctxt->context->contextSize;
12865 total =
12866 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12867 CHECK_ERROR0;
12868 if ((ctxt->value != NULL)
12869 && (ctxt->value->type == XPATH_NODESET)
12870 && (ctxt->value->nodesetval != NULL)
12871 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12872 /*
12873 * limit tree traversing to first node in the result
12874 */
12875 if (ctxt->value->nodesetval->nodeNr > 1)
12876 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12877 *last =
12878 ctxt->value->nodesetval->nodeTab[ctxt->value->
12879 nodesetval->nodeNr -
12880 1];
12881 }
12882 ctxt->context->doc = bakd;
12883 ctxt->context->node = bak;
12884 ctxt->context->proximityPosition = pp;
12885 ctxt->context->contextSize = cs;
12886 cur =
12887 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12888 CHECK_ERROR0;
12889 if ((ctxt->value != NULL)
12890 && (ctxt->value->type == XPATH_NODESET)
12891 && (ctxt->value->nodesetval != NULL)
12892 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12893 }
12894 CHECK_TYPE0(XPATH_NODESET);
12895 arg2 = valuePop(ctxt);
12896
12897 CHECK_TYPE0(XPATH_NODESET);
12898 arg1 = valuePop(ctxt);
12899
12900 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12901 arg2->nodesetval);
12902 valuePush(ctxt, arg1);
12903 xmlXPathReleaseObject(ctxt->context, arg2);
12904 /* optimizer */
12905 if (total > cur)
12906 xmlXPathCompSwap(op);
12907 return (total + cur);
12908 case XPATH_OP_ROOT:
12909 xmlXPathRoot(ctxt);
12910 return (0);
12911 case XPATH_OP_NODE:
12912 if (op->ch1 != -1)
12913 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12914 CHECK_ERROR0;
12915 if (op->ch2 != -1)
12916 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12917 CHECK_ERROR0;
12918 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12919 ctxt->context->node));
12920 return (total);
12921 case XPATH_OP_RESET:
12922 if (op->ch1 != -1)
12923 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12924 CHECK_ERROR0;
12925 if (op->ch2 != -1)
12926 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12927 CHECK_ERROR0;
12928 ctxt->context->node = NULL;
12929 return (total);
12930 case XPATH_OP_COLLECT:{
12931 if (op->ch1 == -1)
12932 return (0);
12933
12934 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12935 CHECK_ERROR0;
12936
12937 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12938 return (total);
12939 }
12940 case XPATH_OP_VALUE:
12941 valuePush(ctxt,
12942 xmlXPathCacheObjectCopy(ctxt->context,
12943 (xmlXPathObjectPtr) op->value4));
12944 return (0);
12945 case XPATH_OP_SORT:
12946 if (op->ch1 != -1)
12947 total +=
12948 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12949 last);
12950 CHECK_ERROR0;
12951 if ((ctxt->value != NULL)
12952 && (ctxt->value->type == XPATH_NODESET)
12953 && (ctxt->value->nodesetval != NULL)
12954 && (ctxt->value->nodesetval->nodeNr > 1))
12955 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12956 return (total);
12957 default:
12958 return (xmlXPathCompOpEval(ctxt, op));
12959 }
12960}
12961
12962#ifdef XP_OPTIMIZED_FILTER_FIRST
12963static int
12964xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12965 xmlXPathStepOpPtr op, xmlNodePtr * first)
12966{
12967 int total = 0;
12968 xmlXPathCompExprPtr comp;
12969 xmlXPathObjectPtr res;
12970 xmlXPathObjectPtr obj;
12971 xmlNodeSetPtr oldset;
12972 xmlNodePtr oldnode;
12973 xmlDocPtr oldDoc;
12974 int i;
12975
12976 CHECK_ERROR0;
12977 comp = ctxt->comp;
12978 /*
12979 * Optimization for ()[last()] selection i.e. the last elem
12980 */
12981 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12982 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12983 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12984 int f = comp->steps[op->ch2].ch1;
12985
12986 if ((f != -1) &&
12987 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12988 (comp->steps[f].value5 == NULL) &&
12989 (comp->steps[f].value == 0) &&
12990 (comp->steps[f].value4 != NULL) &&
12991 (xmlStrEqual
12992 (comp->steps[f].value4, BAD_CAST "last"))) {
12993 xmlNodePtr last = NULL;
12994
12995 total +=
12996 xmlXPathCompOpEvalLast(ctxt,
12997 &comp->steps[op->ch1],
12998 &last);
12999 CHECK_ERROR0;
13000 /*
13001 * The nodeset should be in document order,
13002 * Keep only the last value
13003 */
13004 if ((ctxt->value != NULL) &&
13005 (ctxt->value->type == XPATH_NODESET) &&
13006 (ctxt->value->nodesetval != NULL) &&
13007 (ctxt->value->nodesetval->nodeTab != NULL) &&
13008 (ctxt->value->nodesetval->nodeNr > 1)) {
13009 ctxt->value->nodesetval->nodeTab[0] =
13010 ctxt->value->nodesetval->nodeTab[ctxt->
13011 value->
13012 nodesetval->
13013 nodeNr -
13014 1];
13015 ctxt->value->nodesetval->nodeNr = 1;
13016 *first = *(ctxt->value->nodesetval->nodeTab);
13017 }
13018 return (total);
13019 }
13020 }
13021
13022 if (op->ch1 != -1)
13023 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13024 CHECK_ERROR0;
13025 if (op->ch2 == -1)
13026 return (total);
13027 if (ctxt->value == NULL)
13028 return (total);
13029
13030#ifdef LIBXML_XPTR_ENABLED
13031 oldnode = ctxt->context->node;
13032 /*
13033 * Hum are we filtering the result of an XPointer expression
13034 */
13035 if (ctxt->value->type == XPATH_LOCATIONSET) {
13036 xmlXPathObjectPtr tmp = NULL;
13037 xmlLocationSetPtr newlocset = NULL;
13038 xmlLocationSetPtr oldlocset;
13039
13040 /*
13041 * Extract the old locset, and then evaluate the result of the
13042 * expression for all the element in the locset. use it to grow
13043 * up a new locset.
13044 */
13045 CHECK_TYPE0(XPATH_LOCATIONSET);
13046 obj = valuePop(ctxt);
13047 oldlocset = obj->user;
13048 ctxt->context->node = NULL;
13049
13050 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13051 ctxt->context->contextSize = 0;
13052 ctxt->context->proximityPosition = 0;
13053 if (op->ch2 != -1)
13054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13055 res = valuePop(ctxt);
13056 if (res != NULL) {
13057 xmlXPathReleaseObject(ctxt->context, res);
13058 }
13059 valuePush(ctxt, obj);
13060 CHECK_ERROR0;
13061 return (total);
13062 }
13063 newlocset = xmlXPtrLocationSetCreate(NULL);
13064
13065 for (i = 0; i < oldlocset->locNr; i++) {
13066 /*
13067 * Run the evaluation with a node list made of a
13068 * single item in the nodelocset.
13069 */
13070 ctxt->context->node = oldlocset->locTab[i]->user;
13071 ctxt->context->contextSize = oldlocset->locNr;
13072 ctxt->context->proximityPosition = i + 1;
13073 if (tmp == NULL) {
13074 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13075 ctxt->context->node);
13076 } else {
13077 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13078 ctxt->context->node) < 0) {
13079 ctxt->error = XPATH_MEMORY_ERROR;
13080 }
13081 }
13082 valuePush(ctxt, tmp);
13083 if (op->ch2 != -1)
13084 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13085 if (ctxt->error != XPATH_EXPRESSION_OK) {
13086 xmlXPathFreeObject(obj);
13087 return(0);
13088 }
13089 /*
13090 * The result of the evaluation need to be tested to
13091 * decided whether the filter succeeded or not
13092 */
13093 res = valuePop(ctxt);
13094 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13095 xmlXPtrLocationSetAdd(newlocset,
13096 xmlXPathCacheObjectCopy(ctxt->context,
13097 oldlocset->locTab[i]));
13098 }
13099 /*
13100 * Cleanup
13101 */
13102 if (res != NULL) {
13103 xmlXPathReleaseObject(ctxt->context, res);
13104 }
13105 if (ctxt->value == tmp) {
13106 valuePop(ctxt);
13107 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13108 /*
13109 * REVISIT TODO: Don't create a temporary nodeset
13110 * for everly iteration.
13111 */
13112 /* OLD: xmlXPathFreeObject(res); */
13113 } else
13114 tmp = NULL;
13115 ctxt->context->node = NULL;
13116 /*
13117 * Only put the first node in the result, then leave.
13118 */
13119 if (newlocset->locNr > 0) {
13120 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13121 break;
13122 }
13123 }
13124 if (tmp != NULL) {
13125 xmlXPathReleaseObject(ctxt->context, tmp);
13126 }
13127 /*
13128 * The result is used as the new evaluation locset.
13129 */
13130 xmlXPathReleaseObject(ctxt->context, obj);
13131 ctxt->context->node = NULL;
13132 ctxt->context->contextSize = -1;
13133 ctxt->context->proximityPosition = -1;
13134 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13135 ctxt->context->node = oldnode;
13136 return (total);
13137 }
13138#endif /* LIBXML_XPTR_ENABLED */
13139
13140 /*
13141 * Extract the old set, and then evaluate the result of the
13142 * expression for all the element in the set. use it to grow
13143 * up a new set.
13144 */
13145 CHECK_TYPE0(XPATH_NODESET);
13146 obj = valuePop(ctxt);
13147 oldset = obj->nodesetval;
13148
13149 oldnode = ctxt->context->node;
13150 oldDoc = ctxt->context->doc;
13151 ctxt->context->node = NULL;
13152
13153 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13154 ctxt->context->contextSize = 0;
13155 ctxt->context->proximityPosition = 0;
13156 /* QUESTION TODO: Why was this code commented out?
13157 if (op->ch2 != -1)
13158 total +=
13159 xmlXPathCompOpEval(ctxt,
13160 &comp->steps[op->ch2]);
13161 CHECK_ERROR0;
13162 res = valuePop(ctxt);
13163 if (res != NULL)
13164 xmlXPathFreeObject(res);
13165 */
13166 valuePush(ctxt, obj);
13167 ctxt->context->node = oldnode;
13168 CHECK_ERROR0;
13169 } else {
13170 xmlNodeSetPtr newset;
13171 xmlXPathObjectPtr tmp = NULL;
13172 /*
13173 * Initialize the new set.
13174 * Also set the xpath document in case things like
13175 * key() evaluation are attempted on the predicate
13176 */
13177 newset = xmlXPathNodeSetCreate(NULL);
13178 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13179
13180 for (i = 0; i < oldset->nodeNr; i++) {
13181 /*
13182 * Run the evaluation with a node list made of
13183 * a single item in the nodeset.
13184 */
13185 ctxt->context->node = oldset->nodeTab[i];
13186 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13187 (oldset->nodeTab[i]->doc != NULL))
13188 ctxt->context->doc = oldset->nodeTab[i]->doc;
13189 if (tmp == NULL) {
13190 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13191 ctxt->context->node);
13192 } else {
13193 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13194 ctxt->context->node) < 0) {
13195 ctxt->error = XPATH_MEMORY_ERROR;
13196 }
13197 }
13198 valuePush(ctxt, tmp);
13199 ctxt->context->contextSize = oldset->nodeNr;
13200 ctxt->context->proximityPosition = i + 1;
13201 if (op->ch2 != -1)
13202 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13203 if (ctxt->error != XPATH_EXPRESSION_OK) {
13204 xmlXPathFreeNodeSet(newset);
13205 xmlXPathFreeObject(obj);
13206 return(0);
13207 }
13208 /*
13209 * The result of the evaluation needs to be tested to
13210 * decide whether the filter succeeded or not
13211 */
13212 res = valuePop(ctxt);
13213 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13214 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13215 ctxt->error = XPATH_MEMORY_ERROR;
13216 }
13217 /*
13218 * Cleanup
13219 */
13220 if (res != NULL) {
13221 xmlXPathReleaseObject(ctxt->context, res);
13222 }
13223 if (ctxt->value == tmp) {
13224 valuePop(ctxt);
13225 /*
13226 * Don't free the temporary nodeset
13227 * in order to avoid massive recreation inside this
13228 * loop.
13229 */
13230 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13231 } else
13232 tmp = NULL;
13233 ctxt->context->node = NULL;
13234 /*
13235 * Only put the first node in the result, then leave.
13236 */
13237 if (newset->nodeNr > 0) {
13238 *first = *(newset->nodeTab);
13239 break;
13240 }
13241 }
13242 if (tmp != NULL) {
13243 xmlXPathReleaseObject(ctxt->context, tmp);
13244 }
13245 /*
13246 * The result is used as the new evaluation set.
13247 */
13248 xmlXPathReleaseObject(ctxt->context, obj);
13249 ctxt->context->node = NULL;
13250 ctxt->context->contextSize = -1;
13251 ctxt->context->proximityPosition = -1;
13252 /* may want to move this past the '}' later */
13253 ctxt->context->doc = oldDoc;
13254 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13255 }
13256 ctxt->context->node = oldnode;
13257 return(total);
13258}
13259#endif /* XP_OPTIMIZED_FILTER_FIRST */
13260
13261/**
13262 * xmlXPathCompOpEval:
13263 * @ctxt: the XPath parser context with the compiled expression
13264 * @op: an XPath compiled operation
13265 *
13266 * Evaluate the Precompiled XPath operation
13267 * Returns the number of nodes traversed
13268 */
13269static int
13270xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13271{
13272 int total = 0;
13273 int equal, ret;
13274 xmlXPathCompExprPtr comp;
13275 xmlXPathObjectPtr arg1, arg2;
13276 xmlNodePtr bak;
13277 xmlDocPtr bakd;
13278 int pp;
13279 int cs;
13280
13281 CHECK_ERROR0;
13282 comp = ctxt->comp;
13283 switch (op->op) {
13284 case XPATH_OP_END:
13285 return (0);
13286 case XPATH_OP_AND:
13287 bakd = ctxt->context->doc;
13288 bak = ctxt->context->node;
13289 pp = ctxt->context->proximityPosition;
13290 cs = ctxt->context->contextSize;
13291 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13292 CHECK_ERROR0;
13293 xmlXPathBooleanFunction(ctxt, 1);
13294 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13295 return (total);
13296 arg2 = valuePop(ctxt);
13297 ctxt->context->doc = bakd;
13298 ctxt->context->node = bak;
13299 ctxt->context->proximityPosition = pp;
13300 ctxt->context->contextSize = cs;
13301 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13302 if (ctxt->error) {
13303 xmlXPathFreeObject(arg2);
13304 return(0);
13305 }
13306 xmlXPathBooleanFunction(ctxt, 1);
13307 arg1 = valuePop(ctxt);
13308 arg1->boolval &= arg2->boolval;
13309 valuePush(ctxt, arg1);
13310 xmlXPathReleaseObject(ctxt->context, arg2);
13311 return (total);
13312 case XPATH_OP_OR:
13313 bakd = ctxt->context->doc;
13314 bak = ctxt->context->node;
13315 pp = ctxt->context->proximityPosition;
13316 cs = ctxt->context->contextSize;
13317 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13318 CHECK_ERROR0;
13319 xmlXPathBooleanFunction(ctxt, 1);
13320 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13321 return (total);
13322 arg2 = valuePop(ctxt);
13323 ctxt->context->doc = bakd;
13324 ctxt->context->node = bak;
13325 ctxt->context->proximityPosition = pp;
13326 ctxt->context->contextSize = cs;
13327 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13328 if (ctxt->error) {
13329 xmlXPathFreeObject(arg2);
13330 return(0);
13331 }
13332 xmlXPathBooleanFunction(ctxt, 1);
13333 arg1 = valuePop(ctxt);
13334 arg1->boolval |= arg2->boolval;
13335 valuePush(ctxt, arg1);
13336 xmlXPathReleaseObject(ctxt->context, arg2);
13337 return (total);
13338 case XPATH_OP_EQUAL:
13339 bakd = ctxt->context->doc;
13340 bak = ctxt->context->node;
13341 pp = ctxt->context->proximityPosition;
13342 cs = ctxt->context->contextSize;
13343 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13344 CHECK_ERROR0;
13345 ctxt->context->doc = bakd;
13346 ctxt->context->node = bak;
13347 ctxt->context->proximityPosition = pp;
13348 ctxt->context->contextSize = cs;
13349 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13350 CHECK_ERROR0;
13351 if (op->value)
13352 equal = xmlXPathEqualValues(ctxt);
13353 else
13354 equal = xmlXPathNotEqualValues(ctxt);
13355 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13356 return (total);
13357 case XPATH_OP_CMP:
13358 bakd = ctxt->context->doc;
13359 bak = ctxt->context->node;
13360 pp = ctxt->context->proximityPosition;
13361 cs = ctxt->context->contextSize;
13362 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13363 CHECK_ERROR0;
13364 ctxt->context->doc = bakd;
13365 ctxt->context->node = bak;
13366 ctxt->context->proximityPosition = pp;
13367 ctxt->context->contextSize = cs;
13368 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13369 CHECK_ERROR0;
13370 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13371 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13372 return (total);
13373 case XPATH_OP_PLUS:
13374 bakd = ctxt->context->doc;
13375 bak = ctxt->context->node;
13376 pp = ctxt->context->proximityPosition;
13377 cs = ctxt->context->contextSize;
13378 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13379 CHECK_ERROR0;
13380 if (op->ch2 != -1) {
13381 ctxt->context->doc = bakd;
13382 ctxt->context->node = bak;
13383 ctxt->context->proximityPosition = pp;
13384 ctxt->context->contextSize = cs;
13385 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13386 }
13387 CHECK_ERROR0;
13388 if (op->value == 0)
13389 xmlXPathSubValues(ctxt);
13390 else if (op->value == 1)
13391 xmlXPathAddValues(ctxt);
13392 else if (op->value == 2)
13393 xmlXPathValueFlipSign(ctxt);
13394 else if (op->value == 3) {
13395 CAST_TO_NUMBER;
13396 CHECK_TYPE0(XPATH_NUMBER);
13397 }
13398 return (total);
13399 case XPATH_OP_MULT:
13400 bakd = ctxt->context->doc;
13401 bak = ctxt->context->node;
13402 pp = ctxt->context->proximityPosition;
13403 cs = ctxt->context->contextSize;
13404 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13405 CHECK_ERROR0;
13406 ctxt->context->doc = bakd;
13407 ctxt->context->node = bak;
13408 ctxt->context->proximityPosition = pp;
13409 ctxt->context->contextSize = cs;
13410 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13411 CHECK_ERROR0;
13412 if (op->value == 0)
13413 xmlXPathMultValues(ctxt);
13414 else if (op->value == 1)
13415 xmlXPathDivValues(ctxt);
13416 else if (op->value == 2)
13417 xmlXPathModValues(ctxt);
13418 return (total);
13419 case XPATH_OP_UNION:
13420 bakd = ctxt->context->doc;
13421 bak = ctxt->context->node;
13422 pp = ctxt->context->proximityPosition;
13423 cs = ctxt->context->contextSize;
13424 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13425 CHECK_ERROR0;
13426 ctxt->context->doc = bakd;
13427 ctxt->context->node = bak;
13428 ctxt->context->proximityPosition = pp;
13429 ctxt->context->contextSize = cs;
13430 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13431 CHECK_ERROR0;
13432 CHECK_TYPE0(XPATH_NODESET);
13433 arg2 = valuePop(ctxt);
13434
13435 CHECK_TYPE0(XPATH_NODESET);
13436 arg1 = valuePop(ctxt);
13437
13438 if ((arg1->nodesetval == NULL) ||
13439 ((arg2->nodesetval != NULL) &&
13440 (arg2->nodesetval->nodeNr != 0)))
13441 {
13442 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13443 arg2->nodesetval);
13444 }
13445
13446 valuePush(ctxt, arg1);
13447 xmlXPathReleaseObject(ctxt->context, arg2);
13448 return (total);
13449 case XPATH_OP_ROOT:
13450 xmlXPathRoot(ctxt);
13451 return (total);
13452 case XPATH_OP_NODE:
13453 if (op->ch1 != -1)
13454 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13455 CHECK_ERROR0;
13456 if (op->ch2 != -1)
13457 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13458 CHECK_ERROR0;
13459 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13460 ctxt->context->node));
13461 return (total);
13462 case XPATH_OP_RESET:
13463 if (op->ch1 != -1)
13464 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13465 CHECK_ERROR0;
13466 if (op->ch2 != -1)
13467 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13468 CHECK_ERROR0;
13469 ctxt->context->node = NULL;
13470 return (total);
13471 case XPATH_OP_COLLECT:{
13472 if (op->ch1 == -1)
13473 return (total);
13474
13475 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13476 CHECK_ERROR0;
13477
13478 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13479 return (total);
13480 }
13481 case XPATH_OP_VALUE:
13482 valuePush(ctxt,
13483 xmlXPathCacheObjectCopy(ctxt->context,
13484 (xmlXPathObjectPtr) op->value4));
13485 return (total);
13486 case XPATH_OP_VARIABLE:{
13487 xmlXPathObjectPtr val;
13488
13489 if (op->ch1 != -1)
13490 total +=
13491 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13492 if (op->value5 == NULL) {
13493 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13494 if (val == NULL) {
13495 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13496 return(0);
13497 }
13498 valuePush(ctxt, val);
13499 } else {
13500 const xmlChar *URI;
13501
13502 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13503 if (URI == NULL) {
13504 xmlGenericError(xmlGenericErrorContext,
13505 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13506 (char *) op->value4, (char *)op->value5);
13507 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13508 return (total);
13509 }
13510 val = xmlXPathVariableLookupNS(ctxt->context,
13511 op->value4, URI);
13512 if (val == NULL) {
13513 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13514 return(0);
13515 }
13516 valuePush(ctxt, val);
13517 }
13518 return (total);
13519 }
13520 case XPATH_OP_FUNCTION:{
13521 xmlXPathFunction func;
13522 const xmlChar *oldFunc, *oldFuncURI;
13523 int i;
13524 int frame;
13525
13526 frame = xmlXPathSetFrame(ctxt);
13527 if (op->ch1 != -1) {
13528 total +=
13529 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13530 if (ctxt->error != XPATH_EXPRESSION_OK) {
13531 xmlXPathPopFrame(ctxt, frame);
13532 return (total);
13533 }
13534 }
13535 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13536 xmlGenericError(xmlGenericErrorContext,
13537 "xmlXPathCompOpEval: parameter error\n");
13538 ctxt->error = XPATH_INVALID_OPERAND;
13539 xmlXPathPopFrame(ctxt, frame);
13540 return (total);
13541 }
13542 for (i = 0; i < op->value; i++) {
13543 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13544 xmlGenericError(xmlGenericErrorContext,
13545 "xmlXPathCompOpEval: parameter error\n");
13546 ctxt->error = XPATH_INVALID_OPERAND;
13547 xmlXPathPopFrame(ctxt, frame);
13548 return (total);
13549 }
13550 }
13551 if (op->cache != NULL)
13552 XML_CAST_FPTR(func) = op->cache;
13553 else {
13554 const xmlChar *URI = NULL;
13555
13556 if (op->value5 == NULL)
13557 func =
13558 xmlXPathFunctionLookup(ctxt->context,
13559 op->value4);
13560 else {
13561 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13562 if (URI == NULL) {
13563 xmlGenericError(xmlGenericErrorContext,
13564 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13565 (char *)op->value4, (char *)op->value5);
13566 xmlXPathPopFrame(ctxt, frame);
13567 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13568 return (total);
13569 }
13570 func = xmlXPathFunctionLookupNS(ctxt->context,
13571 op->value4, URI);
13572 }
13573 if (func == NULL) {
13574 xmlGenericError(xmlGenericErrorContext,
13575 "xmlXPathCompOpEval: function %s not found\n",
13576 (char *)op->value4);
13577 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13578 }
13579 op->cache = XML_CAST_FPTR(func);
13580 op->cacheURI = (void *) URI;
13581 }
13582 oldFunc = ctxt->context->function;
13583 oldFuncURI = ctxt->context->functionURI;
13584 ctxt->context->function = op->value4;
13585 ctxt->context->functionURI = op->cacheURI;
13586 func(ctxt, op->value);
13587 ctxt->context->function = oldFunc;
13588 ctxt->context->functionURI = oldFuncURI;
13589 xmlXPathPopFrame(ctxt, frame);
13590 return (total);
13591 }
13592 case XPATH_OP_ARG:
13593 bakd = ctxt->context->doc;
13594 bak = ctxt->context->node;
13595 pp = ctxt->context->proximityPosition;
13596 cs = ctxt->context->contextSize;
13597 if (op->ch1 != -1) {
13598 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13599 ctxt->context->contextSize = cs;
13600 ctxt->context->proximityPosition = pp;
13601 ctxt->context->node = bak;
13602 ctxt->context->doc = bakd;
13603 CHECK_ERROR0;
13604 }
13605 if (op->ch2 != -1) {
13606 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13607 ctxt->context->contextSize = cs;
13608 ctxt->context->proximityPosition = pp;
13609 ctxt->context->node = bak;
13610 ctxt->context->doc = bakd;
13611 CHECK_ERROR0;
13612 }
13613 return (total);
13614 case XPATH_OP_PREDICATE:
13615 case XPATH_OP_FILTER:{
13616 xmlXPathObjectPtr res;
13617 xmlXPathObjectPtr obj, tmp;
13618 xmlNodeSetPtr newset = NULL;
13619 xmlNodeSetPtr oldset;
13620 xmlNodePtr oldnode;
13621 xmlDocPtr oldDoc;
13622 int i;
13623
13624 /*
13625 * Optimization for ()[1] selection i.e. the first elem
13626 */
13627 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13628#ifdef XP_OPTIMIZED_FILTER_FIRST
13629 /*
13630 * FILTER TODO: Can we assume that the inner processing
13631 * will result in an ordered list if we have an
13632 * XPATH_OP_FILTER?
13633 * What about an additional field or flag on
13634 * xmlXPathObject like @sorted ? This way we wouln'd need
13635 * to assume anything, so it would be more robust and
13636 * easier to optimize.
13637 */
13638 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13639 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13640#else
13641 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13642#endif
13643 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13644 xmlXPathObjectPtr val;
13645
13646 val = comp->steps[op->ch2].value4;
13647 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13648 (val->floatval == 1.0)) {
13649 xmlNodePtr first = NULL;
13650
13651 total +=
13652 xmlXPathCompOpEvalFirst(ctxt,
13653 &comp->steps[op->ch1],
13654 &first);
13655 CHECK_ERROR0;
13656 /*
13657 * The nodeset should be in document order,
13658 * Keep only the first value
13659 */
13660 if ((ctxt->value != NULL) &&
13661 (ctxt->value->type == XPATH_NODESET) &&
13662 (ctxt->value->nodesetval != NULL) &&
13663 (ctxt->value->nodesetval->nodeNr > 1))
13664 ctxt->value->nodesetval->nodeNr = 1;
13665 return (total);
13666 }
13667 }
13668 /*
13669 * Optimization for ()[last()] selection i.e. the last elem
13670 */
13671 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13672 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13673 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13674 int f = comp->steps[op->ch2].ch1;
13675
13676 if ((f != -1) &&
13677 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13678 (comp->steps[f].value5 == NULL) &&
13679 (comp->steps[f].value == 0) &&
13680 (comp->steps[f].value4 != NULL) &&
13681 (xmlStrEqual
13682 (comp->steps[f].value4, BAD_CAST "last"))) {
13683 xmlNodePtr last = NULL;
13684
13685 total +=
13686 xmlXPathCompOpEvalLast(ctxt,
13687 &comp->steps[op->ch1],
13688 &last);
13689 CHECK_ERROR0;
13690 /*
13691 * The nodeset should be in document order,
13692 * Keep only the last value
13693 */
13694 if ((ctxt->value != NULL) &&
13695 (ctxt->value->type == XPATH_NODESET) &&
13696 (ctxt->value->nodesetval != NULL) &&
13697 (ctxt->value->nodesetval->nodeTab != NULL) &&
13698 (ctxt->value->nodesetval->nodeNr > 1)) {
13699 ctxt->value->nodesetval->nodeTab[0] =
13700 ctxt->value->nodesetval->nodeTab[ctxt->
13701 value->
13702 nodesetval->
13703 nodeNr -
13704 1];
13705 ctxt->value->nodesetval->nodeNr = 1;
13706 }
13707 return (total);
13708 }
13709 }
13710 /*
13711 * Process inner predicates first.
13712 * Example "index[parent::book][1]":
13713 * ...
13714 * PREDICATE <-- we are here "[1]"
13715 * PREDICATE <-- process "[parent::book]" first
13716 * SORT
13717 * COLLECT 'parent' 'name' 'node' book
13718 * NODE
13719 * ELEM Object is a number : 1
13720 */
13721 if (op->ch1 != -1)
13722 total +=
13723 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13724 CHECK_ERROR0;
13725 if (op->ch2 == -1)
13726 return (total);
13727 if (ctxt->value == NULL)
13728 return (total);
13729
13730 oldnode = ctxt->context->node;
13731
13732#ifdef LIBXML_XPTR_ENABLED
13733 /*
13734 * Hum are we filtering the result of an XPointer expression
13735 */
13736 if (ctxt->value->type == XPATH_LOCATIONSET) {
13737 xmlLocationSetPtr newlocset = NULL;
13738 xmlLocationSetPtr oldlocset;
13739
13740 /*
13741 * Extract the old locset, and then evaluate the result of the
13742 * expression for all the element in the locset. use it to grow
13743 * up a new locset.
13744 */
13745 CHECK_TYPE0(XPATH_LOCATIONSET);
13746 obj = valuePop(ctxt);
13747 oldlocset = obj->user;
13748 ctxt->context->node = NULL;
13749
13750 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13751 ctxt->context->contextSize = 0;
13752 ctxt->context->proximityPosition = 0;
13753 if (op->ch2 != -1)
13754 total +=
13755 xmlXPathCompOpEval(ctxt,
13756 &comp->steps[op->ch2]);
13757 res = valuePop(ctxt);
13758 if (res != NULL) {
13759 xmlXPathReleaseObject(ctxt->context, res);
13760 }
13761 valuePush(ctxt, obj);
13762 CHECK_ERROR0;
13763 return (total);
13764 }
13765 newlocset = xmlXPtrLocationSetCreate(NULL);
13766
13767 for (i = 0; i < oldlocset->locNr; i++) {
13768 /*
13769 * Run the evaluation with a node list made of a
13770 * single item in the nodelocset.
13771 */
13772 ctxt->context->node = oldlocset->locTab[i]->user;
13773 ctxt->context->contextSize = oldlocset->locNr;
13774 ctxt->context->proximityPosition = i + 1;
13775 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13776 ctxt->context->node);
13777 valuePush(ctxt, tmp);
13778
13779 if (op->ch2 != -1)
13780 total +=
13781 xmlXPathCompOpEval(ctxt,
13782 &comp->steps[op->ch2]);
13783 if (ctxt->error != XPATH_EXPRESSION_OK) {
13784 xmlXPathFreeObject(obj);
13785 return(0);
13786 }
13787
13788 /*
13789 * The result of the evaluation need to be tested to
13790 * decided whether the filter succeeded or not
13791 */
13792 res = valuePop(ctxt);
13793 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13794 xmlXPtrLocationSetAdd(newlocset,
13795 xmlXPathObjectCopy
13796 (oldlocset->locTab[i]));
13797 }
13798
13799 /*
13800 * Cleanup
13801 */
13802 if (res != NULL) {
13803 xmlXPathReleaseObject(ctxt->context, res);
13804 }
13805 if (ctxt->value == tmp) {
13806 res = valuePop(ctxt);
13807 xmlXPathReleaseObject(ctxt->context, res);
13808 }
13809
13810 ctxt->context->node = NULL;
13811 }
13812
13813 /*
13814 * The result is used as the new evaluation locset.
13815 */
13816 xmlXPathReleaseObject(ctxt->context, obj);
13817 ctxt->context->node = NULL;
13818 ctxt->context->contextSize = -1;
13819 ctxt->context->proximityPosition = -1;
13820 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13821 ctxt->context->node = oldnode;
13822 return (total);
13823 }
13824#endif /* LIBXML_XPTR_ENABLED */
13825
13826 /*
13827 * Extract the old set, and then evaluate the result of the
13828 * expression for all the element in the set. use it to grow
13829 * up a new set.
13830 */
13831 CHECK_TYPE0(XPATH_NODESET);
13832 obj = valuePop(ctxt);
13833 oldset = obj->nodesetval;
13834
13835 oldnode = ctxt->context->node;
13836 oldDoc = ctxt->context->doc;
13837 ctxt->context->node = NULL;
13838
13839 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13840 ctxt->context->contextSize = 0;
13841 ctxt->context->proximityPosition = 0;
13842/*
13843 if (op->ch2 != -1)
13844 total +=
13845 xmlXPathCompOpEval(ctxt,
13846 &comp->steps[op->ch2]);
13847 CHECK_ERROR0;
13848 res = valuePop(ctxt);
13849 if (res != NULL)
13850 xmlXPathFreeObject(res);
13851*/
13852 valuePush(ctxt, obj);
13853 ctxt->context->node = oldnode;
13854 CHECK_ERROR0;
13855 } else {
13856 tmp = NULL;
13857 /*
13858 * Initialize the new set.
13859 * Also set the xpath document in case things like
13860 * key() evaluation are attempted on the predicate
13861 */
13862 newset = xmlXPathNodeSetCreate(NULL);
13863 /*
13864 * SPEC XPath 1.0:
13865 * "For each node in the node-set to be filtered, the
13866 * PredicateExpr is evaluated with that node as the
13867 * context node, with the number of nodes in the
13868 * node-set as the context size, and with the proximity
13869 * position of the node in the node-set with respect to
13870 * the axis as the context position;"
13871 * @oldset is the node-set" to be filtered.
13872 *
13873 * SPEC XPath 1.0:
13874 * "only predicates change the context position and
13875 * context size (see [2.4 Predicates])."
13876 * Example:
13877 * node-set context pos
13878 * nA 1
13879 * nB 2
13880 * nC 3
13881 * After applying predicate [position() > 1] :
13882 * node-set context pos
13883 * nB 1
13884 * nC 2
13885 *
13886 * removed the first node in the node-set, then
13887 * the context position of the
13888 */
13889 for (i = 0; i < oldset->nodeNr; i++) {
13890 /*
13891 * Run the evaluation with a node list made of
13892 * a single item in the nodeset.
13893 */
13894 ctxt->context->node = oldset->nodeTab[i];
13895 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13896 (oldset->nodeTab[i]->doc != NULL))
13897 ctxt->context->doc = oldset->nodeTab[i]->doc;
13898 if (tmp == NULL) {
13899 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13900 ctxt->context->node);
13901 } else {
13902 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13903 ctxt->context->node) < 0) {
13904 ctxt->error = XPATH_MEMORY_ERROR;
13905 }
13906 }
13907 valuePush(ctxt, tmp);
13908 ctxt->context->contextSize = oldset->nodeNr;
13909 ctxt->context->proximityPosition = i + 1;
13910 /*
13911 * Evaluate the predicate against the context node.
13912 * Can/should we optimize position() predicates
13913 * here (e.g. "[1]")?
13914 */
13915 if (op->ch2 != -1)
13916 total +=
13917 xmlXPathCompOpEval(ctxt,
13918 &comp->steps[op->ch2]);
13919 if (ctxt->error != XPATH_EXPRESSION_OK) {
13920 xmlXPathFreeNodeSet(newset);
13921 xmlXPathFreeObject(obj);
13922 return(0);
13923 }
13924
13925 /*
13926 * The result of the evaluation needs to be tested to
13927 * decide whether the filter succeeded or not
13928 */
13929 /*
13930 * OPTIMIZE TODO: Can we use
13931 * xmlXPathNodeSetAdd*Unique()* instead?
13932 */
13933 res = valuePop(ctxt);
13934 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13935 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13936 < 0)
13937 ctxt->error = XPATH_MEMORY_ERROR;
13938 }
13939
13940 /*
13941 * Cleanup
13942 */
13943 if (res != NULL) {
13944 xmlXPathReleaseObject(ctxt->context, res);
13945 }
13946 if (ctxt->value == tmp) {
13947 valuePop(ctxt);
13948 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13949 /*
13950 * Don't free the temporary nodeset
13951 * in order to avoid massive recreation inside this
13952 * loop.
13953 */
13954 } else
13955 tmp = NULL;
13956 ctxt->context->node = NULL;
13957 }
13958 if (tmp != NULL)
13959 xmlXPathReleaseObject(ctxt->context, tmp);
13960 /*
13961 * The result is used as the new evaluation set.
13962 */
13963 xmlXPathReleaseObject(ctxt->context, obj);
13964 ctxt->context->node = NULL;
13965 ctxt->context->contextSize = -1;
13966 ctxt->context->proximityPosition = -1;
13967 /* may want to move this past the '}' later */
13968 ctxt->context->doc = oldDoc;
13969 valuePush(ctxt,
13970 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13971 }
13972 ctxt->context->node = oldnode;
13973 return (total);
13974 }
13975 case XPATH_OP_SORT:
13976 if (op->ch1 != -1)
13977 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13978 CHECK_ERROR0;
13979 if ((ctxt->value != NULL) &&
13980 (ctxt->value->type == XPATH_NODESET) &&
13981 (ctxt->value->nodesetval != NULL) &&
13982 (ctxt->value->nodesetval->nodeNr > 1))
13983 {
13984 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13985 }
13986 return (total);
13987#ifdef LIBXML_XPTR_ENABLED
13988 case XPATH_OP_RANGETO:{
13989 xmlXPathObjectPtr range;
13990 xmlXPathObjectPtr res, obj;
13991 xmlXPathObjectPtr tmp;
13992 xmlLocationSetPtr newlocset = NULL;
13993 xmlLocationSetPtr oldlocset;
13994 xmlNodeSetPtr oldset;
13995 int i, j;
13996
13997 if (op->ch1 != -1)
13998 total +=
13999 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14000 if (op->ch2 == -1)
14001 return (total);
14002
14003 if (ctxt->value->type == XPATH_LOCATIONSET) {
14004 /*
14005 * Extract the old locset, and then evaluate the result of the
14006 * expression for all the element in the locset. use it to grow
14007 * up a new locset.
14008 */
14009 CHECK_TYPE0(XPATH_LOCATIONSET);
14010 obj = valuePop(ctxt);
14011 oldlocset = obj->user;
14012
14013 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14014 ctxt->context->node = NULL;
14015 ctxt->context->contextSize = 0;
14016 ctxt->context->proximityPosition = 0;
14017 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14018 res = valuePop(ctxt);
14019 if (res != NULL) {
14020 xmlXPathReleaseObject(ctxt->context, res);
14021 }
14022 valuePush(ctxt, obj);
14023 CHECK_ERROR0;
14024 return (total);
14025 }
14026 newlocset = xmlXPtrLocationSetCreate(NULL);
14027
14028 for (i = 0; i < oldlocset->locNr; i++) {
14029 /*
14030 * Run the evaluation with a node list made of a
14031 * single item in the nodelocset.
14032 */
14033 ctxt->context->node = oldlocset->locTab[i]->user;
14034 ctxt->context->contextSize = oldlocset->locNr;
14035 ctxt->context->proximityPosition = i + 1;
14036 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14037 ctxt->context->node);
14038 valuePush(ctxt, tmp);
14039
14040 if (op->ch2 != -1)
14041 total +=
14042 xmlXPathCompOpEval(ctxt,
14043 &comp->steps[op->ch2]);
14044 if (ctxt->error != XPATH_EXPRESSION_OK) {
14045 xmlXPathFreeObject(obj);
14046 return(0);
14047 }
14048
14049 res = valuePop(ctxt);
14050 if (res->type == XPATH_LOCATIONSET) {
14051 xmlLocationSetPtr rloc =
14052 (xmlLocationSetPtr)res->user;
14053 for (j=0; j<rloc->locNr; j++) {
14054 range = xmlXPtrNewRange(
14055 oldlocset->locTab[i]->user,
14056 oldlocset->locTab[i]->index,
14057 rloc->locTab[j]->user2,
14058 rloc->locTab[j]->index2);
14059 if (range != NULL) {
14060 xmlXPtrLocationSetAdd(newlocset, range);
14061 }
14062 }
14063 } else {
14064 range = xmlXPtrNewRangeNodeObject(
14065 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14066 if (range != NULL) {
14067 xmlXPtrLocationSetAdd(newlocset,range);
14068 }
14069 }
14070
14071 /*
14072 * Cleanup
14073 */
14074 if (res != NULL) {
14075 xmlXPathReleaseObject(ctxt->context, res);
14076 }
14077 if (ctxt->value == tmp) {
14078 res = valuePop(ctxt);
14079 xmlXPathReleaseObject(ctxt->context, res);
14080 }
14081
14082 ctxt->context->node = NULL;
14083 }
14084 } else { /* Not a location set */
14085 CHECK_TYPE0(XPATH_NODESET);
14086 obj = valuePop(ctxt);
14087 oldset = obj->nodesetval;
14088 ctxt->context->node = NULL;
14089
14090 newlocset = xmlXPtrLocationSetCreate(NULL);
14091
14092 if (oldset != NULL) {
14093 for (i = 0; i < oldset->nodeNr; i++) {
14094 /*
14095 * Run the evaluation with a node list made of a single item
14096 * in the nodeset.
14097 */
14098 ctxt->context->node = oldset->nodeTab[i];
14099 /*
14100 * OPTIMIZE TODO: Avoid recreation for every iteration.
14101 */
14102 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14103 ctxt->context->node);
14104 valuePush(ctxt, tmp);
14105
14106 if (op->ch2 != -1)
14107 total +=
14108 xmlXPathCompOpEval(ctxt,
14109 &comp->steps[op->ch2]);
14110 if (ctxt->error != XPATH_EXPRESSION_OK) {
14111 xmlXPathFreeObject(obj);
14112 return(0);
14113 }
14114
14115 res = valuePop(ctxt);
14116 range =
14117 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14118 res);
14119 if (range != NULL) {
14120 xmlXPtrLocationSetAdd(newlocset, range);
14121 }
14122
14123 /*
14124 * Cleanup
14125 */
14126 if (res != NULL) {
14127 xmlXPathReleaseObject(ctxt->context, res);
14128 }
14129 if (ctxt->value == tmp) {
14130 res = valuePop(ctxt);
14131 xmlXPathReleaseObject(ctxt->context, res);
14132 }
14133
14134 ctxt->context->node = NULL;
14135 }
14136 }
14137 }
14138
14139 /*
14140 * The result is used as the new evaluation set.
14141 */
14142 xmlXPathReleaseObject(ctxt->context, obj);
14143 ctxt->context->node = NULL;
14144 ctxt->context->contextSize = -1;
14145 ctxt->context->proximityPosition = -1;
14146 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14147 return (total);
14148 }
14149#endif /* LIBXML_XPTR_ENABLED */
14150 }
14151 xmlGenericError(xmlGenericErrorContext,
14152 "XPath: unknown precompiled operation %d\n", op->op);
14153 ctxt->error = XPATH_INVALID_OPERAND;
14154 return (total);
14155}
14156
14157/**
14158 * xmlXPathCompOpEvalToBoolean:
14159 * @ctxt: the XPath parser context
14160 *
14161 * Evaluates if the expression evaluates to true.
14162 *
14163 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14164 */
14165static int
14166xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14167 xmlXPathStepOpPtr op,
14168 int isPredicate)
14169{
14170 xmlXPathObjectPtr resObj = NULL;
14171
14172start:
14173 /* comp = ctxt->comp; */
14174 switch (op->op) {
14175 case XPATH_OP_END:
14176 return (0);
14177 case XPATH_OP_VALUE:
14178 resObj = (xmlXPathObjectPtr) op->value4;
14179 if (isPredicate)
14180 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14181 return(xmlXPathCastToBoolean(resObj));
14182 case XPATH_OP_SORT:
14183 /*
14184 * We don't need sorting for boolean results. Skip this one.
14185 */
14186 if (op->ch1 != -1) {
14187 op = &ctxt->comp->steps[op->ch1];
14188 goto start;
14189 }
14190 return(0);
14191 case XPATH_OP_COLLECT:
14192 if (op->ch1 == -1)
14193 return(0);
14194
14195 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14196 if (ctxt->error != XPATH_EXPRESSION_OK)
14197 return(-1);
14198
14199 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14200 if (ctxt->error != XPATH_EXPRESSION_OK)
14201 return(-1);
14202
14203 resObj = valuePop(ctxt);
14204 if (resObj == NULL)
14205 return(-1);
14206 break;
14207 default:
14208 /*
14209 * Fallback to call xmlXPathCompOpEval().
14210 */
14211 xmlXPathCompOpEval(ctxt, op);
14212 if (ctxt->error != XPATH_EXPRESSION_OK)
14213 return(-1);
14214
14215 resObj = valuePop(ctxt);
14216 if (resObj == NULL)
14217 return(-1);
14218 break;
14219 }
14220
14221 if (resObj) {
14222 int res;
14223
14224 if (resObj->type == XPATH_BOOLEAN) {
14225 res = resObj->boolval;
14226 } else if (isPredicate) {
14227 /*
14228 * For predicates a result of type "number" is handled
14229 * differently:
14230 * SPEC XPath 1.0:
14231 * "If the result is a number, the result will be converted
14232 * to true if the number is equal to the context position
14233 * and will be converted to false otherwise;"
14234 */
14235 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14236 } else {
14237 res = xmlXPathCastToBoolean(resObj);
14238 }
14239 xmlXPathReleaseObject(ctxt->context, resObj);
14240 return(res);
14241 }
14242
14243 return(0);
14244}
14245
14246#ifdef XPATH_STREAMING
14247/**
14248 * xmlXPathRunStreamEval:
14249 * @ctxt: the XPath parser context with the compiled expression
14250 *
14251 * Evaluate the Precompiled Streamable XPath expression in the given context.
14252 */
14253static int
14254xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14255 xmlXPathObjectPtr *resultSeq, int toBool)
14256{
14257 int max_depth, min_depth;
14258 int from_root;
14259 int ret, depth;
14260 int eval_all_nodes;
14261 xmlNodePtr cur = NULL, limit = NULL;
14262 xmlStreamCtxtPtr patstream = NULL;
14263
14264 int nb_nodes = 0;
14265
14266 if ((ctxt == NULL) || (comp == NULL))
14267 return(-1);
14268 max_depth = xmlPatternMaxDepth(comp);
14269 if (max_depth == -1)
14270 return(-1);
14271 if (max_depth == -2)
14272 max_depth = 10000;
14273 min_depth = xmlPatternMinDepth(comp);
14274 if (min_depth == -1)
14275 return(-1);
14276 from_root = xmlPatternFromRoot(comp);
14277 if (from_root < 0)
14278 return(-1);
14279#if 0
14280 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14281#endif
14282
14283 if (! toBool) {
14284 if (resultSeq == NULL)
14285 return(-1);
14286 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14287 if (*resultSeq == NULL)
14288 return(-1);
14289 }
14290
14291 /*
14292 * handle the special cases of "/" amd "." being matched
14293 */
14294 if (min_depth == 0) {
14295 if (from_root) {
14296 /* Select "/" */
14297 if (toBool)
14298 return(1);
14299 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14300 (xmlNodePtr) ctxt->doc);
14301 } else {
14302 /* Select "self::node()" */
14303 if (toBool)
14304 return(1);
14305 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14306 }
14307 }
14308 if (max_depth == 0) {
14309 return(0);
14310 }
14311
14312 if (from_root) {
14313 cur = (xmlNodePtr)ctxt->doc;
14314 } else if (ctxt->node != NULL) {
14315 switch (ctxt->node->type) {
14316 case XML_ELEMENT_NODE:
14317 case XML_DOCUMENT_NODE:
14318 case XML_DOCUMENT_FRAG_NODE:
14319 case XML_HTML_DOCUMENT_NODE:
14320#ifdef LIBXML_DOCB_ENABLED
14321 case XML_DOCB_DOCUMENT_NODE:
14322#endif
14323 cur = ctxt->node;
14324 break;
14325 case XML_ATTRIBUTE_NODE:
14326 case XML_TEXT_NODE:
14327 case XML_CDATA_SECTION_NODE:
14328 case XML_ENTITY_REF_NODE:
14329 case XML_ENTITY_NODE:
14330 case XML_PI_NODE:
14331 case XML_COMMENT_NODE:
14332 case XML_NOTATION_NODE:
14333 case XML_DTD_NODE:
14334 case XML_DOCUMENT_TYPE_NODE:
14335 case XML_ELEMENT_DECL:
14336 case XML_ATTRIBUTE_DECL:
14337 case XML_ENTITY_DECL:
14338 case XML_NAMESPACE_DECL:
14339 case XML_XINCLUDE_START:
14340 case XML_XINCLUDE_END:
14341 break;
14342 }
14343 limit = cur;
14344 }
14345 if (cur == NULL) {
14346 return(0);
14347 }
14348
14349 patstream = xmlPatternGetStreamCtxt(comp);
14350 if (patstream == NULL) {
14351 /*
14352 * QUESTION TODO: Is this an error?
14353 */
14354 return(0);
14355 }
14356
14357 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14358
14359 if (from_root) {
14360 ret = xmlStreamPush(patstream, NULL, NULL);
14361 if (ret < 0) {
14362 } else if (ret == 1) {
14363 if (toBool)
14364 goto return_1;
14365 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14366 }
14367 }
14368 depth = 0;
14369 goto scan_children;
14370next_node:
14371 do {
14372 nb_nodes++;
14373
14374 switch (cur->type) {
14375 case XML_ELEMENT_NODE:
14376 case XML_TEXT_NODE:
14377 case XML_CDATA_SECTION_NODE:
14378 case XML_COMMENT_NODE:
14379 case XML_PI_NODE:
14380 if (cur->type == XML_ELEMENT_NODE) {
14381 ret = xmlStreamPush(patstream, cur->name,
14382 (cur->ns ? cur->ns->href : NULL));
14383 } else if (eval_all_nodes)
14384 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14385 else
14386 break;
14387
14388 if (ret < 0) {
14389 /* NOP. */
14390 } else if (ret == 1) {
14391 if (toBool)
14392 goto return_1;
14393 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14394 < 0) {
14395 ctxt->lastError.domain = XML_FROM_XPATH;
14396 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14397 }
14398 }
14399 if ((cur->children == NULL) || (depth >= max_depth)) {
14400 ret = xmlStreamPop(patstream);
14401 while (cur->next != NULL) {
14402 cur = cur->next;
14403 if ((cur->type != XML_ENTITY_DECL) &&
14404 (cur->type != XML_DTD_NODE))
14405 goto next_node;
14406 }
14407 }
14408 default:
14409 break;
14410 }
14411
14412scan_children:
14413 if (cur->type == XML_NAMESPACE_DECL) break;
14414 if ((cur->children != NULL) && (depth < max_depth)) {
14415 /*
14416 * Do not descend on entities declarations
14417 */
14418 if (cur->children->type != XML_ENTITY_DECL) {
14419 cur = cur->children;
14420 depth++;
14421 /*
14422 * Skip DTDs
14423 */
14424 if (cur->type != XML_DTD_NODE)
14425 continue;
14426 }
14427 }
14428
14429 if (cur == limit)
14430 break;
14431
14432 while (cur->next != NULL) {
14433 cur = cur->next;
14434 if ((cur->type != XML_ENTITY_DECL) &&
14435 (cur->type != XML_DTD_NODE))
14436 goto next_node;
14437 }
14438
14439 do {
14440 cur = cur->parent;
14441 depth--;
14442 if ((cur == NULL) || (cur == limit))
14443 goto done;
14444 if (cur->type == XML_ELEMENT_NODE) {
14445 ret = xmlStreamPop(patstream);
14446 } else if ((eval_all_nodes) &&
14447 ((cur->type == XML_TEXT_NODE) ||
14448 (cur->type == XML_CDATA_SECTION_NODE) ||
14449 (cur->type == XML_COMMENT_NODE) ||
14450 (cur->type == XML_PI_NODE)))
14451 {
14452 ret = xmlStreamPop(patstream);
14453 }
14454 if (cur->next != NULL) {
14455 cur = cur->next;
14456 break;
14457 }
14458 } while (cur != NULL);
14459
14460 } while ((cur != NULL) && (depth >= 0));
14461
14462done:
14463
14464#if 0
14465 printf("stream eval: checked %d nodes selected %d\n",
14466 nb_nodes, retObj->nodesetval->nodeNr);
14467#endif
14468
14469 if (patstream)
14470 xmlFreeStreamCtxt(patstream);
14471 return(0);
14472
14473return_1:
14474 if (patstream)
14475 xmlFreeStreamCtxt(patstream);
14476 return(1);
14477}
14478#endif /* XPATH_STREAMING */
14479
14480/**
14481 * xmlXPathRunEval:
14482 * @ctxt: the XPath parser context with the compiled expression
14483 * @toBool: evaluate to a boolean result
14484 *
14485 * Evaluate the Precompiled XPath expression in the given context.
14486 */
14487static int
14488xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14489{
14490 xmlXPathCompExprPtr comp;
14491
14492 if ((ctxt == NULL) || (ctxt->comp == NULL))
14493 return(-1);
14494
14495 if (ctxt->valueTab == NULL) {
14496 /* Allocate the value stack */
14497 ctxt->valueTab = (xmlXPathObjectPtr *)
14498 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14499 if (ctxt->valueTab == NULL) {
14500 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14501 xmlFree(ctxt);
14502 }
14503 ctxt->valueNr = 0;
14504 ctxt->valueMax = 10;
14505 ctxt->value = NULL;
14506 ctxt->valueFrame = 0;
14507 }
14508#ifdef XPATH_STREAMING
14509 if (ctxt->comp->stream) {
14510 int res;
14511
14512 if (toBool) {
14513 /*
14514 * Evaluation to boolean result.
14515 */
14516 res = xmlXPathRunStreamEval(ctxt->context,
14517 ctxt->comp->stream, NULL, 1);
14518 if (res != -1)
14519 return(res);
14520 } else {
14521 xmlXPathObjectPtr resObj = NULL;
14522
14523 /*
14524 * Evaluation to a sequence.
14525 */
14526 res = xmlXPathRunStreamEval(ctxt->context,
14527 ctxt->comp->stream, &resObj, 0);
14528
14529 if ((res != -1) && (resObj != NULL)) {
14530 valuePush(ctxt, resObj);
14531 return(0);
14532 }
14533 if (resObj != NULL)
14534 xmlXPathReleaseObject(ctxt->context, resObj);
14535 }
14536 /*
14537 * QUESTION TODO: This falls back to normal XPath evaluation
14538 * if res == -1. Is this intended?
14539 */
14540 }
14541#endif
14542 comp = ctxt->comp;
14543 if (comp->last < 0) {
14544 xmlGenericError(xmlGenericErrorContext,
14545 "xmlXPathRunEval: last is less than zero\n");
14546 return(-1);
14547 }
14548 if (toBool)
14549 return(xmlXPathCompOpEvalToBoolean(ctxt,
14550 &comp->steps[comp->last], 0));
14551 else
14552 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14553
14554 return(0);
14555}
14556
14557/************************************************************************
14558 * *
14559 * Public interfaces *
14560 * *
14561 ************************************************************************/
14562
14563/**
14564 * xmlXPathEvalPredicate:
14565 * @ctxt: the XPath context
14566 * @res: the Predicate Expression evaluation result
14567 *
14568 * Evaluate a predicate result for the current node.
14569 * A PredicateExpr is evaluated by evaluating the Expr and converting
14570 * the result to a boolean. If the result is a number, the result will
14571 * be converted to true if the number is equal to the position of the
14572 * context node in the context node list (as returned by the position
14573 * function) and will be converted to false otherwise; if the result
14574 * is not a number, then the result will be converted as if by a call
14575 * to the boolean function.
14576 *
14577 * Returns 1 if predicate is true, 0 otherwise
14578 */
14579int
14580xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14581 if ((ctxt == NULL) || (res == NULL)) return(0);
14582 switch (res->type) {
14583 case XPATH_BOOLEAN:
14584 return(res->boolval);
14585 case XPATH_NUMBER:
14586 return(res->floatval == ctxt->proximityPosition);
14587 case XPATH_NODESET:
14588 case XPATH_XSLT_TREE:
14589 if (res->nodesetval == NULL)
14590 return(0);
14591 return(res->nodesetval->nodeNr != 0);
14592 case XPATH_STRING:
14593 return((res->stringval != NULL) &&
14594 (xmlStrlen(res->stringval) != 0));
14595 default:
14596 STRANGE
14597 }
14598 return(0);
14599}
14600
14601/**
14602 * xmlXPathEvaluatePredicateResult:
14603 * @ctxt: the XPath Parser context
14604 * @res: the Predicate Expression evaluation result
14605 *
14606 * Evaluate a predicate result for the current node.
14607 * A PredicateExpr is evaluated by evaluating the Expr and converting
14608 * the result to a boolean. If the result is a number, the result will
14609 * be converted to true if the number is equal to the position of the
14610 * context node in the context node list (as returned by the position
14611 * function) and will be converted to false otherwise; if the result
14612 * is not a number, then the result will be converted as if by a call
14613 * to the boolean function.
14614 *
14615 * Returns 1 if predicate is true, 0 otherwise
14616 */
14617int
14618xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14619 xmlXPathObjectPtr res) {
14620 if ((ctxt == NULL) || (res == NULL)) return(0);
14621 switch (res->type) {
14622 case XPATH_BOOLEAN:
14623 return(res->boolval);
14624 case XPATH_NUMBER:
14625#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14626 return((res->floatval == ctxt->context->proximityPosition) &&
14627 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14628#else
14629 return(res->floatval == ctxt->context->proximityPosition);
14630#endif
14631 case XPATH_NODESET:
14632 case XPATH_XSLT_TREE:
14633 if (res->nodesetval == NULL)
14634 return(0);
14635 return(res->nodesetval->nodeNr != 0);
14636 case XPATH_STRING:
14637 return((res->stringval != NULL) && (res->stringval[0] != 0));
14638#ifdef LIBXML_XPTR_ENABLED
14639 case XPATH_LOCATIONSET:{
14640 xmlLocationSetPtr ptr = res->user;
14641 if (ptr == NULL)
14642 return(0);
14643 return (ptr->locNr != 0);
14644 }
14645#endif
14646 default:
14647 STRANGE
14648 }
14649 return(0);
14650}
14651
14652#ifdef XPATH_STREAMING
14653/**
14654 * xmlXPathTryStreamCompile:
14655 * @ctxt: an XPath context
14656 * @str: the XPath expression
14657 *
14658 * Try to compile the XPath expression as a streamable subset.
14659 *
14660 * Returns the compiled expression or NULL if failed to compile.
14661 */
14662static xmlXPathCompExprPtr
14663xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14664 /*
14665 * Optimization: use streaming patterns when the XPath expression can
14666 * be compiled to a stream lookup
14667 */
14668 xmlPatternPtr stream;
14669 xmlXPathCompExprPtr comp;
14670 xmlDictPtr dict = NULL;
14671 const xmlChar **namespaces = NULL;
14672 xmlNsPtr ns;
14673 int i, j;
14674
14675 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14676 (!xmlStrchr(str, '@'))) {
14677 const xmlChar *tmp;
14678
14679 /*
14680 * We don't try to handle expressions using the verbose axis
14681 * specifiers ("::"), just the simplied form at this point.
14682 * Additionally, if there is no list of namespaces available and
14683 * there's a ":" in the expression, indicating a prefixed QName,
14684 * then we won't try to compile either. xmlPatterncompile() needs
14685 * to have a list of namespaces at compilation time in order to
14686 * compile prefixed name tests.
14687 */
14688 tmp = xmlStrchr(str, ':');
14689 if ((tmp != NULL) &&
14690 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14691 return(NULL);
14692
14693 if (ctxt != NULL) {
14694 dict = ctxt->dict;
14695 if (ctxt->nsNr > 0) {
14696 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14697 if (namespaces == NULL) {
14698 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14699 return(NULL);
14700 }
14701 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14702 ns = ctxt->namespaces[j];
14703 namespaces[i++] = ns->href;
14704 namespaces[i++] = ns->prefix;
14705 }
14706 namespaces[i++] = NULL;
14707 namespaces[i] = NULL;
14708 }
14709 }
14710
14711 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14712 &namespaces[0]);
14713 if (namespaces != NULL) {
14714 xmlFree((xmlChar **)namespaces);
14715 }
14716 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14717 comp = xmlXPathNewCompExpr();
14718 if (comp == NULL) {
14719 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14720 return(NULL);
14721 }
14722 comp->stream = stream;
14723 comp->dict = dict;
14724 if (comp->dict)
14725 xmlDictReference(comp->dict);
14726 return(comp);
14727 }
14728 xmlFreePattern(stream);
14729 }
14730 return(NULL);
14731}
14732#endif /* XPATH_STREAMING */
14733
14734static void
14735xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14736{
14737 /*
14738 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14739 * internal representation.
14740 */
14741
14742 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14743 (op->ch1 != -1) &&
14744 (op->ch2 == -1 /* no predicate */))
14745 {
14746 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14747
14748 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14749 ((xmlXPathAxisVal) prevop->value ==
14750 AXIS_DESCENDANT_OR_SELF) &&
14751 (prevop->ch2 == -1) &&
14752 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14753 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14754 {
14755 /*
14756 * This is a "descendant-or-self::node()" without predicates.
14757 * Try to eliminate it.
14758 */
14759
14760 switch ((xmlXPathAxisVal) op->value) {
14761 case AXIS_CHILD:
14762 case AXIS_DESCENDANT:
14763 /*
14764 * Convert "descendant-or-self::node()/child::" or
14765 * "descendant-or-self::node()/descendant::" to
14766 * "descendant::"
14767 */
14768 op->ch1 = prevop->ch1;
14769 op->value = AXIS_DESCENDANT;
14770 break;
14771 case AXIS_SELF:
14772 case AXIS_DESCENDANT_OR_SELF:
14773 /*
14774 * Convert "descendant-or-self::node()/self::" or
14775 * "descendant-or-self::node()/descendant-or-self::" to
14776 * to "descendant-or-self::"
14777 */
14778 op->ch1 = prevop->ch1;
14779 op->value = AXIS_DESCENDANT_OR_SELF;
14780 break;
14781 default:
14782 break;
14783 }
14784 }
14785 }
14786
14787 /* Recurse */
14788 if (op->ch1 != -1)
14789 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14790 if (op->ch2 != -1)
14791 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14792}
14793
14794/**
14795 * xmlXPathCtxtCompile:
14796 * @ctxt: an XPath context
14797 * @str: the XPath expression
14798 *
14799 * Compile an XPath expression
14800 *
14801 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14802 * the caller has to free the object.
14803 */
14804xmlXPathCompExprPtr
14805xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14806 xmlXPathParserContextPtr pctxt;
14807 xmlXPathCompExprPtr comp;
14808
14809#ifdef XPATH_STREAMING
14810 comp = xmlXPathTryStreamCompile(ctxt, str);
14811 if (comp != NULL)
14812 return(comp);
14813#endif
14814
14815 xmlXPathInit();
14816
14817 pctxt = xmlXPathNewParserContext(str, ctxt);
14818 if (pctxt == NULL)
14819 return NULL;
14820 xmlXPathCompileExpr(pctxt, 1);
14821
14822 if( pctxt->error != XPATH_EXPRESSION_OK )
14823 {
14824 xmlXPathFreeParserContext(pctxt);
14825 return(NULL);
14826 }
14827
14828 if (*pctxt->cur != 0) {
14829 /*
14830 * aleksey: in some cases this line prints *second* error message
14831 * (see bug #78858) and probably this should be fixed.
14832 * However, we are not sure that all error messages are printed
14833 * out in other places. It's not critical so we leave it as-is for now
14834 */
14835 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14836 comp = NULL;
14837 } else {
14838 comp = pctxt->comp;
14839 pctxt->comp = NULL;
14840 }
14841 xmlXPathFreeParserContext(pctxt);
14842
14843 if (comp != NULL) {
14844 comp->expr = xmlStrdup(str);
14845#ifdef DEBUG_EVAL_COUNTS
14846 comp->string = xmlStrdup(str);
14847 comp->nb = 0;
14848#endif
14849 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14850 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14851 }
14852 }
14853 return(comp);
14854}
14855
14856/**
14857 * xmlXPathCompile:
14858 * @str: the XPath expression
14859 *
14860 * Compile an XPath expression
14861 *
14862 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14863 * the caller has to free the object.
14864 */
14865xmlXPathCompExprPtr
14866xmlXPathCompile(const xmlChar *str) {
14867 return(xmlXPathCtxtCompile(NULL, str));
14868}
14869
14870/**
14871 * xmlXPathCompiledEvalInternal:
14872 * @comp: the compiled XPath expression
14873 * @ctxt: the XPath context
14874 * @resObj: the resulting XPath object or NULL
14875 * @toBool: 1 if only a boolean result is requested
14876 *
14877 * Evaluate the Precompiled XPath expression in the given context.
14878 * The caller has to free @resObj.
14879 *
14880 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14881 * the caller has to free the object.
14882 */
14883static int
14884xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14885 xmlXPathContextPtr ctxt,
14886 xmlXPathObjectPtr *resObj,
14887 int toBool)
14888{
14889 xmlXPathParserContextPtr pctxt;
14890#ifndef LIBXML_THREAD_ENABLED
14891 static int reentance = 0;
14892#endif
14893 int res;
14894
14895 CHECK_CTXT_NEG(ctxt)
14896
14897 if (comp == NULL)
14898 return(-1);
14899 xmlXPathInit();
14900
14901#ifndef LIBXML_THREAD_ENABLED
14902 reentance++;
14903 if (reentance > 1)
14904 xmlXPathDisableOptimizer = 1;
14905#endif
14906
14907#ifdef DEBUG_EVAL_COUNTS
14908 comp->nb++;
14909 if ((comp->string != NULL) && (comp->nb > 100)) {
14910 fprintf(stderr, "100 x %s\n", comp->string);
14911 comp->nb = 0;
14912 }
14913#endif
14914 pctxt = xmlXPathCompParserContext(comp, ctxt);
14915 res = xmlXPathRunEval(pctxt, toBool);
14916
14917 if (resObj) {
14918 if (pctxt->value == NULL) {
14919 xmlGenericError(xmlGenericErrorContext,
14920 "xmlXPathCompiledEval: evaluation failed\n");
14921 *resObj = NULL;
14922 } else {
14923 *resObj = valuePop(pctxt);
14924 }
14925 }
14926
14927 /*
14928 * Pop all remaining objects from the stack.
14929 */
14930 if (pctxt->valueNr > 0) {
14931 xmlXPathObjectPtr tmp;
14932 int stack = 0;
14933
14934 do {
14935 tmp = valuePop(pctxt);
14936 if (tmp != NULL) {
14937 stack++;
14938 xmlXPathReleaseObject(ctxt, tmp);
14939 }
14940 } while (tmp != NULL);
14941 if ((stack != 0) &&
14942 ((toBool) || ((resObj) && (*resObj))))
14943 {
14944 xmlGenericError(xmlGenericErrorContext,
14945 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14946 stack);
14947 }
14948 }
14949
14950 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14951 xmlXPathFreeObject(*resObj);
14952 *resObj = NULL;
14953 }
14954 pctxt->comp = NULL;
14955 xmlXPathFreeParserContext(pctxt);
14956#ifndef LIBXML_THREAD_ENABLED
14957 reentance--;
14958#endif
14959
14960 return(res);
14961}
14962
14963/**
14964 * xmlXPathCompiledEval:
14965 * @comp: the compiled XPath expression
14966 * @ctx: the XPath context
14967 *
14968 * Evaluate the Precompiled XPath expression in the given context.
14969 *
14970 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14971 * the caller has to free the object.
14972 */
14973xmlXPathObjectPtr
14974xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14975{
14976 xmlXPathObjectPtr res = NULL;
14977
14978 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14979 return(res);
14980}
14981
14982/**
14983 * xmlXPathCompiledEvalToBoolean:
14984 * @comp: the compiled XPath expression
14985 * @ctxt: the XPath context
14986 *
14987 * Applies the XPath boolean() function on the result of the given
14988 * compiled expression.
14989 *
14990 * Returns 1 if the expression evaluated to true, 0 if to false and
14991 * -1 in API and internal errors.
14992 */
14993int
14994xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14995 xmlXPathContextPtr ctxt)
14996{
14997 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14998}
14999
15000/**
15001 * xmlXPathEvalExpr:
15002 * @ctxt: the XPath Parser context
15003 *
15004 * Parse and evaluate an XPath expression in the given context,
15005 * then push the result on the context stack
15006 */
15007void
15008xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
15009#ifdef XPATH_STREAMING
15010 xmlXPathCompExprPtr comp;
15011#endif
15012
15013 if (ctxt == NULL) return;
15014
15015#ifdef XPATH_STREAMING
15016 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15017 if (comp != NULL) {
15018 if (ctxt->comp != NULL)
15019 xmlXPathFreeCompExpr(ctxt->comp);
15020 ctxt->comp = comp;
15021 if (ctxt->cur != NULL)
15022 while (*ctxt->cur != 0) ctxt->cur++;
15023 } else
15024#endif
15025 {
15026 xmlXPathCompileExpr(ctxt, 1);
15027 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15028 (ctxt->comp != NULL) &&
15029 (ctxt->comp->nbStep > 1) &&
15030 (ctxt->comp->last >= 0))
15031 {
15032 xmlXPathOptimizeExpression(ctxt->comp,
15033 &ctxt->comp->steps[ctxt->comp->last]);
15034 }
15035 }
15036 CHECK_ERROR;
15037 xmlXPathRunEval(ctxt, 0);
15038}
15039
15040/**
15041 * xmlXPathEval:
15042 * @str: the XPath expression
15043 * @ctx: the XPath context
15044 *
15045 * Evaluate the XPath Location Path in the given context.
15046 *
15047 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15048 * the caller has to free the object.
15049 */
15050xmlXPathObjectPtr
15051xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15052 xmlXPathParserContextPtr ctxt;
15053 xmlXPathObjectPtr res, tmp, init = NULL;
15054 int stack = 0;
15055
15056 CHECK_CTXT(ctx)
15057
15058 xmlXPathInit();
15059
15060 ctxt = xmlXPathNewParserContext(str, ctx);
15061 if (ctxt == NULL)
15062 return NULL;
15063 xmlXPathEvalExpr(ctxt);
15064
15065 if (ctxt->value == NULL) {
15066 xmlGenericError(xmlGenericErrorContext,
15067 "xmlXPathEval: evaluation failed\n");
15068 res = NULL;
15069 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
15070#ifdef XPATH_STREAMING
15071 && (ctxt->comp->stream == NULL)
15072#endif
15073 ) {
15074 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15075 res = NULL;
15076 } else {
15077 res = valuePop(ctxt);
15078 }
15079
15080 do {
15081 tmp = valuePop(ctxt);
15082 if (tmp != NULL) {
15083 if (tmp != init)
15084 stack++;
15085 xmlXPathReleaseObject(ctx, tmp);
15086 }
15087 } while (tmp != NULL);
15088 if ((stack != 0) && (res != NULL)) {
15089 xmlGenericError(xmlGenericErrorContext,
15090 "xmlXPathEval: %d object left on the stack\n",
15091 stack);
15092 }
15093 if (ctxt->error != XPATH_EXPRESSION_OK) {
15094 xmlXPathFreeObject(res);
15095 res = NULL;
15096 }
15097
15098 xmlXPathFreeParserContext(ctxt);
15099 return(res);
15100}
15101
15102/**
15103 * xmlXPathSetContextNode:
15104 * @node: the node to to use as the context node
15105 * @ctx: the XPath context
15106 *
15107 * Sets 'node' as the context node. The node must be in the same
15108 * document as that associated with the context.
15109 *
15110 * Returns -1 in case of error or 0 if successful
15111 */
15112int
15113xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15114 if ((node == NULL) || (ctx == NULL))
15115 return(-1);
15116
15117 if (node->doc == ctx->doc) {
15118 ctx->node = node;
15119 return(0);
15120 }
15121 return(-1);
15122}
15123
15124/**
15125 * xmlXPathNodeEval:
15126 * @node: the node to to use as the context node
15127 * @str: the XPath expression
15128 * @ctx: the XPath context
15129 *
15130 * Evaluate the XPath Location Path in the given context. The node 'node'
15131 * is set as the context node. The context node is not restored.
15132 *
15133 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15134 * the caller has to free the object.
15135 */
15136xmlXPathObjectPtr
15137xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15138 if (str == NULL)
15139 return(NULL);
15140 if (xmlXPathSetContextNode(node, ctx) < 0)
15141 return(NULL);
15142 return(xmlXPathEval(str, ctx));
15143}
15144
15145/**
15146 * xmlXPathEvalExpression:
15147 * @str: the XPath expression
15148 * @ctxt: the XPath context
15149 *
15150 * Evaluate the XPath expression in the given context.
15151 *
15152 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15153 * the caller has to free the object.
15154 */
15155xmlXPathObjectPtr
15156xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15157 xmlXPathParserContextPtr pctxt;
15158 xmlXPathObjectPtr res, tmp;
15159 int stack = 0;
15160
15161 CHECK_CTXT(ctxt)
15162
15163 xmlXPathInit();
15164
15165 pctxt = xmlXPathNewParserContext(str, ctxt);
15166 if (pctxt == NULL)
15167 return NULL;
15168 xmlXPathEvalExpr(pctxt);
15169
15170 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15171 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15172 res = NULL;
15173 } else {
15174 res = valuePop(pctxt);
15175 }
15176 do {
15177 tmp = valuePop(pctxt);
15178 if (tmp != NULL) {
15179 xmlXPathReleaseObject(ctxt, tmp);
15180 stack++;
15181 }
15182 } while (tmp != NULL);
15183 if ((stack != 0) && (res != NULL)) {
15184 xmlGenericError(xmlGenericErrorContext,
15185 "xmlXPathEvalExpression: %d object left on the stack\n",
15186 stack);
15187 }
15188 xmlXPathFreeParserContext(pctxt);
15189 return(res);
15190}
15191
15192/************************************************************************
15193 * *
15194 * Extra functions not pertaining to the XPath spec *
15195 * *
15196 ************************************************************************/
15197/**
15198 * xmlXPathEscapeUriFunction:
15199 * @ctxt: the XPath Parser context
15200 * @nargs: the number of arguments
15201 *
15202 * Implement the escape-uri() XPath function
15203 * string escape-uri(string $str, bool $escape-reserved)
15204 *
15205 * This function applies the URI escaping rules defined in section 2 of [RFC
15206 * 2396] to the string supplied as $uri-part, which typically represents all
15207 * or part of a URI. The effect of the function is to replace any special
15208 * character in the string by an escape sequence of the form %xx%yy...,
15209 * where xxyy... is the hexadecimal representation of the octets used to
15210 * represent the character in UTF-8.
15211 *
15212 * The set of characters that are escaped depends on the setting of the
15213 * boolean argument $escape-reserved.
15214 *
15215 * If $escape-reserved is true, all characters are escaped other than lower
15216 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15217 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15218 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15219 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15220 * A-F).
15221 *
15222 * If $escape-reserved is false, the behavior differs in that characters
15223 * referred to in [RFC 2396] as reserved characters are not escaped. These
15224 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15225 *
15226 * [RFC 2396] does not define whether escaped URIs should use lower case or
15227 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15228 * compared using string comparison functions, this function must always use
15229 * the upper-case letters A-F.
15230 *
15231 * Generally, $escape-reserved should be set to true when escaping a string
15232 * that is to form a single part of a URI, and to false when escaping an
15233 * entire URI or URI reference.
15234 *
15235 * In the case of non-ascii characters, the string is encoded according to
15236 * utf-8 and then converted according to RFC 2396.
15237 *
15238 * Examples
15239 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15240 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15241 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15242 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15243 *
15244 */
15245static void
15246xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15247 xmlXPathObjectPtr str;
15248 int escape_reserved;
15249 xmlBufPtr target;
15250 xmlChar *cptr;
15251 xmlChar escape[4];
15252
15253 CHECK_ARITY(2);
15254
15255 escape_reserved = xmlXPathPopBoolean(ctxt);
15256
15257 CAST_TO_STRING;
15258 str = valuePop(ctxt);
15259
15260 target = xmlBufCreate();
15261
15262 escape[0] = '%';
15263 escape[3] = 0;
15264
15265 if (target) {
15266 for (cptr = str->stringval; *cptr; cptr++) {
15267 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15268 (*cptr >= 'a' && *cptr <= 'z') ||
15269 (*cptr >= '0' && *cptr <= '9') ||
15270 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15271 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15272 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15273 (*cptr == '%' &&
15274 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15275 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15276 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15277 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15278 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15279 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15280 (!escape_reserved &&
15281 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15282 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15283 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15284 *cptr == ','))) {
15285 xmlBufAdd(target, cptr, 1);
15286 } else {
15287 if ((*cptr >> 4) < 10)
15288 escape[1] = '0' + (*cptr >> 4);
15289 else
15290 escape[1] = 'A' - 10 + (*cptr >> 4);
15291 if ((*cptr & 0xF) < 10)
15292 escape[2] = '0' + (*cptr & 0xF);
15293 else
15294 escape[2] = 'A' - 10 + (*cptr & 0xF);
15295
15296 xmlBufAdd(target, &escape[0], 3);
15297 }
15298 }
15299 }
15300 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15301 xmlBufContent(target)));
15302 xmlBufFree(target);
15303 xmlXPathReleaseObject(ctxt->context, str);
15304}
15305
15306/**
15307 * xmlXPathRegisterAllFunctions:
15308 * @ctxt: the XPath context
15309 *
15310 * Registers all default XPath functions in this context
15311 */
15312void
15313xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15314{
15315 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15316 xmlXPathBooleanFunction);
15317 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15318 xmlXPathCeilingFunction);
15319 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15320 xmlXPathCountFunction);
15321 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15322 xmlXPathConcatFunction);
15323 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15324 xmlXPathContainsFunction);
15325 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15326 xmlXPathIdFunction);
15327 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15328 xmlXPathFalseFunction);
15329 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15330 xmlXPathFloorFunction);
15331 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15332 xmlXPathLastFunction);
15333 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15334 xmlXPathLangFunction);
15335 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15336 xmlXPathLocalNameFunction);
15337 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15338 xmlXPathNotFunction);
15339 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15340 xmlXPathNameFunction);
15341 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15342 xmlXPathNamespaceURIFunction);
15343 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15344 xmlXPathNormalizeFunction);
15345 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15346 xmlXPathNumberFunction);
15347 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15348 xmlXPathPositionFunction);
15349 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15350 xmlXPathRoundFunction);
15351 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15352 xmlXPathStringFunction);
15353 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15354 xmlXPathStringLengthFunction);
15355 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15356 xmlXPathStartsWithFunction);
15357 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15358 xmlXPathSubstringFunction);
15359 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15360 xmlXPathSubstringBeforeFunction);
15361 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15362 xmlXPathSubstringAfterFunction);
15363 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15364 xmlXPathSumFunction);
15365 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15366 xmlXPathTrueFunction);
15367 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15368 xmlXPathTranslateFunction);
15369
15370 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15371 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15372 xmlXPathEscapeUriFunction);
15373}
15374
15375#endif /* LIBXML_XPATH_ENABLED */
15376#define bottom_xpath
15377#include "elfgcchack.h"
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette