VirtualBox

source: vbox/trunk/src/libs/libxml2-2.9.14/xpath.c@ 102654

Last change on this file since 102654 was 95312, checked in by vboxsync, 2 years ago

libs/{curl,libxml2}: OSE export fixes, bugref:8515

  • Property svn:eol-style set to native
File size: 399.8 KB
Line 
1/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See Copyright for the status of this software
12 *
13 * Author: daniel@veillard.com
14 *
15 */
16
17/* To avoid EBCDIC trouble when parsing on zOS */
18#if defined(__MVS__)
19#pragma convert("ISO8859-1")
20#endif
21
22#define IN_LIBXML
23#include "libxml.h"
24
25#include <limits.h>
26#include <string.h>
27#include <stddef.h>
28
29#ifdef HAVE_SYS_TYPES_H
30#include <sys/types.h>
31#endif
32#ifdef HAVE_MATH_H
33#include <math.h>
34#endif
35#ifdef HAVE_FLOAT_H
36#include <float.h>
37#endif
38#ifdef HAVE_CTYPE_H
39#include <ctype.h>
40#endif
41#ifdef HAVE_SIGNAL_H
42#include <signal.h>
43#endif
44
45#include <libxml/xmlmemory.h>
46#include <libxml/tree.h>
47#include <libxml/valid.h>
48#include <libxml/xpath.h>
49#include <libxml/xpathInternals.h>
50#include <libxml/parserInternals.h>
51#include <libxml/hash.h>
52#ifdef LIBXML_XPTR_ENABLED
53#include <libxml/xpointer.h>
54#endif
55#ifdef LIBXML_DEBUG_ENABLED
56#include <libxml/debugXML.h>
57#endif
58#include <libxml/xmlerror.h>
59#include <libxml/threads.h>
60#include <libxml/globals.h>
61#ifdef LIBXML_PATTERN_ENABLED
62#include <libxml/pattern.h>
63#endif
64
65#include "buf.h"
66
67#ifdef LIBXML_PATTERN_ENABLED
68#define XPATH_STREAMING
69#endif
70
71#define TODO \
72 xmlGenericError(xmlGenericErrorContext, \
73 "Unimplemented block at %s:%d\n", \
74 __FILE__, __LINE__);
75
76/**
77 * WITH_TIM_SORT:
78 *
79 * Use the Timsort algorithm provided in timsort.h to sort
80 * nodeset as this is a great improvement over the old Shell sort
81 * used in xmlXPathNodeSetSort()
82 */
83#define WITH_TIM_SORT
84
85/*
86* XP_OPTIMIZED_NON_ELEM_COMPARISON:
87* If defined, this will use xmlXPathCmpNodesExt() instead of
88* xmlXPathCmpNodes(). The new function is optimized comparison of
89* non-element nodes; actually it will speed up comparison only if
90* xmlXPathOrderDocElems() was called in order to index the elements of
91* a tree in document order; Libxslt does such an indexing, thus it will
92* benefit from this optimization.
93*/
94#define XP_OPTIMIZED_NON_ELEM_COMPARISON
95
96/*
97* XP_OPTIMIZED_FILTER_FIRST:
98* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99* in a way, that it stop evaluation at the first node.
100*/
101#define XP_OPTIMIZED_FILTER_FIRST
102
103/*
104* XP_DEBUG_OBJ_USAGE:
105* Internal flag to enable tracking of how much XPath objects have been
106* created.
107*/
108/* #define XP_DEBUG_OBJ_USAGE */
109
110/*
111 * XPATH_MAX_STEPS:
112 * when compiling an XPath expression we arbitrary limit the maximum
113 * number of step operation in the compiled expression. 1000000 is
114 * an insanely large value which should never be reached under normal
115 * circumstances
116 */
117#define XPATH_MAX_STEPS 1000000
118
119/*
120 * XPATH_MAX_STACK_DEPTH:
121 * when evaluating an XPath expression we arbitrary limit the maximum
122 * number of object allowed to be pushed on the stack. 1000000 is
123 * an insanely large value which should never be reached under normal
124 * circumstances
125 */
126#define XPATH_MAX_STACK_DEPTH 1000000
127
128/*
129 * XPATH_MAX_NODESET_LENGTH:
130 * when evaluating an XPath expression nodesets are created and we
131 * arbitrary limit the maximum length of those node set. 10000000 is
132 * an insanely large value which should never be reached under normal
133 * circumstances, one would first need to construct an in memory tree
134 * with more than 10 millions nodes.
135 */
136#define XPATH_MAX_NODESET_LENGTH 10000000
137
138/*
139 * XPATH_MAX_RECRUSION_DEPTH:
140 * Maximum amount of nested functions calls when parsing or evaluating
141 * expressions
142 */
143#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
144#define XPATH_MAX_RECURSION_DEPTH 500
145#else
146#define XPATH_MAX_RECURSION_DEPTH 5000
147#endif
148
149/*
150 * TODO:
151 * There are a few spots where some tests are done which depend upon ascii
152 * data. These should be enhanced for full UTF8 support (see particularly
153 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
154 */
155
156#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
157/**
158 * xmlXPathCmpNodesExt:
159 * @node1: the first node
160 * @node2: the second node
161 *
162 * Compare two nodes w.r.t document order.
163 * This one is optimized for handling of non-element nodes.
164 *
165 * Returns -2 in case of error 1 if first point < second point, 0 if
166 * it's the same node, -1 otherwise
167 */
168static int
169xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
170 int depth1, depth2;
171 int misc = 0, precedence1 = 0, precedence2 = 0;
172 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
173 xmlNodePtr cur, root;
174 ptrdiff_t l1, l2;
175
176 if ((node1 == NULL) || (node2 == NULL))
177 return(-2);
178
179 if (node1 == node2)
180 return(0);
181
182 /*
183 * a couple of optimizations which will avoid computations in most cases
184 */
185 switch (node1->type) {
186 case XML_ELEMENT_NODE:
187 if (node2->type == XML_ELEMENT_NODE) {
188 if ((0 > (ptrdiff_t) node1->content) &&
189 (0 > (ptrdiff_t) node2->content) &&
190 (node1->doc == node2->doc))
191 {
192 l1 = -((ptrdiff_t) node1->content);
193 l2 = -((ptrdiff_t) node2->content);
194 if (l1 < l2)
195 return(1);
196 if (l1 > l2)
197 return(-1);
198 } else
199 goto turtle_comparison;
200 }
201 break;
202 case XML_ATTRIBUTE_NODE:
203 precedence1 = 1; /* element is owner */
204 miscNode1 = node1;
205 node1 = node1->parent;
206 misc = 1;
207 break;
208 case XML_TEXT_NODE:
209 case XML_CDATA_SECTION_NODE:
210 case XML_COMMENT_NODE:
211 case XML_PI_NODE: {
212 miscNode1 = node1;
213 /*
214 * Find nearest element node.
215 */
216 if (node1->prev != NULL) {
217 do {
218 node1 = node1->prev;
219 if (node1->type == XML_ELEMENT_NODE) {
220 precedence1 = 3; /* element in prev-sibl axis */
221 break;
222 }
223 if (node1->prev == NULL) {
224 precedence1 = 2; /* element is parent */
225 /*
226 * URGENT TODO: Are there any cases, where the
227 * parent of such a node is not an element node?
228 */
229 node1 = node1->parent;
230 break;
231 }
232 } while (1);
233 } else {
234 precedence1 = 2; /* element is parent */
235 node1 = node1->parent;
236 }
237 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
238 (0 <= (ptrdiff_t) node1->content)) {
239 /*
240 * Fallback for whatever case.
241 */
242 node1 = miscNode1;
243 precedence1 = 0;
244 } else
245 misc = 1;
246 }
247 break;
248 case XML_NAMESPACE_DECL:
249 /*
250 * TODO: why do we return 1 for namespace nodes?
251 */
252 return(1);
253 default:
254 break;
255 }
256 switch (node2->type) {
257 case XML_ELEMENT_NODE:
258 break;
259 case XML_ATTRIBUTE_NODE:
260 precedence2 = 1; /* element is owner */
261 miscNode2 = node2;
262 node2 = node2->parent;
263 misc = 1;
264 break;
265 case XML_TEXT_NODE:
266 case XML_CDATA_SECTION_NODE:
267 case XML_COMMENT_NODE:
268 case XML_PI_NODE: {
269 miscNode2 = node2;
270 if (node2->prev != NULL) {
271 do {
272 node2 = node2->prev;
273 if (node2->type == XML_ELEMENT_NODE) {
274 precedence2 = 3; /* element in prev-sibl axis */
275 break;
276 }
277 if (node2->prev == NULL) {
278 precedence2 = 2; /* element is parent */
279 node2 = node2->parent;
280 break;
281 }
282 } while (1);
283 } else {
284 precedence2 = 2; /* element is parent */
285 node2 = node2->parent;
286 }
287 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
288 (0 <= (ptrdiff_t) node2->content))
289 {
290 node2 = miscNode2;
291 precedence2 = 0;
292 } else
293 misc = 1;
294 }
295 break;
296 case XML_NAMESPACE_DECL:
297 return(1);
298 default:
299 break;
300 }
301 if (misc) {
302 if (node1 == node2) {
303 if (precedence1 == precedence2) {
304 /*
305 * The ugly case; but normally there aren't many
306 * adjacent non-element nodes around.
307 */
308 cur = miscNode2->prev;
309 while (cur != NULL) {
310 if (cur == miscNode1)
311 return(1);
312 if (cur->type == XML_ELEMENT_NODE)
313 return(-1);
314 cur = cur->prev;
315 }
316 return (-1);
317 } else {
318 /*
319 * Evaluate based on higher precedence wrt to the element.
320 * TODO: This assumes attributes are sorted before content.
321 * Is this 100% correct?
322 */
323 if (precedence1 < precedence2)
324 return(1);
325 else
326 return(-1);
327 }
328 }
329 /*
330 * Special case: One of the helper-elements is contained by the other.
331 * <foo>
332 * <node2>
333 * <node1>Text-1(precedence1 == 2)</node1>
334 * </node2>
335 * Text-6(precedence2 == 3)
336 * </foo>
337 */
338 if ((precedence2 == 3) && (precedence1 > 1)) {
339 cur = node1->parent;
340 while (cur) {
341 if (cur == node2)
342 return(1);
343 cur = cur->parent;
344 }
345 }
346 if ((precedence1 == 3) && (precedence2 > 1)) {
347 cur = node2->parent;
348 while (cur) {
349 if (cur == node1)
350 return(-1);
351 cur = cur->parent;
352 }
353 }
354 }
355
356 /*
357 * Speedup using document order if available.
358 */
359 if ((node1->type == XML_ELEMENT_NODE) &&
360 (node2->type == XML_ELEMENT_NODE) &&
361 (0 > (ptrdiff_t) node1->content) &&
362 (0 > (ptrdiff_t) node2->content) &&
363 (node1->doc == node2->doc)) {
364
365 l1 = -((ptrdiff_t) node1->content);
366 l2 = -((ptrdiff_t) node2->content);
367 if (l1 < l2)
368 return(1);
369 if (l1 > l2)
370 return(-1);
371 }
372
373turtle_comparison:
374
375 if (node1 == node2->prev)
376 return(1);
377 if (node1 == node2->next)
378 return(-1);
379 /*
380 * compute depth to root
381 */
382 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
383 if (cur->parent == node1)
384 return(1);
385 depth2++;
386 }
387 root = cur;
388 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
389 if (cur->parent == node2)
390 return(-1);
391 depth1++;
392 }
393 /*
394 * Distinct document (or distinct entities :-( ) case.
395 */
396 if (root != cur) {
397 return(-2);
398 }
399 /*
400 * get the nearest common ancestor.
401 */
402 while (depth1 > depth2) {
403 depth1--;
404 node1 = node1->parent;
405 }
406 while (depth2 > depth1) {
407 depth2--;
408 node2 = node2->parent;
409 }
410 while (node1->parent != node2->parent) {
411 node1 = node1->parent;
412 node2 = node2->parent;
413 /* should not happen but just in case ... */
414 if ((node1 == NULL) || (node2 == NULL))
415 return(-2);
416 }
417 /*
418 * Find who's first.
419 */
420 if (node1 == node2->prev)
421 return(1);
422 if (node1 == node2->next)
423 return(-1);
424 /*
425 * Speedup using document order if available.
426 */
427 if ((node1->type == XML_ELEMENT_NODE) &&
428 (node2->type == XML_ELEMENT_NODE) &&
429 (0 > (ptrdiff_t) node1->content) &&
430 (0 > (ptrdiff_t) node2->content) &&
431 (node1->doc == node2->doc)) {
432
433 l1 = -((ptrdiff_t) node1->content);
434 l2 = -((ptrdiff_t) node2->content);
435 if (l1 < l2)
436 return(1);
437 if (l1 > l2)
438 return(-1);
439 }
440
441 for (cur = node1->next;cur != NULL;cur = cur->next)
442 if (cur == node2)
443 return(1);
444 return(-1); /* assume there is no sibling list corruption */
445}
446#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
447
448/*
449 * Wrapper for the Timsort algorithm from timsort.h
450 */
451#ifdef WITH_TIM_SORT
452#define SORT_NAME libxml_domnode
453#define SORT_TYPE xmlNodePtr
454/**
455 * wrap_cmp:
456 * @x: a node
457 * @y: another node
458 *
459 * Comparison function for the Timsort implementation
460 *
461 * Returns -2 in case of error -1 if first point < second point, 0 if
462 * it's the same node, +1 otherwise
463 */
464static
465int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
466#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
467 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
468 {
469 int res = xmlXPathCmpNodesExt(x, y);
470 return res == -2 ? res : -res;
471 }
472#else
473 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
474 {
475 int res = xmlXPathCmpNodes(x, y);
476 return res == -2 ? res : -res;
477 }
478#endif
479#define SORT_CMP(x, y) (wrap_cmp(x, y))
480#include "timsort.h"
481#endif /* WITH_TIM_SORT */
482
483#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
484
485/************************************************************************
486 * *
487 * Floating point stuff *
488 * *
489 ************************************************************************/
490
491double xmlXPathNAN = 0.0;
492double xmlXPathPINF = 0.0;
493double xmlXPathNINF = 0.0;
494
495/**
496 * xmlXPathInit:
497 *
498 * Initialize the XPath environment
499 */
500ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
501void
502xmlXPathInit(void) {
503 /* MSVC doesn't allow division by zero in constant expressions. */
504 double zero = 0.0;
505 xmlXPathNAN = 0.0 / zero;
506 xmlXPathPINF = 1.0 / zero;
507 xmlXPathNINF = -xmlXPathPINF;
508}
509
510/**
511 * xmlXPathIsNaN:
512 * @val: a double value
513 *
514 * Returns 1 if the value is a NaN, 0 otherwise
515 */
516int
517xmlXPathIsNaN(double val) {
518#ifdef isnan
519 return isnan(val);
520#else
521 return !(val == val);
522#endif
523}
524
525/**
526 * xmlXPathIsInf:
527 * @val: a double value
528 *
529 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
530 */
531int
532xmlXPathIsInf(double val) {
533#ifdef isinf
534 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
535#else
536 if (val >= xmlXPathPINF)
537 return 1;
538 if (val <= -xmlXPathPINF)
539 return -1;
540 return 0;
541#endif
542}
543
544#endif /* SCHEMAS or XPATH */
545
546#ifdef LIBXML_XPATH_ENABLED
547
548/*
549 * TODO: when compatibility allows remove all "fake node libxslt" strings
550 * the test should just be name[0] = ' '
551 */
552#ifdef DEBUG_XPATH_EXPRESSION
553#define DEBUG_STEP
554#define DEBUG_EXPR
555#define DEBUG_EVAL_COUNTS
556#endif
557
558static xmlNs xmlXPathXMLNamespaceStruct = {
559 NULL,
560 XML_NAMESPACE_DECL,
561 XML_XML_NAMESPACE,
562 BAD_CAST "xml",
563 NULL,
564 NULL
565};
566static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
567#ifndef LIBXML_THREAD_ENABLED
568/*
569 * Optimizer is disabled only when threaded apps are detected while
570 * the library ain't compiled for thread safety.
571 */
572static int xmlXPathDisableOptimizer = 0;
573#endif
574
575/************************************************************************
576 * *
577 * Error handling routines *
578 * *
579 ************************************************************************/
580
581/**
582 * XP_ERRORNULL:
583 * @X: the error code
584 *
585 * Macro to raise an XPath error and return NULL.
586 */
587#define XP_ERRORNULL(X) \
588 { xmlXPathErr(ctxt, X); return(NULL); }
589
590/*
591 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
592 */
593static const char *xmlXPathErrorMessages[] = {
594 "Ok\n",
595 "Number encoding\n",
596 "Unfinished literal\n",
597 "Start of literal\n",
598 "Expected $ for variable reference\n",
599 "Undefined variable\n",
600 "Invalid predicate\n",
601 "Invalid expression\n",
602 "Missing closing curly brace\n",
603 "Unregistered function\n",
604 "Invalid operand\n",
605 "Invalid type\n",
606 "Invalid number of arguments\n",
607 "Invalid context size\n",
608 "Invalid context position\n",
609 "Memory allocation error\n",
610 "Syntax error\n",
611 "Resource error\n",
612 "Sub resource error\n",
613 "Undefined namespace prefix\n",
614 "Encoding error\n",
615 "Char out of XML range\n",
616 "Invalid or incomplete context\n",
617 "Stack usage error\n",
618 "Forbidden variable\n",
619 "Operation limit exceeded\n",
620 "Recursion limit exceeded\n",
621 "?? Unknown error ??\n" /* Must be last in the list! */
622};
623#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
624 sizeof(xmlXPathErrorMessages[0])) - 1)
625/**
626 * xmlXPathErrMemory:
627 * @ctxt: an XPath context
628 * @extra: extra information
629 *
630 * Handle a redefinition of attribute error
631 */
632static void
633xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
634{
635 if (ctxt != NULL) {
636 xmlResetError(&ctxt->lastError);
637 if (extra) {
638 xmlChar buf[200];
639
640 xmlStrPrintf(buf, 200,
641 "Memory allocation failed : %s\n",
642 extra);
643 ctxt->lastError.message = (char *) xmlStrdup(buf);
644 } else {
645 ctxt->lastError.message = (char *)
646 xmlStrdup(BAD_CAST "Memory allocation failed\n");
647 }
648 ctxt->lastError.domain = XML_FROM_XPATH;
649 ctxt->lastError.code = XML_ERR_NO_MEMORY;
650 if (ctxt->error != NULL)
651 ctxt->error(ctxt->userData, &ctxt->lastError);
652 } else {
653 if (extra)
654 __xmlRaiseError(NULL, NULL, NULL,
655 NULL, NULL, XML_FROM_XPATH,
656 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
657 extra, NULL, NULL, 0, 0,
658 "Memory allocation failed : %s\n", extra);
659 else
660 __xmlRaiseError(NULL, NULL, NULL,
661 NULL, NULL, XML_FROM_XPATH,
662 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
663 NULL, NULL, NULL, 0, 0,
664 "Memory allocation failed\n");
665 }
666}
667
668/**
669 * xmlXPathPErrMemory:
670 * @ctxt: an XPath parser context
671 * @extra: extra information
672 *
673 * Handle a redefinition of attribute error
674 */
675static void
676xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
677{
678 if (ctxt == NULL)
679 xmlXPathErrMemory(NULL, extra);
680 else {
681 ctxt->error = XPATH_MEMORY_ERROR;
682 xmlXPathErrMemory(ctxt->context, extra);
683 }
684}
685
686/**
687 * xmlXPathErr:
688 * @ctxt: a XPath parser context
689 * @error: the error code
690 *
691 * Handle an XPath error
692 */
693void
694xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
695{
696 if ((error < 0) || (error > MAXERRNO))
697 error = MAXERRNO;
698 if (ctxt == NULL) {
699 __xmlRaiseError(NULL, NULL, NULL,
700 NULL, NULL, XML_FROM_XPATH,
701 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
702 XML_ERR_ERROR, NULL, 0,
703 NULL, NULL, NULL, 0, 0,
704 "%s", xmlXPathErrorMessages[error]);
705 return;
706 }
707 ctxt->error = error;
708 if (ctxt->context == NULL) {
709 __xmlRaiseError(NULL, NULL, NULL,
710 NULL, NULL, XML_FROM_XPATH,
711 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
712 XML_ERR_ERROR, NULL, 0,
713 (const char *) ctxt->base, NULL, NULL,
714 ctxt->cur - ctxt->base, 0,
715 "%s", xmlXPathErrorMessages[error]);
716 return;
717 }
718
719 /* cleanup current last error */
720 xmlResetError(&ctxt->context->lastError);
721
722 ctxt->context->lastError.domain = XML_FROM_XPATH;
723 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
724 XPATH_EXPRESSION_OK;
725 ctxt->context->lastError.level = XML_ERR_ERROR;
726 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
727 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
728 ctxt->context->lastError.node = ctxt->context->debugNode;
729 if (ctxt->context->error != NULL) {
730 ctxt->context->error(ctxt->context->userData,
731 &ctxt->context->lastError);
732 } else {
733 __xmlRaiseError(NULL, NULL, NULL,
734 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
735 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
736 XML_ERR_ERROR, NULL, 0,
737 (const char *) ctxt->base, NULL, NULL,
738 ctxt->cur - ctxt->base, 0,
739 "%s", xmlXPathErrorMessages[error]);
740 }
741
742}
743
744/**
745 * xmlXPatherror:
746 * @ctxt: the XPath Parser context
747 * @file: the file name
748 * @line: the line number
749 * @no: the error number
750 *
751 * Formats an error message.
752 */
753void
754xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
755 int line ATTRIBUTE_UNUSED, int no) {
756 xmlXPathErr(ctxt, no);
757}
758
759/**
760 * xmlXPathCheckOpLimit:
761 * @ctxt: the XPath Parser context
762 * @opCount: the number of operations to be added
763 *
764 * Adds opCount to the running total of operations and returns -1 if the
765 * operation limit is exceeded. Returns 0 otherwise.
766 */
767static int
768xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
769 xmlXPathContextPtr xpctxt = ctxt->context;
770
771 if ((opCount > xpctxt->opLimit) ||
772 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
773 xpctxt->opCount = xpctxt->opLimit;
774 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
775 return(-1);
776 }
777
778 xpctxt->opCount += opCount;
779 return(0);
780}
781
782#define OP_LIMIT_EXCEEDED(ctxt, n) \
783 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
784
785/************************************************************************
786 * *
787 * Utilities *
788 * *
789 ************************************************************************/
790
791/**
792 * xsltPointerList:
793 *
794 * Pointer-list for various purposes.
795 */
796typedef struct _xmlPointerList xmlPointerList;
797typedef xmlPointerList *xmlPointerListPtr;
798struct _xmlPointerList {
799 void **items;
800 int number;
801 int size;
802};
803/*
804* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
805* and here, we should make the functions public.
806*/
807static int
808xmlPointerListAddSize(xmlPointerListPtr list,
809 void *item,
810 int initialSize)
811{
812 if (list->items == NULL) {
813 if (initialSize <= 0)
814 initialSize = 1;
815 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
816 if (list->items == NULL) {
817 xmlXPathErrMemory(NULL,
818 "xmlPointerListCreate: allocating item\n");
819 return(-1);
820 }
821 list->number = 0;
822 list->size = initialSize;
823 } else if (list->size <= list->number) {
824 if (list->size > 50000000) {
825 xmlXPathErrMemory(NULL,
826 "xmlPointerListAddSize: re-allocating item\n");
827 return(-1);
828 }
829 list->size *= 2;
830 list->items = (void **) xmlRealloc(list->items,
831 list->size * sizeof(void *));
832 if (list->items == NULL) {
833 xmlXPathErrMemory(NULL,
834 "xmlPointerListAddSize: re-allocating item\n");
835 list->size = 0;
836 return(-1);
837 }
838 }
839 list->items[list->number++] = item;
840 return(0);
841}
842
843/**
844 * xsltPointerListCreate:
845 *
846 * Creates an xsltPointerList structure.
847 *
848 * Returns a xsltPointerList structure or NULL in case of an error.
849 */
850static xmlPointerListPtr
851xmlPointerListCreate(int initialSize)
852{
853 xmlPointerListPtr ret;
854
855 ret = xmlMalloc(sizeof(xmlPointerList));
856 if (ret == NULL) {
857 xmlXPathErrMemory(NULL,
858 "xmlPointerListCreate: allocating item\n");
859 return (NULL);
860 }
861 memset(ret, 0, sizeof(xmlPointerList));
862 if (initialSize > 0) {
863 xmlPointerListAddSize(ret, NULL, initialSize);
864 ret->number = 0;
865 }
866 return (ret);
867}
868
869/**
870 * xsltPointerListFree:
871 *
872 * Frees the xsltPointerList structure. This does not free
873 * the content of the list.
874 */
875static void
876xmlPointerListFree(xmlPointerListPtr list)
877{
878 if (list == NULL)
879 return;
880 if (list->items != NULL)
881 xmlFree(list->items);
882 xmlFree(list);
883}
884
885/************************************************************************
886 * *
887 * Parser Types *
888 * *
889 ************************************************************************/
890
891/*
892 * Types are private:
893 */
894
895typedef enum {
896 XPATH_OP_END=0,
897 XPATH_OP_AND,
898 XPATH_OP_OR,
899 XPATH_OP_EQUAL,
900 XPATH_OP_CMP,
901 XPATH_OP_PLUS,
902 XPATH_OP_MULT,
903 XPATH_OP_UNION,
904 XPATH_OP_ROOT,
905 XPATH_OP_NODE,
906 XPATH_OP_COLLECT,
907 XPATH_OP_VALUE, /* 11 */
908 XPATH_OP_VARIABLE,
909 XPATH_OP_FUNCTION,
910 XPATH_OP_ARG,
911 XPATH_OP_PREDICATE,
912 XPATH_OP_FILTER, /* 16 */
913 XPATH_OP_SORT /* 17 */
914#ifdef LIBXML_XPTR_ENABLED
915 ,XPATH_OP_RANGETO
916#endif
917} xmlXPathOp;
918
919typedef enum {
920 AXIS_ANCESTOR = 1,
921 AXIS_ANCESTOR_OR_SELF,
922 AXIS_ATTRIBUTE,
923 AXIS_CHILD,
924 AXIS_DESCENDANT,
925 AXIS_DESCENDANT_OR_SELF,
926 AXIS_FOLLOWING,
927 AXIS_FOLLOWING_SIBLING,
928 AXIS_NAMESPACE,
929 AXIS_PARENT,
930 AXIS_PRECEDING,
931 AXIS_PRECEDING_SIBLING,
932 AXIS_SELF
933} xmlXPathAxisVal;
934
935typedef enum {
936 NODE_TEST_NONE = 0,
937 NODE_TEST_TYPE = 1,
938 NODE_TEST_PI = 2,
939 NODE_TEST_ALL = 3,
940 NODE_TEST_NS = 4,
941 NODE_TEST_NAME = 5
942} xmlXPathTestVal;
943
944typedef enum {
945 NODE_TYPE_NODE = 0,
946 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
947 NODE_TYPE_TEXT = XML_TEXT_NODE,
948 NODE_TYPE_PI = XML_PI_NODE
949} xmlXPathTypeVal;
950
951typedef struct _xmlXPathStepOp xmlXPathStepOp;
952typedef xmlXPathStepOp *xmlXPathStepOpPtr;
953struct _xmlXPathStepOp {
954 xmlXPathOp op; /* The identifier of the operation */
955 int ch1; /* First child */
956 int ch2; /* Second child */
957 int value;
958 int value2;
959 int value3;
960 void *value4;
961 void *value5;
962 xmlXPathFunction cache;
963 void *cacheURI;
964};
965
966struct _xmlXPathCompExpr {
967 int nbStep; /* Number of steps in this expression */
968 int maxStep; /* Maximum number of steps allocated */
969 xmlXPathStepOp *steps; /* ops for computation of this expression */
970 int last; /* index of last step in expression */
971 xmlChar *expr; /* the expression being computed */
972 xmlDictPtr dict; /* the dictionary to use if any */
973#ifdef DEBUG_EVAL_COUNTS
974 int nb;
975 xmlChar *string;
976#endif
977#ifdef XPATH_STREAMING
978 xmlPatternPtr stream;
979#endif
980};
981
982/************************************************************************
983 * *
984 * Forward declarations *
985 * *
986 ************************************************************************/
987static void
988xmlXPathFreeValueTree(xmlNodeSetPtr obj);
989static void
990xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
991static int
992xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
993 xmlXPathStepOpPtr op, xmlNodePtr *first);
994static int
995xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
996 xmlXPathStepOpPtr op,
997 int isPredicate);
998static void
999xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1000
1001/************************************************************************
1002 * *
1003 * Parser Type functions *
1004 * *
1005 ************************************************************************/
1006
1007/**
1008 * xmlXPathNewCompExpr:
1009 *
1010 * Create a new Xpath component
1011 *
1012 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1013 */
1014static xmlXPathCompExprPtr
1015xmlXPathNewCompExpr(void) {
1016 xmlXPathCompExprPtr cur;
1017
1018 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1019 if (cur == NULL) {
1020 xmlXPathErrMemory(NULL, "allocating component\n");
1021 return(NULL);
1022 }
1023 memset(cur, 0, sizeof(xmlXPathCompExpr));
1024 cur->maxStep = 10;
1025 cur->nbStep = 0;
1026 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1027 sizeof(xmlXPathStepOp));
1028 if (cur->steps == NULL) {
1029 xmlXPathErrMemory(NULL, "allocating steps\n");
1030 xmlFree(cur);
1031 return(NULL);
1032 }
1033 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1034 cur->last = -1;
1035#ifdef DEBUG_EVAL_COUNTS
1036 cur->nb = 0;
1037#endif
1038 return(cur);
1039}
1040
1041/**
1042 * xmlXPathFreeCompExpr:
1043 * @comp: an XPATH comp
1044 *
1045 * Free up the memory allocated by @comp
1046 */
1047void
1048xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1049{
1050 xmlXPathStepOpPtr op;
1051 int i;
1052
1053 if (comp == NULL)
1054 return;
1055 if (comp->dict == NULL) {
1056 for (i = 0; i < comp->nbStep; i++) {
1057 op = &comp->steps[i];
1058 if (op->value4 != NULL) {
1059 if (op->op == XPATH_OP_VALUE)
1060 xmlXPathFreeObject(op->value4);
1061 else
1062 xmlFree(op->value4);
1063 }
1064 if (op->value5 != NULL)
1065 xmlFree(op->value5);
1066 }
1067 } else {
1068 for (i = 0; i < comp->nbStep; i++) {
1069 op = &comp->steps[i];
1070 if (op->value4 != NULL) {
1071 if (op->op == XPATH_OP_VALUE)
1072 xmlXPathFreeObject(op->value4);
1073 }
1074 }
1075 xmlDictFree(comp->dict);
1076 }
1077 if (comp->steps != NULL) {
1078 xmlFree(comp->steps);
1079 }
1080#ifdef DEBUG_EVAL_COUNTS
1081 if (comp->string != NULL) {
1082 xmlFree(comp->string);
1083 }
1084#endif
1085#ifdef XPATH_STREAMING
1086 if (comp->stream != NULL) {
1087 xmlFreePatternList(comp->stream);
1088 }
1089#endif
1090 if (comp->expr != NULL) {
1091 xmlFree(comp->expr);
1092 }
1093
1094 xmlFree(comp);
1095}
1096
1097/**
1098 * xmlXPathCompExprAdd:
1099 * @comp: the compiled expression
1100 * @ch1: first child index
1101 * @ch2: second child index
1102 * @op: an op
1103 * @value: the first int value
1104 * @value2: the second int value
1105 * @value3: the third int value
1106 * @value4: the first string value
1107 * @value5: the second string value
1108 *
1109 * Add a step to an XPath Compiled Expression
1110 *
1111 * Returns -1 in case of failure, the index otherwise
1112 */
1113static int
1114xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1115 xmlXPathOp op, int value,
1116 int value2, int value3, void *value4, void *value5) {
1117 xmlXPathCompExprPtr comp = ctxt->comp;
1118 if (comp->nbStep >= comp->maxStep) {
1119 xmlXPathStepOp *real;
1120
1121 if (comp->maxStep >= XPATH_MAX_STEPS) {
1122 xmlXPathPErrMemory(ctxt, "adding step\n");
1123 return(-1);
1124 }
1125 comp->maxStep *= 2;
1126 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1127 comp->maxStep * sizeof(xmlXPathStepOp));
1128 if (real == NULL) {
1129 comp->maxStep /= 2;
1130 xmlXPathPErrMemory(ctxt, "adding step\n");
1131 return(-1);
1132 }
1133 comp->steps = real;
1134 }
1135 comp->last = comp->nbStep;
1136 comp->steps[comp->nbStep].ch1 = ch1;
1137 comp->steps[comp->nbStep].ch2 = ch2;
1138 comp->steps[comp->nbStep].op = op;
1139 comp->steps[comp->nbStep].value = value;
1140 comp->steps[comp->nbStep].value2 = value2;
1141 comp->steps[comp->nbStep].value3 = value3;
1142 if ((comp->dict != NULL) &&
1143 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1144 (op == XPATH_OP_COLLECT))) {
1145 if (value4 != NULL) {
1146 comp->steps[comp->nbStep].value4 = (xmlChar *)
1147 (void *)xmlDictLookup(comp->dict, value4, -1);
1148 xmlFree(value4);
1149 } else
1150 comp->steps[comp->nbStep].value4 = NULL;
1151 if (value5 != NULL) {
1152 comp->steps[comp->nbStep].value5 = (xmlChar *)
1153 (void *)xmlDictLookup(comp->dict, value5, -1);
1154 xmlFree(value5);
1155 } else
1156 comp->steps[comp->nbStep].value5 = NULL;
1157 } else {
1158 comp->steps[comp->nbStep].value4 = value4;
1159 comp->steps[comp->nbStep].value5 = value5;
1160 }
1161 comp->steps[comp->nbStep].cache = NULL;
1162 return(comp->nbStep++);
1163}
1164
1165/**
1166 * xmlXPathCompSwap:
1167 * @comp: the compiled expression
1168 * @op: operation index
1169 *
1170 * Swaps 2 operations in the compiled expression
1171 */
1172static void
1173xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1174 int tmp;
1175
1176#ifndef LIBXML_THREAD_ENABLED
1177 /*
1178 * Since this manipulates possibly shared variables, this is
1179 * disabled if one detects that the library is used in a multithreaded
1180 * application
1181 */
1182 if (xmlXPathDisableOptimizer)
1183 return;
1184#endif
1185
1186 tmp = op->ch1;
1187 op->ch1 = op->ch2;
1188 op->ch2 = tmp;
1189}
1190
1191#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1192 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1193 (op), (val), (val2), (val3), (val4), (val5))
1194#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1195 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1196 (op), (val), (val2), (val3), (val4), (val5))
1197
1198#define PUSH_LEAVE_EXPR(op, val, val2) \
1199xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1200
1201#define PUSH_UNARY_EXPR(op, ch, val, val2) \
1202xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1203
1204#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1205xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1206 (val), (val2), 0 ,NULL ,NULL)
1207
1208/************************************************************************
1209 * *
1210 * XPath object cache structures *
1211 * *
1212 ************************************************************************/
1213
1214/* #define XP_DEFAULT_CACHE_ON */
1215
1216#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1217
1218typedef struct _xmlXPathContextCache xmlXPathContextCache;
1219typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1220struct _xmlXPathContextCache {
1221 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1222 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1223 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1224 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1225 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1226 int maxNodeset;
1227 int maxString;
1228 int maxBoolean;
1229 int maxNumber;
1230 int maxMisc;
1231#ifdef XP_DEBUG_OBJ_USAGE
1232 int dbgCachedAll;
1233 int dbgCachedNodeset;
1234 int dbgCachedString;
1235 int dbgCachedBool;
1236 int dbgCachedNumber;
1237 int dbgCachedPoint;
1238 int dbgCachedRange;
1239 int dbgCachedLocset;
1240 int dbgCachedUsers;
1241 int dbgCachedXSLTTree;
1242 int dbgCachedUndefined;
1243
1244
1245 int dbgReusedAll;
1246 int dbgReusedNodeset;
1247 int dbgReusedString;
1248 int dbgReusedBool;
1249 int dbgReusedNumber;
1250 int dbgReusedPoint;
1251 int dbgReusedRange;
1252 int dbgReusedLocset;
1253 int dbgReusedUsers;
1254 int dbgReusedXSLTTree;
1255 int dbgReusedUndefined;
1256
1257#endif
1258};
1259
1260/************************************************************************
1261 * *
1262 * Debugging related functions *
1263 * *
1264 ************************************************************************/
1265
1266#define STRANGE \
1267 xmlGenericError(xmlGenericErrorContext, \
1268 "Internal error at %s:%d\n", \
1269 __FILE__, __LINE__);
1270
1271#ifdef LIBXML_DEBUG_ENABLED
1272static void
1273xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1274 int i;
1275 char shift[100];
1276
1277 for (i = 0;((i < depth) && (i < 25));i++)
1278 shift[2 * i] = shift[2 * i + 1] = ' ';
1279 shift[2 * i] = shift[2 * i + 1] = 0;
1280 if (cur == NULL) {
1281 fprintf(output, "%s", shift);
1282 fprintf(output, "Node is NULL !\n");
1283 return;
1284
1285 }
1286
1287 if ((cur->type == XML_DOCUMENT_NODE) ||
1288 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1289 fprintf(output, "%s", shift);
1290 fprintf(output, " /\n");
1291 } else if (cur->type == XML_ATTRIBUTE_NODE)
1292 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1293 else
1294 xmlDebugDumpOneNode(output, cur, depth);
1295}
1296static void
1297xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1298 xmlNodePtr tmp;
1299 int i;
1300 char shift[100];
1301
1302 for (i = 0;((i < depth) && (i < 25));i++)
1303 shift[2 * i] = shift[2 * i + 1] = ' ';
1304 shift[2 * i] = shift[2 * i + 1] = 0;
1305 if (cur == NULL) {
1306 fprintf(output, "%s", shift);
1307 fprintf(output, "Node is NULL !\n");
1308 return;
1309
1310 }
1311
1312 while (cur != NULL) {
1313 tmp = cur;
1314 cur = cur->next;
1315 xmlDebugDumpOneNode(output, tmp, depth);
1316 }
1317}
1318
1319static void
1320xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1321 int i;
1322 char shift[100];
1323
1324 for (i = 0;((i < depth) && (i < 25));i++)
1325 shift[2 * i] = shift[2 * i + 1] = ' ';
1326 shift[2 * i] = shift[2 * i + 1] = 0;
1327
1328 if (cur == NULL) {
1329 fprintf(output, "%s", shift);
1330 fprintf(output, "NodeSet is NULL !\n");
1331 return;
1332
1333 }
1334
1335 if (cur != NULL) {
1336 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1337 for (i = 0;i < cur->nodeNr;i++) {
1338 fprintf(output, "%s", shift);
1339 fprintf(output, "%d", i + 1);
1340 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1341 }
1342 }
1343}
1344
1345static void
1346xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1347 int i;
1348 char shift[100];
1349
1350 for (i = 0;((i < depth) && (i < 25));i++)
1351 shift[2 * i] = shift[2 * i + 1] = ' ';
1352 shift[2 * i] = shift[2 * i + 1] = 0;
1353
1354 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1355 fprintf(output, "%s", shift);
1356 fprintf(output, "Value Tree is NULL !\n");
1357 return;
1358
1359 }
1360
1361 fprintf(output, "%s", shift);
1362 fprintf(output, "%d", i + 1);
1363 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1364}
1365#if defined(LIBXML_XPTR_ENABLED)
1366static void
1367xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1368 int i;
1369 char shift[100];
1370
1371 for (i = 0;((i < depth) && (i < 25));i++)
1372 shift[2 * i] = shift[2 * i + 1] = ' ';
1373 shift[2 * i] = shift[2 * i + 1] = 0;
1374
1375 if (cur == NULL) {
1376 fprintf(output, "%s", shift);
1377 fprintf(output, "LocationSet is NULL !\n");
1378 return;
1379
1380 }
1381
1382 for (i = 0;i < cur->locNr;i++) {
1383 fprintf(output, "%s", shift);
1384 fprintf(output, "%d : ", i + 1);
1385 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1386 }
1387}
1388#endif /* LIBXML_XPTR_ENABLED */
1389
1390/**
1391 * xmlXPathDebugDumpObject:
1392 * @output: the FILE * to dump the output
1393 * @cur: the object to inspect
1394 * @depth: indentation level
1395 *
1396 * Dump the content of the object for debugging purposes
1397 */
1398void
1399xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1400 int i;
1401 char shift[100];
1402
1403 if (output == NULL) return;
1404
1405 for (i = 0;((i < depth) && (i < 25));i++)
1406 shift[2 * i] = shift[2 * i + 1] = ' ';
1407 shift[2 * i] = shift[2 * i + 1] = 0;
1408
1409
1410 fprintf(output, "%s", shift);
1411
1412 if (cur == NULL) {
1413 fprintf(output, "Object is empty (NULL)\n");
1414 return;
1415 }
1416 switch(cur->type) {
1417 case XPATH_UNDEFINED:
1418 fprintf(output, "Object is uninitialized\n");
1419 break;
1420 case XPATH_NODESET:
1421 fprintf(output, "Object is a Node Set :\n");
1422 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1423 break;
1424 case XPATH_XSLT_TREE:
1425 fprintf(output, "Object is an XSLT value tree :\n");
1426 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1427 break;
1428 case XPATH_BOOLEAN:
1429 fprintf(output, "Object is a Boolean : ");
1430 if (cur->boolval) fprintf(output, "true\n");
1431 else fprintf(output, "false\n");
1432 break;
1433 case XPATH_NUMBER:
1434 switch (xmlXPathIsInf(cur->floatval)) {
1435 case 1:
1436 fprintf(output, "Object is a number : Infinity\n");
1437 break;
1438 case -1:
1439 fprintf(output, "Object is a number : -Infinity\n");
1440 break;
1441 default:
1442 if (xmlXPathIsNaN(cur->floatval)) {
1443 fprintf(output, "Object is a number : NaN\n");
1444 } else if (cur->floatval == 0) {
1445 /* Omit sign for negative zero. */
1446 fprintf(output, "Object is a number : 0\n");
1447 } else {
1448 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1449 }
1450 }
1451 break;
1452 case XPATH_STRING:
1453 fprintf(output, "Object is a string : ");
1454 xmlDebugDumpString(output, cur->stringval);
1455 fprintf(output, "\n");
1456 break;
1457 case XPATH_POINT:
1458 fprintf(output, "Object is a point : index %d in node", cur->index);
1459 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1460 fprintf(output, "\n");
1461 break;
1462 case XPATH_RANGE:
1463 if ((cur->user2 == NULL) ||
1464 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1465 fprintf(output, "Object is a collapsed range :\n");
1466 fprintf(output, "%s", shift);
1467 if (cur->index >= 0)
1468 fprintf(output, "index %d in ", cur->index);
1469 fprintf(output, "node\n");
1470 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1471 depth + 1);
1472 } else {
1473 fprintf(output, "Object is a range :\n");
1474 fprintf(output, "%s", shift);
1475 fprintf(output, "From ");
1476 if (cur->index >= 0)
1477 fprintf(output, "index %d in ", cur->index);
1478 fprintf(output, "node\n");
1479 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1480 depth + 1);
1481 fprintf(output, "%s", shift);
1482 fprintf(output, "To ");
1483 if (cur->index2 >= 0)
1484 fprintf(output, "index %d in ", cur->index2);
1485 fprintf(output, "node\n");
1486 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1487 depth + 1);
1488 fprintf(output, "\n");
1489 }
1490 break;
1491 case XPATH_LOCATIONSET:
1492#if defined(LIBXML_XPTR_ENABLED)
1493 fprintf(output, "Object is a Location Set:\n");
1494 xmlXPathDebugDumpLocationSet(output,
1495 (xmlLocationSetPtr) cur->user, depth);
1496#endif
1497 break;
1498 case XPATH_USERS:
1499 fprintf(output, "Object is user defined\n");
1500 break;
1501 }
1502}
1503
1504static void
1505xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1506 xmlXPathStepOpPtr op, int depth) {
1507 int i;
1508 char shift[100];
1509
1510 for (i = 0;((i < depth) && (i < 25));i++)
1511 shift[2 * i] = shift[2 * i + 1] = ' ';
1512 shift[2 * i] = shift[2 * i + 1] = 0;
1513
1514 fprintf(output, "%s", shift);
1515 if (op == NULL) {
1516 fprintf(output, "Step is NULL\n");
1517 return;
1518 }
1519 switch (op->op) {
1520 case XPATH_OP_END:
1521 fprintf(output, "END"); break;
1522 case XPATH_OP_AND:
1523 fprintf(output, "AND"); break;
1524 case XPATH_OP_OR:
1525 fprintf(output, "OR"); break;
1526 case XPATH_OP_EQUAL:
1527 if (op->value)
1528 fprintf(output, "EQUAL =");
1529 else
1530 fprintf(output, "EQUAL !=");
1531 break;
1532 case XPATH_OP_CMP:
1533 if (op->value)
1534 fprintf(output, "CMP <");
1535 else
1536 fprintf(output, "CMP >");
1537 if (!op->value2)
1538 fprintf(output, "=");
1539 break;
1540 case XPATH_OP_PLUS:
1541 if (op->value == 0)
1542 fprintf(output, "PLUS -");
1543 else if (op->value == 1)
1544 fprintf(output, "PLUS +");
1545 else if (op->value == 2)
1546 fprintf(output, "PLUS unary -");
1547 else if (op->value == 3)
1548 fprintf(output, "PLUS unary - -");
1549 break;
1550 case XPATH_OP_MULT:
1551 if (op->value == 0)
1552 fprintf(output, "MULT *");
1553 else if (op->value == 1)
1554 fprintf(output, "MULT div");
1555 else
1556 fprintf(output, "MULT mod");
1557 break;
1558 case XPATH_OP_UNION:
1559 fprintf(output, "UNION"); break;
1560 case XPATH_OP_ROOT:
1561 fprintf(output, "ROOT"); break;
1562 case XPATH_OP_NODE:
1563 fprintf(output, "NODE"); break;
1564 case XPATH_OP_SORT:
1565 fprintf(output, "SORT"); break;
1566 case XPATH_OP_COLLECT: {
1567 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1568 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1569 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1570 const xmlChar *prefix = op->value4;
1571 const xmlChar *name = op->value5;
1572
1573 fprintf(output, "COLLECT ");
1574 switch (axis) {
1575 case AXIS_ANCESTOR:
1576 fprintf(output, " 'ancestors' "); break;
1577 case AXIS_ANCESTOR_OR_SELF:
1578 fprintf(output, " 'ancestors-or-self' "); break;
1579 case AXIS_ATTRIBUTE:
1580 fprintf(output, " 'attributes' "); break;
1581 case AXIS_CHILD:
1582 fprintf(output, " 'child' "); break;
1583 case AXIS_DESCENDANT:
1584 fprintf(output, " 'descendant' "); break;
1585 case AXIS_DESCENDANT_OR_SELF:
1586 fprintf(output, " 'descendant-or-self' "); break;
1587 case AXIS_FOLLOWING:
1588 fprintf(output, " 'following' "); break;
1589 case AXIS_FOLLOWING_SIBLING:
1590 fprintf(output, " 'following-siblings' "); break;
1591 case AXIS_NAMESPACE:
1592 fprintf(output, " 'namespace' "); break;
1593 case AXIS_PARENT:
1594 fprintf(output, " 'parent' "); break;
1595 case AXIS_PRECEDING:
1596 fprintf(output, " 'preceding' "); break;
1597 case AXIS_PRECEDING_SIBLING:
1598 fprintf(output, " 'preceding-sibling' "); break;
1599 case AXIS_SELF:
1600 fprintf(output, " 'self' "); break;
1601 }
1602 switch (test) {
1603 case NODE_TEST_NONE:
1604 fprintf(output, "'none' "); break;
1605 case NODE_TEST_TYPE:
1606 fprintf(output, "'type' "); break;
1607 case NODE_TEST_PI:
1608 fprintf(output, "'PI' "); break;
1609 case NODE_TEST_ALL:
1610 fprintf(output, "'all' "); break;
1611 case NODE_TEST_NS:
1612 fprintf(output, "'namespace' "); break;
1613 case NODE_TEST_NAME:
1614 fprintf(output, "'name' "); break;
1615 }
1616 switch (type) {
1617 case NODE_TYPE_NODE:
1618 fprintf(output, "'node' "); break;
1619 case NODE_TYPE_COMMENT:
1620 fprintf(output, "'comment' "); break;
1621 case NODE_TYPE_TEXT:
1622 fprintf(output, "'text' "); break;
1623 case NODE_TYPE_PI:
1624 fprintf(output, "'PI' "); break;
1625 }
1626 if (prefix != NULL)
1627 fprintf(output, "%s:", prefix);
1628 if (name != NULL)
1629 fprintf(output, "%s", (const char *) name);
1630 break;
1631
1632 }
1633 case XPATH_OP_VALUE: {
1634 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1635
1636 fprintf(output, "ELEM ");
1637 xmlXPathDebugDumpObject(output, object, 0);
1638 goto finish;
1639 }
1640 case XPATH_OP_VARIABLE: {
1641 const xmlChar *prefix = op->value5;
1642 const xmlChar *name = op->value4;
1643
1644 if (prefix != NULL)
1645 fprintf(output, "VARIABLE %s:%s", prefix, name);
1646 else
1647 fprintf(output, "VARIABLE %s", name);
1648 break;
1649 }
1650 case XPATH_OP_FUNCTION: {
1651 int nbargs = op->value;
1652 const xmlChar *prefix = op->value5;
1653 const xmlChar *name = op->value4;
1654
1655 if (prefix != NULL)
1656 fprintf(output, "FUNCTION %s:%s(%d args)",
1657 prefix, name, nbargs);
1658 else
1659 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1660 break;
1661 }
1662 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1663 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1664 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1665#ifdef LIBXML_XPTR_ENABLED
1666 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1667#endif
1668 default:
1669 fprintf(output, "UNKNOWN %d\n", op->op); return;
1670 }
1671 fprintf(output, "\n");
1672finish:
1673 if (op->ch1 >= 0)
1674 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1675 if (op->ch2 >= 0)
1676 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1677}
1678
1679/**
1680 * xmlXPathDebugDumpCompExpr:
1681 * @output: the FILE * for the output
1682 * @comp: the precompiled XPath expression
1683 * @depth: the indentation level.
1684 *
1685 * Dumps the tree of the compiled XPath expression.
1686 */
1687void
1688xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1689 int depth) {
1690 int i;
1691 char shift[100];
1692
1693 if ((output == NULL) || (comp == NULL)) return;
1694
1695 for (i = 0;((i < depth) && (i < 25));i++)
1696 shift[2 * i] = shift[2 * i + 1] = ' ';
1697 shift[2 * i] = shift[2 * i + 1] = 0;
1698
1699 fprintf(output, "%s", shift);
1700
1701#ifdef XPATH_STREAMING
1702 if (comp->stream) {
1703 fprintf(output, "Streaming Expression\n");
1704 } else
1705#endif
1706 {
1707 fprintf(output, "Compiled Expression : %d elements\n",
1708 comp->nbStep);
1709 i = comp->last;
1710 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1711 }
1712}
1713
1714#ifdef XP_DEBUG_OBJ_USAGE
1715
1716/*
1717* XPath object usage related debugging variables.
1718*/
1719static int xmlXPathDebugObjCounterUndefined = 0;
1720static int xmlXPathDebugObjCounterNodeset = 0;
1721static int xmlXPathDebugObjCounterBool = 0;
1722static int xmlXPathDebugObjCounterNumber = 0;
1723static int xmlXPathDebugObjCounterString = 0;
1724static int xmlXPathDebugObjCounterPoint = 0;
1725static int xmlXPathDebugObjCounterRange = 0;
1726static int xmlXPathDebugObjCounterLocset = 0;
1727static int xmlXPathDebugObjCounterUsers = 0;
1728static int xmlXPathDebugObjCounterXSLTTree = 0;
1729static int xmlXPathDebugObjCounterAll = 0;
1730
1731static int xmlXPathDebugObjTotalUndefined = 0;
1732static int xmlXPathDebugObjTotalNodeset = 0;
1733static int xmlXPathDebugObjTotalBool = 0;
1734static int xmlXPathDebugObjTotalNumber = 0;
1735static int xmlXPathDebugObjTotalString = 0;
1736static int xmlXPathDebugObjTotalPoint = 0;
1737static int xmlXPathDebugObjTotalRange = 0;
1738static int xmlXPathDebugObjTotalLocset = 0;
1739static int xmlXPathDebugObjTotalUsers = 0;
1740static int xmlXPathDebugObjTotalXSLTTree = 0;
1741static int xmlXPathDebugObjTotalAll = 0;
1742
1743static int xmlXPathDebugObjMaxUndefined = 0;
1744static int xmlXPathDebugObjMaxNodeset = 0;
1745static int xmlXPathDebugObjMaxBool = 0;
1746static int xmlXPathDebugObjMaxNumber = 0;
1747static int xmlXPathDebugObjMaxString = 0;
1748static int xmlXPathDebugObjMaxPoint = 0;
1749static int xmlXPathDebugObjMaxRange = 0;
1750static int xmlXPathDebugObjMaxLocset = 0;
1751static int xmlXPathDebugObjMaxUsers = 0;
1752static int xmlXPathDebugObjMaxXSLTTree = 0;
1753static int xmlXPathDebugObjMaxAll = 0;
1754
1755static void
1756xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1757{
1758 if (ctxt != NULL) {
1759 if (ctxt->cache != NULL) {
1760 xmlXPathContextCachePtr cache =
1761 (xmlXPathContextCachePtr) ctxt->cache;
1762
1763 cache->dbgCachedAll = 0;
1764 cache->dbgCachedNodeset = 0;
1765 cache->dbgCachedString = 0;
1766 cache->dbgCachedBool = 0;
1767 cache->dbgCachedNumber = 0;
1768 cache->dbgCachedPoint = 0;
1769 cache->dbgCachedRange = 0;
1770 cache->dbgCachedLocset = 0;
1771 cache->dbgCachedUsers = 0;
1772 cache->dbgCachedXSLTTree = 0;
1773 cache->dbgCachedUndefined = 0;
1774
1775 cache->dbgReusedAll = 0;
1776 cache->dbgReusedNodeset = 0;
1777 cache->dbgReusedString = 0;
1778 cache->dbgReusedBool = 0;
1779 cache->dbgReusedNumber = 0;
1780 cache->dbgReusedPoint = 0;
1781 cache->dbgReusedRange = 0;
1782 cache->dbgReusedLocset = 0;
1783 cache->dbgReusedUsers = 0;
1784 cache->dbgReusedXSLTTree = 0;
1785 cache->dbgReusedUndefined = 0;
1786 }
1787 }
1788
1789 xmlXPathDebugObjCounterUndefined = 0;
1790 xmlXPathDebugObjCounterNodeset = 0;
1791 xmlXPathDebugObjCounterBool = 0;
1792 xmlXPathDebugObjCounterNumber = 0;
1793 xmlXPathDebugObjCounterString = 0;
1794 xmlXPathDebugObjCounterPoint = 0;
1795 xmlXPathDebugObjCounterRange = 0;
1796 xmlXPathDebugObjCounterLocset = 0;
1797 xmlXPathDebugObjCounterUsers = 0;
1798 xmlXPathDebugObjCounterXSLTTree = 0;
1799 xmlXPathDebugObjCounterAll = 0;
1800
1801 xmlXPathDebugObjTotalUndefined = 0;
1802 xmlXPathDebugObjTotalNodeset = 0;
1803 xmlXPathDebugObjTotalBool = 0;
1804 xmlXPathDebugObjTotalNumber = 0;
1805 xmlXPathDebugObjTotalString = 0;
1806 xmlXPathDebugObjTotalPoint = 0;
1807 xmlXPathDebugObjTotalRange = 0;
1808 xmlXPathDebugObjTotalLocset = 0;
1809 xmlXPathDebugObjTotalUsers = 0;
1810 xmlXPathDebugObjTotalXSLTTree = 0;
1811 xmlXPathDebugObjTotalAll = 0;
1812
1813 xmlXPathDebugObjMaxUndefined = 0;
1814 xmlXPathDebugObjMaxNodeset = 0;
1815 xmlXPathDebugObjMaxBool = 0;
1816 xmlXPathDebugObjMaxNumber = 0;
1817 xmlXPathDebugObjMaxString = 0;
1818 xmlXPathDebugObjMaxPoint = 0;
1819 xmlXPathDebugObjMaxRange = 0;
1820 xmlXPathDebugObjMaxLocset = 0;
1821 xmlXPathDebugObjMaxUsers = 0;
1822 xmlXPathDebugObjMaxXSLTTree = 0;
1823 xmlXPathDebugObjMaxAll = 0;
1824
1825}
1826
1827static void
1828xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1829 xmlXPathObjectType objType)
1830{
1831 int isCached = 0;
1832
1833 if (ctxt != NULL) {
1834 if (ctxt->cache != NULL) {
1835 xmlXPathContextCachePtr cache =
1836 (xmlXPathContextCachePtr) ctxt->cache;
1837
1838 isCached = 1;
1839
1840 cache->dbgReusedAll++;
1841 switch (objType) {
1842 case XPATH_UNDEFINED:
1843 cache->dbgReusedUndefined++;
1844 break;
1845 case XPATH_NODESET:
1846 cache->dbgReusedNodeset++;
1847 break;
1848 case XPATH_BOOLEAN:
1849 cache->dbgReusedBool++;
1850 break;
1851 case XPATH_NUMBER:
1852 cache->dbgReusedNumber++;
1853 break;
1854 case XPATH_STRING:
1855 cache->dbgReusedString++;
1856 break;
1857 case XPATH_POINT:
1858 cache->dbgReusedPoint++;
1859 break;
1860 case XPATH_RANGE:
1861 cache->dbgReusedRange++;
1862 break;
1863 case XPATH_LOCATIONSET:
1864 cache->dbgReusedLocset++;
1865 break;
1866 case XPATH_USERS:
1867 cache->dbgReusedUsers++;
1868 break;
1869 case XPATH_XSLT_TREE:
1870 cache->dbgReusedXSLTTree++;
1871 break;
1872 default:
1873 break;
1874 }
1875 }
1876 }
1877
1878 switch (objType) {
1879 case XPATH_UNDEFINED:
1880 if (! isCached)
1881 xmlXPathDebugObjTotalUndefined++;
1882 xmlXPathDebugObjCounterUndefined++;
1883 if (xmlXPathDebugObjCounterUndefined >
1884 xmlXPathDebugObjMaxUndefined)
1885 xmlXPathDebugObjMaxUndefined =
1886 xmlXPathDebugObjCounterUndefined;
1887 break;
1888 case XPATH_NODESET:
1889 if (! isCached)
1890 xmlXPathDebugObjTotalNodeset++;
1891 xmlXPathDebugObjCounterNodeset++;
1892 if (xmlXPathDebugObjCounterNodeset >
1893 xmlXPathDebugObjMaxNodeset)
1894 xmlXPathDebugObjMaxNodeset =
1895 xmlXPathDebugObjCounterNodeset;
1896 break;
1897 case XPATH_BOOLEAN:
1898 if (! isCached)
1899 xmlXPathDebugObjTotalBool++;
1900 xmlXPathDebugObjCounterBool++;
1901 if (xmlXPathDebugObjCounterBool >
1902 xmlXPathDebugObjMaxBool)
1903 xmlXPathDebugObjMaxBool =
1904 xmlXPathDebugObjCounterBool;
1905 break;
1906 case XPATH_NUMBER:
1907 if (! isCached)
1908 xmlXPathDebugObjTotalNumber++;
1909 xmlXPathDebugObjCounterNumber++;
1910 if (xmlXPathDebugObjCounterNumber >
1911 xmlXPathDebugObjMaxNumber)
1912 xmlXPathDebugObjMaxNumber =
1913 xmlXPathDebugObjCounterNumber;
1914 break;
1915 case XPATH_STRING:
1916 if (! isCached)
1917 xmlXPathDebugObjTotalString++;
1918 xmlXPathDebugObjCounterString++;
1919 if (xmlXPathDebugObjCounterString >
1920 xmlXPathDebugObjMaxString)
1921 xmlXPathDebugObjMaxString =
1922 xmlXPathDebugObjCounterString;
1923 break;
1924 case XPATH_POINT:
1925 if (! isCached)
1926 xmlXPathDebugObjTotalPoint++;
1927 xmlXPathDebugObjCounterPoint++;
1928 if (xmlXPathDebugObjCounterPoint >
1929 xmlXPathDebugObjMaxPoint)
1930 xmlXPathDebugObjMaxPoint =
1931 xmlXPathDebugObjCounterPoint;
1932 break;
1933 case XPATH_RANGE:
1934 if (! isCached)
1935 xmlXPathDebugObjTotalRange++;
1936 xmlXPathDebugObjCounterRange++;
1937 if (xmlXPathDebugObjCounterRange >
1938 xmlXPathDebugObjMaxRange)
1939 xmlXPathDebugObjMaxRange =
1940 xmlXPathDebugObjCounterRange;
1941 break;
1942 case XPATH_LOCATIONSET:
1943 if (! isCached)
1944 xmlXPathDebugObjTotalLocset++;
1945 xmlXPathDebugObjCounterLocset++;
1946 if (xmlXPathDebugObjCounterLocset >
1947 xmlXPathDebugObjMaxLocset)
1948 xmlXPathDebugObjMaxLocset =
1949 xmlXPathDebugObjCounterLocset;
1950 break;
1951 case XPATH_USERS:
1952 if (! isCached)
1953 xmlXPathDebugObjTotalUsers++;
1954 xmlXPathDebugObjCounterUsers++;
1955 if (xmlXPathDebugObjCounterUsers >
1956 xmlXPathDebugObjMaxUsers)
1957 xmlXPathDebugObjMaxUsers =
1958 xmlXPathDebugObjCounterUsers;
1959 break;
1960 case XPATH_XSLT_TREE:
1961 if (! isCached)
1962 xmlXPathDebugObjTotalXSLTTree++;
1963 xmlXPathDebugObjCounterXSLTTree++;
1964 if (xmlXPathDebugObjCounterXSLTTree >
1965 xmlXPathDebugObjMaxXSLTTree)
1966 xmlXPathDebugObjMaxXSLTTree =
1967 xmlXPathDebugObjCounterXSLTTree;
1968 break;
1969 default:
1970 break;
1971 }
1972 if (! isCached)
1973 xmlXPathDebugObjTotalAll++;
1974 xmlXPathDebugObjCounterAll++;
1975 if (xmlXPathDebugObjCounterAll >
1976 xmlXPathDebugObjMaxAll)
1977 xmlXPathDebugObjMaxAll =
1978 xmlXPathDebugObjCounterAll;
1979}
1980
1981static void
1982xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1983 xmlXPathObjectType objType)
1984{
1985 int isCached = 0;
1986
1987 if (ctxt != NULL) {
1988 if (ctxt->cache != NULL) {
1989 xmlXPathContextCachePtr cache =
1990 (xmlXPathContextCachePtr) ctxt->cache;
1991
1992 isCached = 1;
1993
1994 cache->dbgCachedAll++;
1995 switch (objType) {
1996 case XPATH_UNDEFINED:
1997 cache->dbgCachedUndefined++;
1998 break;
1999 case XPATH_NODESET:
2000 cache->dbgCachedNodeset++;
2001 break;
2002 case XPATH_BOOLEAN:
2003 cache->dbgCachedBool++;
2004 break;
2005 case XPATH_NUMBER:
2006 cache->dbgCachedNumber++;
2007 break;
2008 case XPATH_STRING:
2009 cache->dbgCachedString++;
2010 break;
2011 case XPATH_POINT:
2012 cache->dbgCachedPoint++;
2013 break;
2014 case XPATH_RANGE:
2015 cache->dbgCachedRange++;
2016 break;
2017 case XPATH_LOCATIONSET:
2018 cache->dbgCachedLocset++;
2019 break;
2020 case XPATH_USERS:
2021 cache->dbgCachedUsers++;
2022 break;
2023 case XPATH_XSLT_TREE:
2024 cache->dbgCachedXSLTTree++;
2025 break;
2026 default:
2027 break;
2028 }
2029
2030 }
2031 }
2032 switch (objType) {
2033 case XPATH_UNDEFINED:
2034 xmlXPathDebugObjCounterUndefined--;
2035 break;
2036 case XPATH_NODESET:
2037 xmlXPathDebugObjCounterNodeset--;
2038 break;
2039 case XPATH_BOOLEAN:
2040 xmlXPathDebugObjCounterBool--;
2041 break;
2042 case XPATH_NUMBER:
2043 xmlXPathDebugObjCounterNumber--;
2044 break;
2045 case XPATH_STRING:
2046 xmlXPathDebugObjCounterString--;
2047 break;
2048 case XPATH_POINT:
2049 xmlXPathDebugObjCounterPoint--;
2050 break;
2051 case XPATH_RANGE:
2052 xmlXPathDebugObjCounterRange--;
2053 break;
2054 case XPATH_LOCATIONSET:
2055 xmlXPathDebugObjCounterLocset--;
2056 break;
2057 case XPATH_USERS:
2058 xmlXPathDebugObjCounterUsers--;
2059 break;
2060 case XPATH_XSLT_TREE:
2061 xmlXPathDebugObjCounterXSLTTree--;
2062 break;
2063 default:
2064 break;
2065 }
2066 xmlXPathDebugObjCounterAll--;
2067}
2068
2069static void
2070xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2071{
2072 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2073 reqXSLTTree, reqUndefined;
2074 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2075 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2076 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2077 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2078 int leftObjs = xmlXPathDebugObjCounterAll;
2079
2080 reqAll = xmlXPathDebugObjTotalAll;
2081 reqNodeset = xmlXPathDebugObjTotalNodeset;
2082 reqString = xmlXPathDebugObjTotalString;
2083 reqBool = xmlXPathDebugObjTotalBool;
2084 reqNumber = xmlXPathDebugObjTotalNumber;
2085 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2086 reqUndefined = xmlXPathDebugObjTotalUndefined;
2087
2088 printf("# XPath object usage:\n");
2089
2090 if (ctxt != NULL) {
2091 if (ctxt->cache != NULL) {
2092 xmlXPathContextCachePtr cache =
2093 (xmlXPathContextCachePtr) ctxt->cache;
2094
2095 reAll = cache->dbgReusedAll;
2096 reqAll += reAll;
2097 reNodeset = cache->dbgReusedNodeset;
2098 reqNodeset += reNodeset;
2099 reString = cache->dbgReusedString;
2100 reqString += reString;
2101 reBool = cache->dbgReusedBool;
2102 reqBool += reBool;
2103 reNumber = cache->dbgReusedNumber;
2104 reqNumber += reNumber;
2105 reXSLTTree = cache->dbgReusedXSLTTree;
2106 reqXSLTTree += reXSLTTree;
2107 reUndefined = cache->dbgReusedUndefined;
2108 reqUndefined += reUndefined;
2109
2110 caAll = cache->dbgCachedAll;
2111 caBool = cache->dbgCachedBool;
2112 caNodeset = cache->dbgCachedNodeset;
2113 caString = cache->dbgCachedString;
2114 caNumber = cache->dbgCachedNumber;
2115 caXSLTTree = cache->dbgCachedXSLTTree;
2116 caUndefined = cache->dbgCachedUndefined;
2117
2118 if (cache->nodesetObjs)
2119 leftObjs -= cache->nodesetObjs->number;
2120 if (cache->stringObjs)
2121 leftObjs -= cache->stringObjs->number;
2122 if (cache->booleanObjs)
2123 leftObjs -= cache->booleanObjs->number;
2124 if (cache->numberObjs)
2125 leftObjs -= cache->numberObjs->number;
2126 if (cache->miscObjs)
2127 leftObjs -= cache->miscObjs->number;
2128 }
2129 }
2130
2131 printf("# all\n");
2132 printf("# total : %d\n", reqAll);
2133 printf("# left : %d\n", leftObjs);
2134 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2135 printf("# reused : %d\n", reAll);
2136 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2137
2138 printf("# node-sets\n");
2139 printf("# total : %d\n", reqNodeset);
2140 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2141 printf("# reused : %d\n", reNodeset);
2142 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2143
2144 printf("# strings\n");
2145 printf("# total : %d\n", reqString);
2146 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2147 printf("# reused : %d\n", reString);
2148 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2149
2150 printf("# booleans\n");
2151 printf("# total : %d\n", reqBool);
2152 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2153 printf("# reused : %d\n", reBool);
2154 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2155
2156 printf("# numbers\n");
2157 printf("# total : %d\n", reqNumber);
2158 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2159 printf("# reused : %d\n", reNumber);
2160 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2161
2162 printf("# XSLT result tree fragments\n");
2163 printf("# total : %d\n", reqXSLTTree);
2164 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2165 printf("# reused : %d\n", reXSLTTree);
2166 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2167
2168 printf("# undefined\n");
2169 printf("# total : %d\n", reqUndefined);
2170 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2171 printf("# reused : %d\n", reUndefined);
2172 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2173
2174}
2175
2176#endif /* XP_DEBUG_OBJ_USAGE */
2177
2178#endif /* LIBXML_DEBUG_ENABLED */
2179
2180/************************************************************************
2181 * *
2182 * XPath object caching *
2183 * *
2184 ************************************************************************/
2185
2186/**
2187 * xmlXPathNewCache:
2188 *
2189 * Create a new object cache
2190 *
2191 * Returns the xmlXPathCache just allocated.
2192 */
2193static xmlXPathContextCachePtr
2194xmlXPathNewCache(void)
2195{
2196 xmlXPathContextCachePtr ret;
2197
2198 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2199 if (ret == NULL) {
2200 xmlXPathErrMemory(NULL, "creating object cache\n");
2201 return(NULL);
2202 }
2203 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2204 ret->maxNodeset = 100;
2205 ret->maxString = 100;
2206 ret->maxBoolean = 100;
2207 ret->maxNumber = 100;
2208 ret->maxMisc = 100;
2209 return(ret);
2210}
2211
2212static void
2213xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2214{
2215 int i;
2216 xmlXPathObjectPtr obj;
2217
2218 if (list == NULL)
2219 return;
2220
2221 for (i = 0; i < list->number; i++) {
2222 obj = list->items[i];
2223 /*
2224 * Note that it is already assured that we don't need to
2225 * look out for namespace nodes in the node-set.
2226 */
2227 if (obj->nodesetval != NULL) {
2228 if (obj->nodesetval->nodeTab != NULL)
2229 xmlFree(obj->nodesetval->nodeTab);
2230 xmlFree(obj->nodesetval);
2231 }
2232 xmlFree(obj);
2233#ifdef XP_DEBUG_OBJ_USAGE
2234 xmlXPathDebugObjCounterAll--;
2235#endif
2236 }
2237 xmlPointerListFree(list);
2238}
2239
2240static void
2241xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2242{
2243 if (cache == NULL)
2244 return;
2245 if (cache->nodesetObjs)
2246 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2247 if (cache->stringObjs)
2248 xmlXPathCacheFreeObjectList(cache->stringObjs);
2249 if (cache->booleanObjs)
2250 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2251 if (cache->numberObjs)
2252 xmlXPathCacheFreeObjectList(cache->numberObjs);
2253 if (cache->miscObjs)
2254 xmlXPathCacheFreeObjectList(cache->miscObjs);
2255 xmlFree(cache);
2256}
2257
2258/**
2259 * xmlXPathContextSetCache:
2260 *
2261 * @ctxt: the XPath context
2262 * @active: enables/disables (creates/frees) the cache
2263 * @value: a value with semantics dependent on @options
2264 * @options: options (currently only the value 0 is used)
2265 *
2266 * Creates/frees an object cache on the XPath context.
2267 * If activates XPath objects (xmlXPathObject) will be cached internally
2268 * to be reused.
2269 * @options:
2270 * 0: This will set the XPath object caching:
2271 * @value:
2272 * This will set the maximum number of XPath objects
2273 * to be cached per slot
2274 * There are 5 slots for: node-set, string, number, boolean, and
2275 * misc objects. Use <0 for the default number (100).
2276 * Other values for @options have currently no effect.
2277 *
2278 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2279 */
2280int
2281xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2282 int active,
2283 int value,
2284 int options)
2285{
2286 if (ctxt == NULL)
2287 return(-1);
2288 if (active) {
2289 xmlXPathContextCachePtr cache;
2290
2291 if (ctxt->cache == NULL) {
2292 ctxt->cache = xmlXPathNewCache();
2293 if (ctxt->cache == NULL)
2294 return(-1);
2295 }
2296 cache = (xmlXPathContextCachePtr) ctxt->cache;
2297 if (options == 0) {
2298 if (value < 0)
2299 value = 100;
2300 cache->maxNodeset = value;
2301 cache->maxString = value;
2302 cache->maxNumber = value;
2303 cache->maxBoolean = value;
2304 cache->maxMisc = value;
2305 }
2306 } else if (ctxt->cache != NULL) {
2307 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2308 ctxt->cache = NULL;
2309 }
2310 return(0);
2311}
2312
2313/**
2314 * xmlXPathCacheWrapNodeSet:
2315 * @ctxt: the XPath context
2316 * @val: the NodePtr value
2317 *
2318 * This is the cached version of xmlXPathWrapNodeSet().
2319 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2320 *
2321 * Returns the created or reused object.
2322 */
2323static xmlXPathObjectPtr
2324xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2325{
2326 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2327 xmlXPathContextCachePtr cache =
2328 (xmlXPathContextCachePtr) ctxt->cache;
2329
2330 if ((cache->miscObjs != NULL) &&
2331 (cache->miscObjs->number != 0))
2332 {
2333 xmlXPathObjectPtr ret;
2334
2335 ret = (xmlXPathObjectPtr)
2336 cache->miscObjs->items[--cache->miscObjs->number];
2337 ret->type = XPATH_NODESET;
2338 ret->nodesetval = val;
2339#ifdef XP_DEBUG_OBJ_USAGE
2340 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2341#endif
2342 return(ret);
2343 }
2344 }
2345
2346 return(xmlXPathWrapNodeSet(val));
2347
2348}
2349
2350/**
2351 * xmlXPathCacheWrapString:
2352 * @ctxt: the XPath context
2353 * @val: the xmlChar * value
2354 *
2355 * This is the cached version of xmlXPathWrapString().
2356 * Wraps the @val string into an XPath object.
2357 *
2358 * Returns the created or reused object.
2359 */
2360static xmlXPathObjectPtr
2361xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2362{
2363 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2364 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2365
2366 if ((cache->stringObjs != NULL) &&
2367 (cache->stringObjs->number != 0))
2368 {
2369
2370 xmlXPathObjectPtr ret;
2371
2372 ret = (xmlXPathObjectPtr)
2373 cache->stringObjs->items[--cache->stringObjs->number];
2374 ret->type = XPATH_STRING;
2375 ret->stringval = val;
2376#ifdef XP_DEBUG_OBJ_USAGE
2377 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2378#endif
2379 return(ret);
2380 } else if ((cache->miscObjs != NULL) &&
2381 (cache->miscObjs->number != 0))
2382 {
2383 xmlXPathObjectPtr ret;
2384 /*
2385 * Fallback to misc-cache.
2386 */
2387 ret = (xmlXPathObjectPtr)
2388 cache->miscObjs->items[--cache->miscObjs->number];
2389
2390 ret->type = XPATH_STRING;
2391 ret->stringval = val;
2392#ifdef XP_DEBUG_OBJ_USAGE
2393 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2394#endif
2395 return(ret);
2396 }
2397 }
2398 return(xmlXPathWrapString(val));
2399}
2400
2401/**
2402 * xmlXPathCacheNewNodeSet:
2403 * @ctxt: the XPath context
2404 * @val: the NodePtr value
2405 *
2406 * This is the cached version of xmlXPathNewNodeSet().
2407 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2408 * it with the single Node @val
2409 *
2410 * Returns the created or reused object.
2411 */
2412static xmlXPathObjectPtr
2413xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2414{
2415 if ((ctxt != NULL) && (ctxt->cache)) {
2416 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2417
2418 if ((cache->nodesetObjs != NULL) &&
2419 (cache->nodesetObjs->number != 0))
2420 {
2421 xmlXPathObjectPtr ret;
2422 /*
2423 * Use the nodeset-cache.
2424 */
2425 ret = (xmlXPathObjectPtr)
2426 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2427 ret->type = XPATH_NODESET;
2428 ret->boolval = 0;
2429 if (val) {
2430 if ((ret->nodesetval->nodeMax == 0) ||
2431 (val->type == XML_NAMESPACE_DECL))
2432 {
2433 /* TODO: Check memory error. */
2434 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2435 } else {
2436 ret->nodesetval->nodeTab[0] = val;
2437 ret->nodesetval->nodeNr = 1;
2438 }
2439 }
2440#ifdef XP_DEBUG_OBJ_USAGE
2441 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2442#endif
2443 return(ret);
2444 } else if ((cache->miscObjs != NULL) &&
2445 (cache->miscObjs->number != 0))
2446 {
2447 xmlXPathObjectPtr ret;
2448 /*
2449 * Fallback to misc-cache.
2450 */
2451
2452 ret = (xmlXPathObjectPtr)
2453 cache->miscObjs->items[--cache->miscObjs->number];
2454
2455 ret->type = XPATH_NODESET;
2456 ret->boolval = 0;
2457 ret->nodesetval = xmlXPathNodeSetCreate(val);
2458 if (ret->nodesetval == NULL) {
2459 ctxt->lastError.domain = XML_FROM_XPATH;
2460 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2461 return(NULL);
2462 }
2463#ifdef XP_DEBUG_OBJ_USAGE
2464 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2465#endif
2466 return(ret);
2467 }
2468 }
2469 return(xmlXPathNewNodeSet(val));
2470}
2471
2472/**
2473 * xmlXPathCacheNewCString:
2474 * @ctxt: the XPath context
2475 * @val: the char * value
2476 *
2477 * This is the cached version of xmlXPathNewCString().
2478 * Acquire an xmlXPathObjectPtr of type string and of value @val
2479 *
2480 * Returns the created or reused object.
2481 */
2482static xmlXPathObjectPtr
2483xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2484{
2485 if ((ctxt != NULL) && (ctxt->cache)) {
2486 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2487
2488 if ((cache->stringObjs != NULL) &&
2489 (cache->stringObjs->number != 0))
2490 {
2491 xmlXPathObjectPtr ret;
2492
2493 ret = (xmlXPathObjectPtr)
2494 cache->stringObjs->items[--cache->stringObjs->number];
2495
2496 ret->type = XPATH_STRING;
2497 ret->stringval = xmlStrdup(BAD_CAST val);
2498#ifdef XP_DEBUG_OBJ_USAGE
2499 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2500#endif
2501 return(ret);
2502 } else if ((cache->miscObjs != NULL) &&
2503 (cache->miscObjs->number != 0))
2504 {
2505 xmlXPathObjectPtr ret;
2506
2507 ret = (xmlXPathObjectPtr)
2508 cache->miscObjs->items[--cache->miscObjs->number];
2509
2510 ret->type = XPATH_STRING;
2511 ret->stringval = xmlStrdup(BAD_CAST val);
2512#ifdef XP_DEBUG_OBJ_USAGE
2513 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2514#endif
2515 return(ret);
2516 }
2517 }
2518 return(xmlXPathNewCString(val));
2519}
2520
2521/**
2522 * xmlXPathCacheNewString:
2523 * @ctxt: the XPath context
2524 * @val: the xmlChar * value
2525 *
2526 * This is the cached version of xmlXPathNewString().
2527 * Acquire an xmlXPathObjectPtr of type string and of value @val
2528 *
2529 * Returns the created or reused object.
2530 */
2531static xmlXPathObjectPtr
2532xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2533{
2534 if ((ctxt != NULL) && (ctxt->cache)) {
2535 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2536
2537 if ((cache->stringObjs != NULL) &&
2538 (cache->stringObjs->number != 0))
2539 {
2540 xmlXPathObjectPtr ret;
2541
2542 ret = (xmlXPathObjectPtr)
2543 cache->stringObjs->items[--cache->stringObjs->number];
2544 ret->type = XPATH_STRING;
2545 if (val != NULL)
2546 ret->stringval = xmlStrdup(val);
2547 else
2548 ret->stringval = xmlStrdup((const xmlChar *)"");
2549#ifdef XP_DEBUG_OBJ_USAGE
2550 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2551#endif
2552 return(ret);
2553 } else if ((cache->miscObjs != NULL) &&
2554 (cache->miscObjs->number != 0))
2555 {
2556 xmlXPathObjectPtr ret;
2557
2558 ret = (xmlXPathObjectPtr)
2559 cache->miscObjs->items[--cache->miscObjs->number];
2560
2561 ret->type = XPATH_STRING;
2562 if (val != NULL)
2563 ret->stringval = xmlStrdup(val);
2564 else
2565 ret->stringval = xmlStrdup((const xmlChar *)"");
2566#ifdef XP_DEBUG_OBJ_USAGE
2567 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2568#endif
2569 return(ret);
2570 }
2571 }
2572 return(xmlXPathNewString(val));
2573}
2574
2575/**
2576 * xmlXPathCacheNewBoolean:
2577 * @ctxt: the XPath context
2578 * @val: the boolean value
2579 *
2580 * This is the cached version of xmlXPathNewBoolean().
2581 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2582 *
2583 * Returns the created or reused object.
2584 */
2585static xmlXPathObjectPtr
2586xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2587{
2588 if ((ctxt != NULL) && (ctxt->cache)) {
2589 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2590
2591 if ((cache->booleanObjs != NULL) &&
2592 (cache->booleanObjs->number != 0))
2593 {
2594 xmlXPathObjectPtr ret;
2595
2596 ret = (xmlXPathObjectPtr)
2597 cache->booleanObjs->items[--cache->booleanObjs->number];
2598 ret->type = XPATH_BOOLEAN;
2599 ret->boolval = (val != 0);
2600#ifdef XP_DEBUG_OBJ_USAGE
2601 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2602#endif
2603 return(ret);
2604 } else if ((cache->miscObjs != NULL) &&
2605 (cache->miscObjs->number != 0))
2606 {
2607 xmlXPathObjectPtr ret;
2608
2609 ret = (xmlXPathObjectPtr)
2610 cache->miscObjs->items[--cache->miscObjs->number];
2611
2612 ret->type = XPATH_BOOLEAN;
2613 ret->boolval = (val != 0);
2614#ifdef XP_DEBUG_OBJ_USAGE
2615 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2616#endif
2617 return(ret);
2618 }
2619 }
2620 return(xmlXPathNewBoolean(val));
2621}
2622
2623/**
2624 * xmlXPathCacheNewFloat:
2625 * @ctxt: the XPath context
2626 * @val: the double value
2627 *
2628 * This is the cached version of xmlXPathNewFloat().
2629 * Acquires an xmlXPathObjectPtr of type double and of value @val
2630 *
2631 * Returns the created or reused object.
2632 */
2633static xmlXPathObjectPtr
2634xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2635{
2636 if ((ctxt != NULL) && (ctxt->cache)) {
2637 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2638
2639 if ((cache->numberObjs != NULL) &&
2640 (cache->numberObjs->number != 0))
2641 {
2642 xmlXPathObjectPtr ret;
2643
2644 ret = (xmlXPathObjectPtr)
2645 cache->numberObjs->items[--cache->numberObjs->number];
2646 ret->type = XPATH_NUMBER;
2647 ret->floatval = val;
2648#ifdef XP_DEBUG_OBJ_USAGE
2649 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2650#endif
2651 return(ret);
2652 } else if ((cache->miscObjs != NULL) &&
2653 (cache->miscObjs->number != 0))
2654 {
2655 xmlXPathObjectPtr ret;
2656
2657 ret = (xmlXPathObjectPtr)
2658 cache->miscObjs->items[--cache->miscObjs->number];
2659
2660 ret->type = XPATH_NUMBER;
2661 ret->floatval = val;
2662#ifdef XP_DEBUG_OBJ_USAGE
2663 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2664#endif
2665 return(ret);
2666 }
2667 }
2668 return(xmlXPathNewFloat(val));
2669}
2670
2671/**
2672 * xmlXPathCacheConvertString:
2673 * @ctxt: the XPath context
2674 * @val: an XPath object
2675 *
2676 * This is the cached version of xmlXPathConvertString().
2677 * Converts an existing object to its string() equivalent
2678 *
2679 * Returns a created or reused object, the old one is freed (cached)
2680 * (or the operation is done directly on @val)
2681 */
2682
2683static xmlXPathObjectPtr
2684xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2685 xmlChar *res = NULL;
2686
2687 if (val == NULL)
2688 return(xmlXPathCacheNewCString(ctxt, ""));
2689
2690 switch (val->type) {
2691 case XPATH_UNDEFINED:
2692#ifdef DEBUG_EXPR
2693 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2694#endif
2695 break;
2696 case XPATH_NODESET:
2697 case XPATH_XSLT_TREE:
2698 res = xmlXPathCastNodeSetToString(val->nodesetval);
2699 break;
2700 case XPATH_STRING:
2701 return(val);
2702 case XPATH_BOOLEAN:
2703 res = xmlXPathCastBooleanToString(val->boolval);
2704 break;
2705 case XPATH_NUMBER:
2706 res = xmlXPathCastNumberToString(val->floatval);
2707 break;
2708 case XPATH_USERS:
2709 case XPATH_POINT:
2710 case XPATH_RANGE:
2711 case XPATH_LOCATIONSET:
2712 TODO;
2713 break;
2714 }
2715 xmlXPathReleaseObject(ctxt, val);
2716 if (res == NULL)
2717 return(xmlXPathCacheNewCString(ctxt, ""));
2718 return(xmlXPathCacheWrapString(ctxt, res));
2719}
2720
2721/**
2722 * xmlXPathCacheObjectCopy:
2723 * @ctxt: the XPath context
2724 * @val: the original object
2725 *
2726 * This is the cached version of xmlXPathObjectCopy().
2727 * Acquire a copy of a given object
2728 *
2729 * Returns a created or reused created object.
2730 */
2731static xmlXPathObjectPtr
2732xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2733{
2734 if (val == NULL)
2735 return(NULL);
2736
2737 if (XP_HAS_CACHE(ctxt)) {
2738 switch (val->type) {
2739 case XPATH_NODESET:
2740 return(xmlXPathCacheWrapNodeSet(ctxt,
2741 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2742 case XPATH_STRING:
2743 return(xmlXPathCacheNewString(ctxt, val->stringval));
2744 case XPATH_BOOLEAN:
2745 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2746 case XPATH_NUMBER:
2747 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2748 default:
2749 break;
2750 }
2751 }
2752 return(xmlXPathObjectCopy(val));
2753}
2754
2755/**
2756 * xmlXPathCacheConvertBoolean:
2757 * @ctxt: the XPath context
2758 * @val: an XPath object
2759 *
2760 * This is the cached version of xmlXPathConvertBoolean().
2761 * Converts an existing object to its boolean() equivalent
2762 *
2763 * Returns a created or reused object, the old one is freed (or the operation
2764 * is done directly on @val)
2765 */
2766static xmlXPathObjectPtr
2767xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2768 xmlXPathObjectPtr ret;
2769
2770 if (val == NULL)
2771 return(xmlXPathCacheNewBoolean(ctxt, 0));
2772 if (val->type == XPATH_BOOLEAN)
2773 return(val);
2774 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2775 xmlXPathReleaseObject(ctxt, val);
2776 return(ret);
2777}
2778
2779/**
2780 * xmlXPathCacheConvertNumber:
2781 * @ctxt: the XPath context
2782 * @val: an XPath object
2783 *
2784 * This is the cached version of xmlXPathConvertNumber().
2785 * Converts an existing object to its number() equivalent
2786 *
2787 * Returns a created or reused object, the old one is freed (or the operation
2788 * is done directly on @val)
2789 */
2790static xmlXPathObjectPtr
2791xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2792 xmlXPathObjectPtr ret;
2793
2794 if (val == NULL)
2795 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2796 if (val->type == XPATH_NUMBER)
2797 return(val);
2798 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2799 xmlXPathReleaseObject(ctxt, val);
2800 return(ret);
2801}
2802
2803/************************************************************************
2804 * *
2805 * Parser stacks related functions and macros *
2806 * *
2807 ************************************************************************/
2808
2809/**
2810 * xmlXPathSetFrame:
2811 * @ctxt: an XPath parser context
2812 *
2813 * Set the callee evaluation frame
2814 *
2815 * Returns the previous frame value to be restored once done
2816 */
2817static int
2818xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2819 int ret;
2820
2821 if (ctxt == NULL)
2822 return(0);
2823 ret = ctxt->valueFrame;
2824 ctxt->valueFrame = ctxt->valueNr;
2825 return(ret);
2826}
2827
2828/**
2829 * xmlXPathPopFrame:
2830 * @ctxt: an XPath parser context
2831 * @frame: the previous frame value
2832 *
2833 * Remove the callee evaluation frame
2834 */
2835static void
2836xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2837 if (ctxt == NULL)
2838 return;
2839 if (ctxt->valueNr < ctxt->valueFrame) {
2840 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2841 }
2842 ctxt->valueFrame = frame;
2843}
2844
2845/**
2846 * valuePop:
2847 * @ctxt: an XPath evaluation context
2848 *
2849 * Pops the top XPath object from the value stack
2850 *
2851 * Returns the XPath object just removed
2852 */
2853xmlXPathObjectPtr
2854valuePop(xmlXPathParserContextPtr ctxt)
2855{
2856 xmlXPathObjectPtr ret;
2857
2858 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2859 return (NULL);
2860
2861 if (ctxt->valueNr <= ctxt->valueFrame) {
2862 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2863 return (NULL);
2864 }
2865
2866 ctxt->valueNr--;
2867 if (ctxt->valueNr > 0)
2868 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2869 else
2870 ctxt->value = NULL;
2871 ret = ctxt->valueTab[ctxt->valueNr];
2872 ctxt->valueTab[ctxt->valueNr] = NULL;
2873 return (ret);
2874}
2875/**
2876 * valuePush:
2877 * @ctxt: an XPath evaluation context
2878 * @value: the XPath object
2879 *
2880 * Pushes a new XPath object on top of the value stack. If value is NULL,
2881 * a memory error is recorded in the parser context.
2882 *
2883 * Returns the number of items on the value stack, or -1 in case of error.
2884 */
2885int
2886valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2887{
2888 if (ctxt == NULL) return(-1);
2889 if (value == NULL) {
2890 /*
2891 * A NULL value typically indicates that a memory allocation failed,
2892 * so we set ctxt->error here to propagate the error.
2893 */
2894 ctxt->error = XPATH_MEMORY_ERROR;
2895 return(-1);
2896 }
2897 if (ctxt->valueNr >= ctxt->valueMax) {
2898 xmlXPathObjectPtr *tmp;
2899
2900 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2901 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2902 return (-1);
2903 }
2904 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2905 2 * ctxt->valueMax *
2906 sizeof(ctxt->valueTab[0]));
2907 if (tmp == NULL) {
2908 xmlXPathPErrMemory(ctxt, "pushing value\n");
2909 return (-1);
2910 }
2911 ctxt->valueMax *= 2;
2912 ctxt->valueTab = tmp;
2913 }
2914 ctxt->valueTab[ctxt->valueNr] = value;
2915 ctxt->value = value;
2916 return (ctxt->valueNr++);
2917}
2918
2919/**
2920 * xmlXPathPopBoolean:
2921 * @ctxt: an XPath parser context
2922 *
2923 * Pops a boolean from the stack, handling conversion if needed.
2924 * Check error with #xmlXPathCheckError.
2925 *
2926 * Returns the boolean
2927 */
2928int
2929xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2930 xmlXPathObjectPtr obj;
2931 int ret;
2932
2933 obj = valuePop(ctxt);
2934 if (obj == NULL) {
2935 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2936 return(0);
2937 }
2938 if (obj->type != XPATH_BOOLEAN)
2939 ret = xmlXPathCastToBoolean(obj);
2940 else
2941 ret = obj->boolval;
2942 xmlXPathReleaseObject(ctxt->context, obj);
2943 return(ret);
2944}
2945
2946/**
2947 * xmlXPathPopNumber:
2948 * @ctxt: an XPath parser context
2949 *
2950 * Pops a number from the stack, handling conversion if needed.
2951 * Check error with #xmlXPathCheckError.
2952 *
2953 * Returns the number
2954 */
2955double
2956xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2957 xmlXPathObjectPtr obj;
2958 double ret;
2959
2960 obj = valuePop(ctxt);
2961 if (obj == NULL) {
2962 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2963 return(0);
2964 }
2965 if (obj->type != XPATH_NUMBER)
2966 ret = xmlXPathCastToNumber(obj);
2967 else
2968 ret = obj->floatval;
2969 xmlXPathReleaseObject(ctxt->context, obj);
2970 return(ret);
2971}
2972
2973/**
2974 * xmlXPathPopString:
2975 * @ctxt: an XPath parser context
2976 *
2977 * Pops a string from the stack, handling conversion if needed.
2978 * Check error with #xmlXPathCheckError.
2979 *
2980 * Returns the string
2981 */
2982xmlChar *
2983xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2984 xmlXPathObjectPtr obj;
2985 xmlChar * ret;
2986
2987 obj = valuePop(ctxt);
2988 if (obj == NULL) {
2989 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2990 return(NULL);
2991 }
2992 ret = xmlXPathCastToString(obj); /* this does required strdup */
2993 /* TODO: needs refactoring somewhere else */
2994 if (obj->stringval == ret)
2995 obj->stringval = NULL;
2996 xmlXPathReleaseObject(ctxt->context, obj);
2997 return(ret);
2998}
2999
3000/**
3001 * xmlXPathPopNodeSet:
3002 * @ctxt: an XPath parser context
3003 *
3004 * Pops a node-set from the stack, handling conversion if needed.
3005 * Check error with #xmlXPathCheckError.
3006 *
3007 * Returns the node-set
3008 */
3009xmlNodeSetPtr
3010xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3011 xmlXPathObjectPtr obj;
3012 xmlNodeSetPtr ret;
3013
3014 if (ctxt == NULL) return(NULL);
3015 if (ctxt->value == NULL) {
3016 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3017 return(NULL);
3018 }
3019 if (!xmlXPathStackIsNodeSet(ctxt)) {
3020 xmlXPathSetTypeError(ctxt);
3021 return(NULL);
3022 }
3023 obj = valuePop(ctxt);
3024 ret = obj->nodesetval;
3025#if 0
3026 /* to fix memory leak of not clearing obj->user */
3027 if (obj->boolval && obj->user != NULL)
3028 xmlFreeNodeList((xmlNodePtr) obj->user);
3029#endif
3030 obj->nodesetval = NULL;
3031 xmlXPathReleaseObject(ctxt->context, obj);
3032 return(ret);
3033}
3034
3035/**
3036 * xmlXPathPopExternal:
3037 * @ctxt: an XPath parser context
3038 *
3039 * Pops an external object from the stack, handling conversion if needed.
3040 * Check error with #xmlXPathCheckError.
3041 *
3042 * Returns the object
3043 */
3044void *
3045xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3046 xmlXPathObjectPtr obj;
3047 void * ret;
3048
3049 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3050 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3051 return(NULL);
3052 }
3053 if (ctxt->value->type != XPATH_USERS) {
3054 xmlXPathSetTypeError(ctxt);
3055 return(NULL);
3056 }
3057 obj = valuePop(ctxt);
3058 ret = obj->user;
3059 obj->user = NULL;
3060 xmlXPathReleaseObject(ctxt->context, obj);
3061 return(ret);
3062}
3063
3064/*
3065 * Macros for accessing the content. Those should be used only by the parser,
3066 * and not exported.
3067 *
3068 * Dirty macros, i.e. one need to make assumption on the context to use them
3069 *
3070 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3071 * CUR returns the current xmlChar value, i.e. a 8 bit value
3072 * in ISO-Latin or UTF-8.
3073 * This should be used internally by the parser
3074 * only to compare to ASCII values otherwise it would break when
3075 * running with UTF-8 encoding.
3076 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3077 * to compare on ASCII based substring.
3078 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3079 * strings within the parser.
3080 * CURRENT Returns the current char value, with the full decoding of
3081 * UTF-8 if we are using this mode. It returns an int.
3082 * NEXT Skip to the next character, this does the proper decoding
3083 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3084 * It returns the pointer to the current xmlChar.
3085 */
3086
3087#define CUR (*ctxt->cur)
3088#define SKIP(val) ctxt->cur += (val)
3089#define NXT(val) ctxt->cur[(val)]
3090#define CUR_PTR ctxt->cur
3091#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3092
3093#define COPY_BUF(l,b,i,v) \
3094 if (l == 1) b[i++] = (xmlChar) v; \
3095 else i += xmlCopyChar(l,&b[i],v)
3096
3097#define NEXTL(l) ctxt->cur += l
3098
3099#define SKIP_BLANKS \
3100 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3101
3102#define CURRENT (*ctxt->cur)
3103#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3104
3105
3106#ifndef DBL_DIG
3107#define DBL_DIG 16
3108#endif
3109#ifndef DBL_EPSILON
3110#define DBL_EPSILON 1E-9
3111#endif
3112
3113#define UPPER_DOUBLE 1E9
3114#define LOWER_DOUBLE 1E-5
3115#define LOWER_DOUBLE_EXP 5
3116
3117#define INTEGER_DIGITS DBL_DIG
3118#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3119#define EXPONENT_DIGITS (3 + 2)
3120
3121/**
3122 * xmlXPathFormatNumber:
3123 * @number: number to format
3124 * @buffer: output buffer
3125 * @buffersize: size of output buffer
3126 *
3127 * Convert the number into a string representation.
3128 */
3129static void
3130xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3131{
3132 switch (xmlXPathIsInf(number)) {
3133 case 1:
3134 if (buffersize > (int)sizeof("Infinity"))
3135 snprintf(buffer, buffersize, "Infinity");
3136 break;
3137 case -1:
3138 if (buffersize > (int)sizeof("-Infinity"))
3139 snprintf(buffer, buffersize, "-Infinity");
3140 break;
3141 default:
3142 if (xmlXPathIsNaN(number)) {
3143 if (buffersize > (int)sizeof("NaN"))
3144 snprintf(buffer, buffersize, "NaN");
3145 } else if (number == 0) {
3146 /* Omit sign for negative zero. */
3147 snprintf(buffer, buffersize, "0");
3148 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3149 (number == (int) number)) {
3150 char work[30];
3151 char *ptr, *cur;
3152 int value = (int) number;
3153
3154 ptr = &buffer[0];
3155 if (value == 0) {
3156 *ptr++ = '0';
3157 } else {
3158 snprintf(work, 29, "%d", value);
3159 cur = &work[0];
3160 while ((*cur) && (ptr - buffer < buffersize)) {
3161 *ptr++ = *cur++;
3162 }
3163 }
3164 if (ptr - buffer < buffersize) {
3165 *ptr = 0;
3166 } else if (buffersize > 0) {
3167 ptr--;
3168 *ptr = 0;
3169 }
3170 } else {
3171 /*
3172 For the dimension of work,
3173 DBL_DIG is number of significant digits
3174 EXPONENT is only needed for "scientific notation"
3175 3 is sign, decimal point, and terminating zero
3176 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3177 Note that this dimension is slightly (a few characters)
3178 larger than actually necessary.
3179 */
3180 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3181 int integer_place, fraction_place;
3182 char *ptr;
3183 char *after_fraction;
3184 double absolute_value;
3185 int size;
3186
3187 absolute_value = fabs(number);
3188
3189 /*
3190 * First choose format - scientific or regular floating point.
3191 * In either case, result is in work, and after_fraction points
3192 * just past the fractional part.
3193 */
3194 if ( ((absolute_value > UPPER_DOUBLE) ||
3195 (absolute_value < LOWER_DOUBLE)) &&
3196 (absolute_value != 0.0) ) {
3197 /* Use scientific notation */
3198 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3199 fraction_place = DBL_DIG - 1;
3200 size = snprintf(work, sizeof(work),"%*.*e",
3201 integer_place, fraction_place, number);
3202 while ((size > 0) && (work[size] != 'e')) size--;
3203
3204 }
3205 else {
3206 /* Use regular notation */
3207 if (absolute_value > 0.0) {
3208 integer_place = (int)log10(absolute_value);
3209 if (integer_place > 0)
3210 fraction_place = DBL_DIG - integer_place - 1;
3211 else
3212 fraction_place = DBL_DIG - integer_place;
3213 } else {
3214 fraction_place = 1;
3215 }
3216 size = snprintf(work, sizeof(work), "%0.*f",
3217 fraction_place, number);
3218 }
3219
3220 /* Remove leading spaces sometimes inserted by snprintf */
3221 while (work[0] == ' ') {
3222 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3223 size--;
3224 }
3225
3226 /* Remove fractional trailing zeroes */
3227 after_fraction = work + size;
3228 ptr = after_fraction;
3229 while (*(--ptr) == '0')
3230 ;
3231 if (*ptr != '.')
3232 ptr++;
3233 while ((*ptr++ = *after_fraction++) != 0);
3234
3235 /* Finally copy result back to caller */
3236 size = strlen(work) + 1;
3237 if (size > buffersize) {
3238 work[buffersize - 1] = 0;
3239 size = buffersize;
3240 }
3241 memmove(buffer, work, size);
3242 }
3243 break;
3244 }
3245}
3246
3247
3248/************************************************************************
3249 * *
3250 * Routines to handle NodeSets *
3251 * *
3252 ************************************************************************/
3253
3254/**
3255 * xmlXPathOrderDocElems:
3256 * @doc: an input document
3257 *
3258 * Call this routine to speed up XPath computation on static documents.
3259 * This stamps all the element nodes with the document order
3260 * Like for line information, the order is kept in the element->content
3261 * field, the value stored is actually - the node number (starting at -1)
3262 * to be able to differentiate from line numbers.
3263 *
3264 * Returns the number of elements found in the document or -1 in case
3265 * of error.
3266 */
3267long
3268xmlXPathOrderDocElems(xmlDocPtr doc) {
3269 ptrdiff_t count = 0;
3270 xmlNodePtr cur;
3271
3272 if (doc == NULL)
3273 return(-1);
3274 cur = doc->children;
3275 while (cur != NULL) {
3276 if (cur->type == XML_ELEMENT_NODE) {
3277 cur->content = (void *) (-(++count));
3278 if (cur->children != NULL) {
3279 cur = cur->children;
3280 continue;
3281 }
3282 }
3283 if (cur->next != NULL) {
3284 cur = cur->next;
3285 continue;
3286 }
3287 do {
3288 cur = cur->parent;
3289 if (cur == NULL)
3290 break;
3291 if (cur == (xmlNodePtr) doc) {
3292 cur = NULL;
3293 break;
3294 }
3295 if (cur->next != NULL) {
3296 cur = cur->next;
3297 break;
3298 }
3299 } while (cur != NULL);
3300 }
3301 return((long) count);
3302}
3303
3304/**
3305 * xmlXPathCmpNodes:
3306 * @node1: the first node
3307 * @node2: the second node
3308 *
3309 * Compare two nodes w.r.t document order
3310 *
3311 * Returns -2 in case of error 1 if first point < second point, 0 if
3312 * it's the same node, -1 otherwise
3313 */
3314int
3315xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3316 int depth1, depth2;
3317 int attr1 = 0, attr2 = 0;
3318 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3319 xmlNodePtr cur, root;
3320
3321 if ((node1 == NULL) || (node2 == NULL))
3322 return(-2);
3323 /*
3324 * a couple of optimizations which will avoid computations in most cases
3325 */
3326 if (node1 == node2) /* trivial case */
3327 return(0);
3328 if (node1->type == XML_ATTRIBUTE_NODE) {
3329 attr1 = 1;
3330 attrNode1 = node1;
3331 node1 = node1->parent;
3332 }
3333 if (node2->type == XML_ATTRIBUTE_NODE) {
3334 attr2 = 1;
3335 attrNode2 = node2;
3336 node2 = node2->parent;
3337 }
3338 if (node1 == node2) {
3339 if (attr1 == attr2) {
3340 /* not required, but we keep attributes in order */
3341 if (attr1 != 0) {
3342 cur = attrNode2->prev;
3343 while (cur != NULL) {
3344 if (cur == attrNode1)
3345 return (1);
3346 cur = cur->prev;
3347 }
3348 return (-1);
3349 }
3350 return(0);
3351 }
3352 if (attr2 == 1)
3353 return(1);
3354 return(-1);
3355 }
3356 if ((node1->type == XML_NAMESPACE_DECL) ||
3357 (node2->type == XML_NAMESPACE_DECL))
3358 return(1);
3359 if (node1 == node2->prev)
3360 return(1);
3361 if (node1 == node2->next)
3362 return(-1);
3363
3364 /*
3365 * Speedup using document order if available.
3366 */
3367 if ((node1->type == XML_ELEMENT_NODE) &&
3368 (node2->type == XML_ELEMENT_NODE) &&
3369 (0 > (ptrdiff_t) node1->content) &&
3370 (0 > (ptrdiff_t) node2->content) &&
3371 (node1->doc == node2->doc)) {
3372 ptrdiff_t l1, l2;
3373
3374 l1 = -((ptrdiff_t) node1->content);
3375 l2 = -((ptrdiff_t) node2->content);
3376 if (l1 < l2)
3377 return(1);
3378 if (l1 > l2)
3379 return(-1);
3380 }
3381
3382 /*
3383 * compute depth to root
3384 */
3385 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3386 if (cur->parent == node1)
3387 return(1);
3388 depth2++;
3389 }
3390 root = cur;
3391 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3392 if (cur->parent == node2)
3393 return(-1);
3394 depth1++;
3395 }
3396 /*
3397 * Distinct document (or distinct entities :-( ) case.
3398 */
3399 if (root != cur) {
3400 return(-2);
3401 }
3402 /*
3403 * get the nearest common ancestor.
3404 */
3405 while (depth1 > depth2) {
3406 depth1--;
3407 node1 = node1->parent;
3408 }
3409 while (depth2 > depth1) {
3410 depth2--;
3411 node2 = node2->parent;
3412 }
3413 while (node1->parent != node2->parent) {
3414 node1 = node1->parent;
3415 node2 = node2->parent;
3416 /* should not happen but just in case ... */
3417 if ((node1 == NULL) || (node2 == NULL))
3418 return(-2);
3419 }
3420 /*
3421 * Find who's first.
3422 */
3423 if (node1 == node2->prev)
3424 return(1);
3425 if (node1 == node2->next)
3426 return(-1);
3427 /*
3428 * Speedup using document order if available.
3429 */
3430 if ((node1->type == XML_ELEMENT_NODE) &&
3431 (node2->type == XML_ELEMENT_NODE) &&
3432 (0 > (ptrdiff_t) node1->content) &&
3433 (0 > (ptrdiff_t) node2->content) &&
3434 (node1->doc == node2->doc)) {
3435 ptrdiff_t l1, l2;
3436
3437 l1 = -((ptrdiff_t) node1->content);
3438 l2 = -((ptrdiff_t) node2->content);
3439 if (l1 < l2)
3440 return(1);
3441 if (l1 > l2)
3442 return(-1);
3443 }
3444
3445 for (cur = node1->next;cur != NULL;cur = cur->next)
3446 if (cur == node2)
3447 return(1);
3448 return(-1); /* assume there is no sibling list corruption */
3449}
3450
3451/**
3452 * xmlXPathNodeSetSort:
3453 * @set: the node set
3454 *
3455 * Sort the node set in document order
3456 */
3457void
3458xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3459#ifndef WITH_TIM_SORT
3460 int i, j, incr, len;
3461 xmlNodePtr tmp;
3462#endif
3463
3464 if (set == NULL)
3465 return;
3466
3467#ifndef WITH_TIM_SORT
3468 /*
3469 * Use the old Shell's sort implementation to sort the node-set
3470 * Timsort ought to be quite faster
3471 */
3472 len = set->nodeNr;
3473 for (incr = len / 2; incr > 0; incr /= 2) {
3474 for (i = incr; i < len; i++) {
3475 j = i - incr;
3476 while (j >= 0) {
3477#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3478 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3479 set->nodeTab[j + incr]) == -1)
3480#else
3481 if (xmlXPathCmpNodes(set->nodeTab[j],
3482 set->nodeTab[j + incr]) == -1)
3483#endif
3484 {
3485 tmp = set->nodeTab[j];
3486 set->nodeTab[j] = set->nodeTab[j + incr];
3487 set->nodeTab[j + incr] = tmp;
3488 j -= incr;
3489 } else
3490 break;
3491 }
3492 }
3493 }
3494#else /* WITH_TIM_SORT */
3495 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3496#endif /* WITH_TIM_SORT */
3497}
3498
3499#define XML_NODESET_DEFAULT 10
3500/**
3501 * xmlXPathNodeSetDupNs:
3502 * @node: the parent node of the namespace XPath node
3503 * @ns: the libxml namespace declaration node.
3504 *
3505 * Namespace node in libxml don't match the XPath semantic. In a node set
3506 * the namespace nodes are duplicated and the next pointer is set to the
3507 * parent node in the XPath semantic.
3508 *
3509 * Returns the newly created object.
3510 */
3511static xmlNodePtr
3512xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3513 xmlNsPtr cur;
3514
3515 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3516 return(NULL);
3517 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3518 return((xmlNodePtr) ns);
3519
3520 /*
3521 * Allocate a new Namespace and fill the fields.
3522 */
3523 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3524 if (cur == NULL) {
3525 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3526 return(NULL);
3527 }
3528 memset(cur, 0, sizeof(xmlNs));
3529 cur->type = XML_NAMESPACE_DECL;
3530 if (ns->href != NULL)
3531 cur->href = xmlStrdup(ns->href);
3532 if (ns->prefix != NULL)
3533 cur->prefix = xmlStrdup(ns->prefix);
3534 cur->next = (xmlNsPtr) node;
3535 return((xmlNodePtr) cur);
3536}
3537
3538/**
3539 * xmlXPathNodeSetFreeNs:
3540 * @ns: the XPath namespace node found in a nodeset.
3541 *
3542 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3543 * the namespace nodes are duplicated and the next pointer is set to the
3544 * parent node in the XPath semantic. Check if such a node needs to be freed
3545 */
3546void
3547xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3548 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3549 return;
3550
3551 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3552 if (ns->href != NULL)
3553 xmlFree((xmlChar *)ns->href);
3554 if (ns->prefix != NULL)
3555 xmlFree((xmlChar *)ns->prefix);
3556 xmlFree(ns);
3557 }
3558}
3559
3560/**
3561 * xmlXPathNodeSetCreate:
3562 * @val: an initial xmlNodePtr, or NULL
3563 *
3564 * Create a new xmlNodeSetPtr of type double and of value @val
3565 *
3566 * Returns the newly created object.
3567 */
3568xmlNodeSetPtr
3569xmlXPathNodeSetCreate(xmlNodePtr val) {
3570 xmlNodeSetPtr ret;
3571
3572 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3573 if (ret == NULL) {
3574 xmlXPathErrMemory(NULL, "creating nodeset\n");
3575 return(NULL);
3576 }
3577 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3578 if (val != NULL) {
3579 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3580 sizeof(xmlNodePtr));
3581 if (ret->nodeTab == NULL) {
3582 xmlXPathErrMemory(NULL, "creating nodeset\n");
3583 xmlFree(ret);
3584 return(NULL);
3585 }
3586 memset(ret->nodeTab, 0 ,
3587 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3588 ret->nodeMax = XML_NODESET_DEFAULT;
3589 if (val->type == XML_NAMESPACE_DECL) {
3590 xmlNsPtr ns = (xmlNsPtr) val;
3591
3592 /* TODO: Check memory error. */
3593 ret->nodeTab[ret->nodeNr++] =
3594 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3595 } else
3596 ret->nodeTab[ret->nodeNr++] = val;
3597 }
3598 return(ret);
3599}
3600
3601/**
3602 * xmlXPathNodeSetContains:
3603 * @cur: the node-set
3604 * @val: the node
3605 *
3606 * checks whether @cur contains @val
3607 *
3608 * Returns true (1) if @cur contains @val, false (0) otherwise
3609 */
3610int
3611xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3612 int i;
3613
3614 if ((cur == NULL) || (val == NULL)) return(0);
3615 if (val->type == XML_NAMESPACE_DECL) {
3616 for (i = 0; i < cur->nodeNr; i++) {
3617 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3618 xmlNsPtr ns1, ns2;
3619
3620 ns1 = (xmlNsPtr) val;
3621 ns2 = (xmlNsPtr) cur->nodeTab[i];
3622 if (ns1 == ns2)
3623 return(1);
3624 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3625 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3626 return(1);
3627 }
3628 }
3629 } else {
3630 for (i = 0; i < cur->nodeNr; i++) {
3631 if (cur->nodeTab[i] == val)
3632 return(1);
3633 }
3634 }
3635 return(0);
3636}
3637
3638/**
3639 * xmlXPathNodeSetAddNs:
3640 * @cur: the initial node set
3641 * @node: the hosting node
3642 * @ns: a the namespace node
3643 *
3644 * add a new namespace node to an existing NodeSet
3645 *
3646 * Returns 0 in case of success and -1 in case of error
3647 */
3648int
3649xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3650 int i;
3651
3652
3653 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3654 (ns->type != XML_NAMESPACE_DECL) ||
3655 (node->type != XML_ELEMENT_NODE))
3656 return(-1);
3657
3658 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3659 /*
3660 * prevent duplicates
3661 */
3662 for (i = 0;i < cur->nodeNr;i++) {
3663 if ((cur->nodeTab[i] != NULL) &&
3664 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3665 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3666 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3667 return(0);
3668 }
3669
3670 /*
3671 * grow the nodeTab if needed
3672 */
3673 if (cur->nodeMax == 0) {
3674 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3675 sizeof(xmlNodePtr));
3676 if (cur->nodeTab == NULL) {
3677 xmlXPathErrMemory(NULL, "growing nodeset\n");
3678 return(-1);
3679 }
3680 memset(cur->nodeTab, 0 ,
3681 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3682 cur->nodeMax = XML_NODESET_DEFAULT;
3683 } else if (cur->nodeNr == cur->nodeMax) {
3684 xmlNodePtr *temp;
3685
3686 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3687 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3688 return(-1);
3689 }
3690 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3691 sizeof(xmlNodePtr));
3692 if (temp == NULL) {
3693 xmlXPathErrMemory(NULL, "growing nodeset\n");
3694 return(-1);
3695 }
3696 cur->nodeMax *= 2;
3697 cur->nodeTab = temp;
3698 }
3699 /* TODO: Check memory error. */
3700 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3701 return(0);
3702}
3703
3704/**
3705 * xmlXPathNodeSetAdd:
3706 * @cur: the initial node set
3707 * @val: a new xmlNodePtr
3708 *
3709 * add a new xmlNodePtr to an existing NodeSet
3710 *
3711 * Returns 0 in case of success, and -1 in case of error
3712 */
3713int
3714xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3715 int i;
3716
3717 if ((cur == NULL) || (val == NULL)) return(-1);
3718
3719 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3720 /*
3721 * prevent duplicates
3722 */
3723 for (i = 0;i < cur->nodeNr;i++)
3724 if (cur->nodeTab[i] == val) return(0);
3725
3726 /*
3727 * grow the nodeTab if needed
3728 */
3729 if (cur->nodeMax == 0) {
3730 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3731 sizeof(xmlNodePtr));
3732 if (cur->nodeTab == NULL) {
3733 xmlXPathErrMemory(NULL, "growing nodeset\n");
3734 return(-1);
3735 }
3736 memset(cur->nodeTab, 0 ,
3737 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3738 cur->nodeMax = XML_NODESET_DEFAULT;
3739 } else if (cur->nodeNr == cur->nodeMax) {
3740 xmlNodePtr *temp;
3741
3742 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3743 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3744 return(-1);
3745 }
3746 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3747 sizeof(xmlNodePtr));
3748 if (temp == NULL) {
3749 xmlXPathErrMemory(NULL, "growing nodeset\n");
3750 return(-1);
3751 }
3752 cur->nodeMax *= 2;
3753 cur->nodeTab = temp;
3754 }
3755 if (val->type == XML_NAMESPACE_DECL) {
3756 xmlNsPtr ns = (xmlNsPtr) val;
3757
3758 /* TODO: Check memory error. */
3759 cur->nodeTab[cur->nodeNr++] =
3760 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3761 } else
3762 cur->nodeTab[cur->nodeNr++] = val;
3763 return(0);
3764}
3765
3766/**
3767 * xmlXPathNodeSetAddUnique:
3768 * @cur: the initial node set
3769 * @val: a new xmlNodePtr
3770 *
3771 * add a new xmlNodePtr to an existing NodeSet, optimized version
3772 * when we are sure the node is not already in the set.
3773 *
3774 * Returns 0 in case of success and -1 in case of failure
3775 */
3776int
3777xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3778 if ((cur == NULL) || (val == NULL)) return(-1);
3779
3780 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3781 /*
3782 * grow the nodeTab if needed
3783 */
3784 if (cur->nodeMax == 0) {
3785 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3786 sizeof(xmlNodePtr));
3787 if (cur->nodeTab == NULL) {
3788 xmlXPathErrMemory(NULL, "growing nodeset\n");
3789 return(-1);
3790 }
3791 memset(cur->nodeTab, 0 ,
3792 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3793 cur->nodeMax = XML_NODESET_DEFAULT;
3794 } else if (cur->nodeNr == cur->nodeMax) {
3795 xmlNodePtr *temp;
3796
3797 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3798 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3799 return(-1);
3800 }
3801 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3802 sizeof(xmlNodePtr));
3803 if (temp == NULL) {
3804 xmlXPathErrMemory(NULL, "growing nodeset\n");
3805 return(-1);
3806 }
3807 cur->nodeTab = temp;
3808 cur->nodeMax *= 2;
3809 }
3810 if (val->type == XML_NAMESPACE_DECL) {
3811 xmlNsPtr ns = (xmlNsPtr) val;
3812
3813 /* TODO: Check memory error. */
3814 cur->nodeTab[cur->nodeNr++] =
3815 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3816 } else
3817 cur->nodeTab[cur->nodeNr++] = val;
3818 return(0);
3819}
3820
3821/**
3822 * xmlXPathNodeSetMerge:
3823 * @val1: the first NodeSet or NULL
3824 * @val2: the second NodeSet
3825 *
3826 * Merges two nodesets, all nodes from @val2 are added to @val1
3827 * if @val1 is NULL, a new set is created and copied from @val2
3828 *
3829 * Returns @val1 once extended or NULL in case of error.
3830 */
3831xmlNodeSetPtr
3832xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3833 int i, j, initNr, skip;
3834 xmlNodePtr n1, n2;
3835
3836 if (val2 == NULL) return(val1);
3837 if (val1 == NULL) {
3838 val1 = xmlXPathNodeSetCreate(NULL);
3839 if (val1 == NULL)
3840 return (NULL);
3841#if 0
3842 /*
3843 * TODO: The optimization won't work in every case, since
3844 * those nasty namespace nodes need to be added with
3845 * xmlXPathNodeSetDupNs() to the set; thus a pure
3846 * memcpy is not possible.
3847 * If there was a flag on the nodesetval, indicating that
3848 * some temporary nodes are in, that would be helpful.
3849 */
3850 /*
3851 * Optimization: Create an equally sized node-set
3852 * and memcpy the content.
3853 */
3854 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3855 if (val1 == NULL)
3856 return(NULL);
3857 if (val2->nodeNr != 0) {
3858 if (val2->nodeNr == 1)
3859 *(val1->nodeTab) = *(val2->nodeTab);
3860 else {
3861 memcpy(val1->nodeTab, val2->nodeTab,
3862 val2->nodeNr * sizeof(xmlNodePtr));
3863 }
3864 val1->nodeNr = val2->nodeNr;
3865 }
3866 return(val1);
3867#endif
3868 }
3869
3870 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3871 initNr = val1->nodeNr;
3872
3873 for (i = 0;i < val2->nodeNr;i++) {
3874 n2 = val2->nodeTab[i];
3875 /*
3876 * check against duplicates
3877 */
3878 skip = 0;
3879 for (j = 0; j < initNr; j++) {
3880 n1 = val1->nodeTab[j];
3881 if (n1 == n2) {
3882 skip = 1;
3883 break;
3884 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3885 (n2->type == XML_NAMESPACE_DECL)) {
3886 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3887 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3888 ((xmlNsPtr) n2)->prefix)))
3889 {
3890 skip = 1;
3891 break;
3892 }
3893 }
3894 }
3895 if (skip)
3896 continue;
3897
3898 /*
3899 * grow the nodeTab if needed
3900 */
3901 if (val1->nodeMax == 0) {
3902 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3903 sizeof(xmlNodePtr));
3904 if (val1->nodeTab == NULL) {
3905 xmlXPathErrMemory(NULL, "merging nodeset\n");
3906 return(NULL);
3907 }
3908 memset(val1->nodeTab, 0 ,
3909 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3910 val1->nodeMax = XML_NODESET_DEFAULT;
3911 } else if (val1->nodeNr == val1->nodeMax) {
3912 xmlNodePtr *temp;
3913
3914 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3915 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3916 return(NULL);
3917 }
3918 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3919 sizeof(xmlNodePtr));
3920 if (temp == NULL) {
3921 xmlXPathErrMemory(NULL, "merging nodeset\n");
3922 return(NULL);
3923 }
3924 val1->nodeTab = temp;
3925 val1->nodeMax *= 2;
3926 }
3927 if (n2->type == XML_NAMESPACE_DECL) {
3928 xmlNsPtr ns = (xmlNsPtr) n2;
3929
3930 /* TODO: Check memory error. */
3931 val1->nodeTab[val1->nodeNr++] =
3932 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3933 } else
3934 val1->nodeTab[val1->nodeNr++] = n2;
3935 }
3936
3937 return(val1);
3938}
3939
3940
3941/**
3942 * xmlXPathNodeSetMergeAndClear:
3943 * @set1: the first NodeSet or NULL
3944 * @set2: the second NodeSet
3945 *
3946 * Merges two nodesets, all nodes from @set2 are added to @set1.
3947 * Checks for duplicate nodes. Clears set2.
3948 *
3949 * Returns @set1 once extended or NULL in case of error.
3950 */
3951static xmlNodeSetPtr
3952xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3953{
3954 {
3955 int i, j, initNbSet1;
3956 xmlNodePtr n1, n2;
3957
3958 initNbSet1 = set1->nodeNr;
3959 for (i = 0;i < set2->nodeNr;i++) {
3960 n2 = set2->nodeTab[i];
3961 /*
3962 * Skip duplicates.
3963 */
3964 for (j = 0; j < initNbSet1; j++) {
3965 n1 = set1->nodeTab[j];
3966 if (n1 == n2) {
3967 goto skip_node;
3968 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3969 (n2->type == XML_NAMESPACE_DECL))
3970 {
3971 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3972 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3973 ((xmlNsPtr) n2)->prefix)))
3974 {
3975 /*
3976 * Free the namespace node.
3977 */
3978 set2->nodeTab[i] = NULL;
3979 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3980 goto skip_node;
3981 }
3982 }
3983 }
3984 /*
3985 * grow the nodeTab if needed
3986 */
3987 if (set1->nodeMax == 0) {
3988 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3989 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3990 if (set1->nodeTab == NULL) {
3991 xmlXPathErrMemory(NULL, "merging nodeset\n");
3992 return(NULL);
3993 }
3994 memset(set1->nodeTab, 0,
3995 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3996 set1->nodeMax = XML_NODESET_DEFAULT;
3997 } else if (set1->nodeNr >= set1->nodeMax) {
3998 xmlNodePtr *temp;
3999
4000 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4001 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4002 return(NULL);
4003 }
4004 temp = (xmlNodePtr *) xmlRealloc(
4005 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4006 if (temp == NULL) {
4007 xmlXPathErrMemory(NULL, "merging nodeset\n");
4008 return(NULL);
4009 }
4010 set1->nodeTab = temp;
4011 set1->nodeMax *= 2;
4012 }
4013 set1->nodeTab[set1->nodeNr++] = n2;
4014skip_node:
4015 {}
4016 }
4017 }
4018 set2->nodeNr = 0;
4019 return(set1);
4020}
4021
4022/**
4023 * xmlXPathNodeSetMergeAndClearNoDupls:
4024 * @set1: the first NodeSet or NULL
4025 * @set2: the second NodeSet
4026 *
4027 * Merges two nodesets, all nodes from @set2 are added to @set1.
4028 * Doesn't check for duplicate nodes. Clears set2.
4029 *
4030 * Returns @set1 once extended or NULL in case of error.
4031 */
4032static xmlNodeSetPtr
4033xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4034{
4035 {
4036 int i;
4037 xmlNodePtr n2;
4038
4039 for (i = 0;i < set2->nodeNr;i++) {
4040 n2 = set2->nodeTab[i];
4041 if (set1->nodeMax == 0) {
4042 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4043 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4044 if (set1->nodeTab == NULL) {
4045 xmlXPathErrMemory(NULL, "merging nodeset\n");
4046 return(NULL);
4047 }
4048 memset(set1->nodeTab, 0,
4049 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4050 set1->nodeMax = XML_NODESET_DEFAULT;
4051 } else if (set1->nodeNr >= set1->nodeMax) {
4052 xmlNodePtr *temp;
4053
4054 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4055 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4056 return(NULL);
4057 }
4058 temp = (xmlNodePtr *) xmlRealloc(
4059 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4060 if (temp == NULL) {
4061 xmlXPathErrMemory(NULL, "merging nodeset\n");
4062 return(NULL);
4063 }
4064 set1->nodeTab = temp;
4065 set1->nodeMax *= 2;
4066 }
4067 set1->nodeTab[set1->nodeNr++] = n2;
4068 }
4069 }
4070 set2->nodeNr = 0;
4071 return(set1);
4072}
4073
4074/**
4075 * xmlXPathNodeSetDel:
4076 * @cur: the initial node set
4077 * @val: an xmlNodePtr
4078 *
4079 * Removes an xmlNodePtr from an existing NodeSet
4080 */
4081void
4082xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4083 int i;
4084
4085 if (cur == NULL) return;
4086 if (val == NULL) return;
4087
4088 /*
4089 * find node in nodeTab
4090 */
4091 for (i = 0;i < cur->nodeNr;i++)
4092 if (cur->nodeTab[i] == val) break;
4093
4094 if (i >= cur->nodeNr) { /* not found */
4095#ifdef DEBUG
4096 xmlGenericError(xmlGenericErrorContext,
4097 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4098 val->name);
4099#endif
4100 return;
4101 }
4102 if ((cur->nodeTab[i] != NULL) &&
4103 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4104 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4105 cur->nodeNr--;
4106 for (;i < cur->nodeNr;i++)
4107 cur->nodeTab[i] = cur->nodeTab[i + 1];
4108 cur->nodeTab[cur->nodeNr] = NULL;
4109}
4110
4111/**
4112 * xmlXPathNodeSetRemove:
4113 * @cur: the initial node set
4114 * @val: the index to remove
4115 *
4116 * Removes an entry from an existing NodeSet list.
4117 */
4118void
4119xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4120 if (cur == NULL) return;
4121 if (val >= cur->nodeNr) return;
4122 if ((cur->nodeTab[val] != NULL) &&
4123 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4124 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4125 cur->nodeNr--;
4126 for (;val < cur->nodeNr;val++)
4127 cur->nodeTab[val] = cur->nodeTab[val + 1];
4128 cur->nodeTab[cur->nodeNr] = NULL;
4129}
4130
4131/**
4132 * xmlXPathFreeNodeSet:
4133 * @obj: the xmlNodeSetPtr to free
4134 *
4135 * Free the NodeSet compound (not the actual nodes !).
4136 */
4137void
4138xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4139 if (obj == NULL) return;
4140 if (obj->nodeTab != NULL) {
4141 int i;
4142
4143 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4144 for (i = 0;i < obj->nodeNr;i++)
4145 if ((obj->nodeTab[i] != NULL) &&
4146 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4147 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4148 xmlFree(obj->nodeTab);
4149 }
4150 xmlFree(obj);
4151}
4152
4153/**
4154 * xmlXPathNodeSetClearFromPos:
4155 * @set: the node set to be cleared
4156 * @pos: the start position to clear from
4157 *
4158 * Clears the list from temporary XPath objects (e.g. namespace nodes
4159 * are feed) starting with the entry at @pos, but does *not* free the list
4160 * itself. Sets the length of the list to @pos.
4161 */
4162static void
4163xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4164{
4165 if ((set == NULL) || (pos >= set->nodeNr))
4166 return;
4167 else if ((hasNsNodes)) {
4168 int i;
4169 xmlNodePtr node;
4170
4171 for (i = pos; i < set->nodeNr; i++) {
4172 node = set->nodeTab[i];
4173 if ((node != NULL) &&
4174 (node->type == XML_NAMESPACE_DECL))
4175 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4176 }
4177 }
4178 set->nodeNr = pos;
4179}
4180
4181/**
4182 * xmlXPathNodeSetClear:
4183 * @set: the node set to clear
4184 *
4185 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4186 * are feed), but does *not* free the list itself. Sets the length of the
4187 * list to 0.
4188 */
4189static void
4190xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4191{
4192 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4193}
4194
4195/**
4196 * xmlXPathNodeSetKeepLast:
4197 * @set: the node set to be cleared
4198 *
4199 * Move the last node to the first position and clear temporary XPath objects
4200 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4201 * to 1.
4202 */
4203static void
4204xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4205{
4206 int i;
4207 xmlNodePtr node;
4208
4209 if ((set == NULL) || (set->nodeNr <= 1))
4210 return;
4211 for (i = 0; i < set->nodeNr - 1; i++) {
4212 node = set->nodeTab[i];
4213 if ((node != NULL) &&
4214 (node->type == XML_NAMESPACE_DECL))
4215 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4216 }
4217 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4218 set->nodeNr = 1;
4219}
4220
4221/**
4222 * xmlXPathFreeValueTree:
4223 * @obj: the xmlNodeSetPtr to free
4224 *
4225 * Free the NodeSet compound and the actual tree, this is different
4226 * from xmlXPathFreeNodeSet()
4227 */
4228static void
4229xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4230 int i;
4231
4232 if (obj == NULL) return;
4233
4234 if (obj->nodeTab != NULL) {
4235 for (i = 0;i < obj->nodeNr;i++) {
4236 if (obj->nodeTab[i] != NULL) {
4237 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4238 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4239 } else {
4240 xmlFreeNodeList(obj->nodeTab[i]);
4241 }
4242 }
4243 }
4244 xmlFree(obj->nodeTab);
4245 }
4246 xmlFree(obj);
4247}
4248
4249#if defined(DEBUG) || defined(DEBUG_STEP)
4250/**
4251 * xmlGenericErrorContextNodeSet:
4252 * @output: a FILE * for the output
4253 * @obj: the xmlNodeSetPtr to display
4254 *
4255 * Quick display of a NodeSet
4256 */
4257void
4258xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4259 int i;
4260
4261 if (output == NULL) output = xmlGenericErrorContext;
4262 if (obj == NULL) {
4263 fprintf(output, "NodeSet == NULL !\n");
4264 return;
4265 }
4266 if (obj->nodeNr == 0) {
4267 fprintf(output, "NodeSet is empty\n");
4268 return;
4269 }
4270 if (obj->nodeTab == NULL) {
4271 fprintf(output, " nodeTab == NULL !\n");
4272 return;
4273 }
4274 for (i = 0; i < obj->nodeNr; i++) {
4275 if (obj->nodeTab[i] == NULL) {
4276 fprintf(output, " NULL !\n");
4277 return;
4278 }
4279 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4280 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4281 fprintf(output, " /");
4282 else if (obj->nodeTab[i]->name == NULL)
4283 fprintf(output, " noname!");
4284 else fprintf(output, " %s", obj->nodeTab[i]->name);
4285 }
4286 fprintf(output, "\n");
4287}
4288#endif
4289
4290/**
4291 * xmlXPathNewNodeSet:
4292 * @val: the NodePtr value
4293 *
4294 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4295 * it with the single Node @val
4296 *
4297 * Returns the newly created object.
4298 */
4299xmlXPathObjectPtr
4300xmlXPathNewNodeSet(xmlNodePtr val) {
4301 xmlXPathObjectPtr ret;
4302
4303 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304 if (ret == NULL) {
4305 xmlXPathErrMemory(NULL, "creating nodeset\n");
4306 return(NULL);
4307 }
4308 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4309 ret->type = XPATH_NODESET;
4310 ret->boolval = 0;
4311 /* TODO: Check memory error. */
4312 ret->nodesetval = xmlXPathNodeSetCreate(val);
4313 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4314#ifdef XP_DEBUG_OBJ_USAGE
4315 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4316#endif
4317 return(ret);
4318}
4319
4320/**
4321 * xmlXPathNewValueTree:
4322 * @val: the NodePtr value
4323 *
4324 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4325 * it with the tree root @val
4326 *
4327 * Returns the newly created object.
4328 */
4329xmlXPathObjectPtr
4330xmlXPathNewValueTree(xmlNodePtr val) {
4331 xmlXPathObjectPtr ret;
4332
4333 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4334 if (ret == NULL) {
4335 xmlXPathErrMemory(NULL, "creating result value tree\n");
4336 return(NULL);
4337 }
4338 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4339 ret->type = XPATH_XSLT_TREE;
4340 ret->boolval = 1;
4341 ret->user = (void *) val;
4342 ret->nodesetval = xmlXPathNodeSetCreate(val);
4343#ifdef XP_DEBUG_OBJ_USAGE
4344 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4345#endif
4346 return(ret);
4347}
4348
4349/**
4350 * xmlXPathNewNodeSetList:
4351 * @val: an existing NodeSet
4352 *
4353 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4354 * it with the Nodeset @val
4355 *
4356 * Returns the newly created object.
4357 */
4358xmlXPathObjectPtr
4359xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4360{
4361 xmlXPathObjectPtr ret;
4362 int i;
4363
4364 if (val == NULL)
4365 ret = NULL;
4366 else if (val->nodeTab == NULL)
4367 ret = xmlXPathNewNodeSet(NULL);
4368 else {
4369 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4370 if (ret) {
4371 for (i = 1; i < val->nodeNr; ++i) {
4372 /* TODO: Propagate memory error. */
4373 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4374 < 0) break;
4375 }
4376 }
4377 }
4378
4379 return (ret);
4380}
4381
4382/**
4383 * xmlXPathWrapNodeSet:
4384 * @val: the NodePtr value
4385 *
4386 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4387 *
4388 * Returns the newly created object.
4389 */
4390xmlXPathObjectPtr
4391xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4392 xmlXPathObjectPtr ret;
4393
4394 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4395 if (ret == NULL) {
4396 xmlXPathErrMemory(NULL, "creating node set object\n");
4397 return(NULL);
4398 }
4399 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4400 ret->type = XPATH_NODESET;
4401 ret->nodesetval = val;
4402#ifdef XP_DEBUG_OBJ_USAGE
4403 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4404#endif
4405 return(ret);
4406}
4407
4408/**
4409 * xmlXPathFreeNodeSetList:
4410 * @obj: an existing NodeSetList object
4411 *
4412 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4413 * the list contrary to xmlXPathFreeObject().
4414 */
4415void
4416xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4417 if (obj == NULL) return;
4418#ifdef XP_DEBUG_OBJ_USAGE
4419 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4420#endif
4421 xmlFree(obj);
4422}
4423
4424/**
4425 * xmlXPathDifference:
4426 * @nodes1: a node-set
4427 * @nodes2: a node-set
4428 *
4429 * Implements the EXSLT - Sets difference() function:
4430 * node-set set:difference (node-set, node-set)
4431 *
4432 * Returns the difference between the two node sets, or nodes1 if
4433 * nodes2 is empty
4434 */
4435xmlNodeSetPtr
4436xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4437 xmlNodeSetPtr ret;
4438 int i, l1;
4439 xmlNodePtr cur;
4440
4441 if (xmlXPathNodeSetIsEmpty(nodes2))
4442 return(nodes1);
4443
4444 /* TODO: Check memory error. */
4445 ret = xmlXPathNodeSetCreate(NULL);
4446 if (xmlXPathNodeSetIsEmpty(nodes1))
4447 return(ret);
4448
4449 l1 = xmlXPathNodeSetGetLength(nodes1);
4450
4451 for (i = 0; i < l1; i++) {
4452 cur = xmlXPathNodeSetItem(nodes1, i);
4453 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4454 /* TODO: Propagate memory error. */
4455 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4456 break;
4457 }
4458 }
4459 return(ret);
4460}
4461
4462/**
4463 * xmlXPathIntersection:
4464 * @nodes1: a node-set
4465 * @nodes2: a node-set
4466 *
4467 * Implements the EXSLT - Sets intersection() function:
4468 * node-set set:intersection (node-set, node-set)
4469 *
4470 * Returns a node set comprising the nodes that are within both the
4471 * node sets passed as arguments
4472 */
4473xmlNodeSetPtr
4474xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4475 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4476 int i, l1;
4477 xmlNodePtr cur;
4478
4479 if (ret == NULL)
4480 return(ret);
4481 if (xmlXPathNodeSetIsEmpty(nodes1))
4482 return(ret);
4483 if (xmlXPathNodeSetIsEmpty(nodes2))
4484 return(ret);
4485
4486 l1 = xmlXPathNodeSetGetLength(nodes1);
4487
4488 for (i = 0; i < l1; i++) {
4489 cur = xmlXPathNodeSetItem(nodes1, i);
4490 if (xmlXPathNodeSetContains(nodes2, cur)) {
4491 /* TODO: Propagate memory error. */
4492 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4493 break;
4494 }
4495 }
4496 return(ret);
4497}
4498
4499/**
4500 * xmlXPathDistinctSorted:
4501 * @nodes: a node-set, sorted by document order
4502 *
4503 * Implements the EXSLT - Sets distinct() function:
4504 * node-set set:distinct (node-set)
4505 *
4506 * Returns a subset of the nodes contained in @nodes, or @nodes if
4507 * it is empty
4508 */
4509xmlNodeSetPtr
4510xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4511 xmlNodeSetPtr ret;
4512 xmlHashTablePtr hash;
4513 int i, l;
4514 xmlChar * strval;
4515 xmlNodePtr cur;
4516
4517 if (xmlXPathNodeSetIsEmpty(nodes))
4518 return(nodes);
4519
4520 ret = xmlXPathNodeSetCreate(NULL);
4521 if (ret == NULL)
4522 return(ret);
4523 l = xmlXPathNodeSetGetLength(nodes);
4524 hash = xmlHashCreate (l);
4525 for (i = 0; i < l; i++) {
4526 cur = xmlXPathNodeSetItem(nodes, i);
4527 strval = xmlXPathCastNodeToString(cur);
4528 if (xmlHashLookup(hash, strval) == NULL) {
4529 xmlHashAddEntry(hash, strval, strval);
4530 /* TODO: Propagate memory error. */
4531 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4532 break;
4533 } else {
4534 xmlFree(strval);
4535 }
4536 }
4537 xmlHashFree(hash, xmlHashDefaultDeallocator);
4538 return(ret);
4539}
4540
4541/**
4542 * xmlXPathDistinct:
4543 * @nodes: a node-set
4544 *
4545 * Implements the EXSLT - Sets distinct() function:
4546 * node-set set:distinct (node-set)
4547 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4548 * is called with the sorted node-set
4549 *
4550 * Returns a subset of the nodes contained in @nodes, or @nodes if
4551 * it is empty
4552 */
4553xmlNodeSetPtr
4554xmlXPathDistinct (xmlNodeSetPtr nodes) {
4555 if (xmlXPathNodeSetIsEmpty(nodes))
4556 return(nodes);
4557
4558 xmlXPathNodeSetSort(nodes);
4559 return(xmlXPathDistinctSorted(nodes));
4560}
4561
4562/**
4563 * xmlXPathHasSameNodes:
4564 * @nodes1: a node-set
4565 * @nodes2: a node-set
4566 *
4567 * Implements the EXSLT - Sets has-same-nodes function:
4568 * boolean set:has-same-node(node-set, node-set)
4569 *
4570 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4571 * otherwise
4572 */
4573int
4574xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4575 int i, l;
4576 xmlNodePtr cur;
4577
4578 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4579 xmlXPathNodeSetIsEmpty(nodes2))
4580 return(0);
4581
4582 l = xmlXPathNodeSetGetLength(nodes1);
4583 for (i = 0; i < l; i++) {
4584 cur = xmlXPathNodeSetItem(nodes1, i);
4585 if (xmlXPathNodeSetContains(nodes2, cur))
4586 return(1);
4587 }
4588 return(0);
4589}
4590
4591/**
4592 * xmlXPathNodeLeadingSorted:
4593 * @nodes: a node-set, sorted by document order
4594 * @node: a node
4595 *
4596 * Implements the EXSLT - Sets leading() function:
4597 * node-set set:leading (node-set, node-set)
4598 *
4599 * Returns the nodes in @nodes that precede @node in document order,
4600 * @nodes if @node is NULL or an empty node-set if @nodes
4601 * doesn't contain @node
4602 */
4603xmlNodeSetPtr
4604xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4605 int i, l;
4606 xmlNodePtr cur;
4607 xmlNodeSetPtr ret;
4608
4609 if (node == NULL)
4610 return(nodes);
4611
4612 ret = xmlXPathNodeSetCreate(NULL);
4613 if (ret == NULL)
4614 return(ret);
4615 if (xmlXPathNodeSetIsEmpty(nodes) ||
4616 (!xmlXPathNodeSetContains(nodes, node)))
4617 return(ret);
4618
4619 l = xmlXPathNodeSetGetLength(nodes);
4620 for (i = 0; i < l; i++) {
4621 cur = xmlXPathNodeSetItem(nodes, i);
4622 if (cur == node)
4623 break;
4624 /* TODO: Propagate memory error. */
4625 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4626 break;
4627 }
4628 return(ret);
4629}
4630
4631/**
4632 * xmlXPathNodeLeading:
4633 * @nodes: a node-set
4634 * @node: a node
4635 *
4636 * Implements the EXSLT - Sets leading() function:
4637 * node-set set:leading (node-set, node-set)
4638 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4639 * is called.
4640 *
4641 * Returns the nodes in @nodes that precede @node in document order,
4642 * @nodes if @node is NULL or an empty node-set if @nodes
4643 * doesn't contain @node
4644 */
4645xmlNodeSetPtr
4646xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4647 xmlXPathNodeSetSort(nodes);
4648 return(xmlXPathNodeLeadingSorted(nodes, node));
4649}
4650
4651/**
4652 * xmlXPathLeadingSorted:
4653 * @nodes1: a node-set, sorted by document order
4654 * @nodes2: a node-set, sorted by document order
4655 *
4656 * Implements the EXSLT - Sets leading() function:
4657 * node-set set:leading (node-set, node-set)
4658 *
4659 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4660 * in document order, @nodes1 if @nodes2 is NULL or empty or
4661 * an empty node-set if @nodes1 doesn't contain @nodes2
4662 */
4663xmlNodeSetPtr
4664xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4665 if (xmlXPathNodeSetIsEmpty(nodes2))
4666 return(nodes1);
4667 return(xmlXPathNodeLeadingSorted(nodes1,
4668 xmlXPathNodeSetItem(nodes2, 1)));
4669}
4670
4671/**
4672 * xmlXPathLeading:
4673 * @nodes1: a node-set
4674 * @nodes2: a node-set
4675 *
4676 * Implements the EXSLT - Sets leading() function:
4677 * node-set set:leading (node-set, node-set)
4678 * @nodes1 and @nodes2 are sorted by document order, then
4679 * #exslSetsLeadingSorted is called.
4680 *
4681 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4682 * in document order, @nodes1 if @nodes2 is NULL or empty or
4683 * an empty node-set if @nodes1 doesn't contain @nodes2
4684 */
4685xmlNodeSetPtr
4686xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4687 if (xmlXPathNodeSetIsEmpty(nodes2))
4688 return(nodes1);
4689 if (xmlXPathNodeSetIsEmpty(nodes1))
4690 return(xmlXPathNodeSetCreate(NULL));
4691 xmlXPathNodeSetSort(nodes1);
4692 xmlXPathNodeSetSort(nodes2);
4693 return(xmlXPathNodeLeadingSorted(nodes1,
4694 xmlXPathNodeSetItem(nodes2, 1)));
4695}
4696
4697/**
4698 * xmlXPathNodeTrailingSorted:
4699 * @nodes: a node-set, sorted by document order
4700 * @node: a node
4701 *
4702 * Implements the EXSLT - Sets trailing() function:
4703 * node-set set:trailing (node-set, node-set)
4704 *
4705 * Returns the nodes in @nodes that follow @node in document order,
4706 * @nodes if @node is NULL or an empty node-set if @nodes
4707 * doesn't contain @node
4708 */
4709xmlNodeSetPtr
4710xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4711 int i, l;
4712 xmlNodePtr cur;
4713 xmlNodeSetPtr ret;
4714
4715 if (node == NULL)
4716 return(nodes);
4717
4718 ret = xmlXPathNodeSetCreate(NULL);
4719 if (ret == NULL)
4720 return(ret);
4721 if (xmlXPathNodeSetIsEmpty(nodes) ||
4722 (!xmlXPathNodeSetContains(nodes, node)))
4723 return(ret);
4724
4725 l = xmlXPathNodeSetGetLength(nodes);
4726 for (i = l - 1; i >= 0; i--) {
4727 cur = xmlXPathNodeSetItem(nodes, i);
4728 if (cur == node)
4729 break;
4730 /* TODO: Propagate memory error. */
4731 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4732 break;
4733 }
4734 xmlXPathNodeSetSort(ret); /* bug 413451 */
4735 return(ret);
4736}
4737
4738/**
4739 * xmlXPathNodeTrailing:
4740 * @nodes: a node-set
4741 * @node: a node
4742 *
4743 * Implements the EXSLT - Sets trailing() function:
4744 * node-set set:trailing (node-set, node-set)
4745 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4746 * is called.
4747 *
4748 * Returns the nodes in @nodes that follow @node in document order,
4749 * @nodes if @node is NULL or an empty node-set if @nodes
4750 * doesn't contain @node
4751 */
4752xmlNodeSetPtr
4753xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4754 xmlXPathNodeSetSort(nodes);
4755 return(xmlXPathNodeTrailingSorted(nodes, node));
4756}
4757
4758/**
4759 * xmlXPathTrailingSorted:
4760 * @nodes1: a node-set, sorted by document order
4761 * @nodes2: a node-set, sorted by document order
4762 *
4763 * Implements the EXSLT - Sets trailing() function:
4764 * node-set set:trailing (node-set, node-set)
4765 *
4766 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4767 * in document order, @nodes1 if @nodes2 is NULL or empty or
4768 * an empty node-set if @nodes1 doesn't contain @nodes2
4769 */
4770xmlNodeSetPtr
4771xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4772 if (xmlXPathNodeSetIsEmpty(nodes2))
4773 return(nodes1);
4774 return(xmlXPathNodeTrailingSorted(nodes1,
4775 xmlXPathNodeSetItem(nodes2, 0)));
4776}
4777
4778/**
4779 * xmlXPathTrailing:
4780 * @nodes1: a node-set
4781 * @nodes2: a node-set
4782 *
4783 * Implements the EXSLT - Sets trailing() function:
4784 * node-set set:trailing (node-set, node-set)
4785 * @nodes1 and @nodes2 are sorted by document order, then
4786 * #xmlXPathTrailingSorted is called.
4787 *
4788 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4789 * in document order, @nodes1 if @nodes2 is NULL or empty or
4790 * an empty node-set if @nodes1 doesn't contain @nodes2
4791 */
4792xmlNodeSetPtr
4793xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4794 if (xmlXPathNodeSetIsEmpty(nodes2))
4795 return(nodes1);
4796 if (xmlXPathNodeSetIsEmpty(nodes1))
4797 return(xmlXPathNodeSetCreate(NULL));
4798 xmlXPathNodeSetSort(nodes1);
4799 xmlXPathNodeSetSort(nodes2);
4800 return(xmlXPathNodeTrailingSorted(nodes1,
4801 xmlXPathNodeSetItem(nodes2, 0)));
4802}
4803
4804/************************************************************************
4805 * *
4806 * Routines to handle extra functions *
4807 * *
4808 ************************************************************************/
4809
4810/**
4811 * xmlXPathRegisterFunc:
4812 * @ctxt: the XPath context
4813 * @name: the function name
4814 * @f: the function implementation or NULL
4815 *
4816 * Register a new function. If @f is NULL it unregisters the function
4817 *
4818 * Returns 0 in case of success, -1 in case of error
4819 */
4820int
4821xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4822 xmlXPathFunction f) {
4823 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4824}
4825
4826/**
4827 * xmlXPathRegisterFuncNS:
4828 * @ctxt: the XPath context
4829 * @name: the function name
4830 * @ns_uri: the function namespace URI
4831 * @f: the function implementation or NULL
4832 *
4833 * Register a new function. If @f is NULL it unregisters the function
4834 *
4835 * Returns 0 in case of success, -1 in case of error
4836 */
4837int
4838xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4839 const xmlChar *ns_uri, xmlXPathFunction f) {
4840 if (ctxt == NULL)
4841 return(-1);
4842 if (name == NULL)
4843 return(-1);
4844
4845 if (ctxt->funcHash == NULL)
4846 ctxt->funcHash = xmlHashCreate(0);
4847 if (ctxt->funcHash == NULL)
4848 return(-1);
4849 if (f == NULL)
4850 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4851XML_IGNORE_PEDANTIC_WARNINGS
4852 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4853XML_POP_WARNINGS
4854}
4855
4856/**
4857 * xmlXPathRegisterFuncLookup:
4858 * @ctxt: the XPath context
4859 * @f: the lookup function
4860 * @funcCtxt: the lookup data
4861 *
4862 * Registers an external mechanism to do function lookup.
4863 */
4864void
4865xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4866 xmlXPathFuncLookupFunc f,
4867 void *funcCtxt) {
4868 if (ctxt == NULL)
4869 return;
4870 ctxt->funcLookupFunc = f;
4871 ctxt->funcLookupData = funcCtxt;
4872}
4873
4874/**
4875 * xmlXPathFunctionLookup:
4876 * @ctxt: the XPath context
4877 * @name: the function name
4878 *
4879 * Search in the Function array of the context for the given
4880 * function.
4881 *
4882 * Returns the xmlXPathFunction or NULL if not found
4883 */
4884xmlXPathFunction
4885xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4886 if (ctxt == NULL)
4887 return (NULL);
4888
4889 if (ctxt->funcLookupFunc != NULL) {
4890 xmlXPathFunction ret;
4891 xmlXPathFuncLookupFunc f;
4892
4893 f = ctxt->funcLookupFunc;
4894 ret = f(ctxt->funcLookupData, name, NULL);
4895 if (ret != NULL)
4896 return(ret);
4897 }
4898 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4899}
4900
4901/**
4902 * xmlXPathFunctionLookupNS:
4903 * @ctxt: the XPath context
4904 * @name: the function name
4905 * @ns_uri: the function namespace URI
4906 *
4907 * Search in the Function array of the context for the given
4908 * function.
4909 *
4910 * Returns the xmlXPathFunction or NULL if not found
4911 */
4912xmlXPathFunction
4913xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4914 const xmlChar *ns_uri) {
4915 xmlXPathFunction ret;
4916
4917 if (ctxt == NULL)
4918 return(NULL);
4919 if (name == NULL)
4920 return(NULL);
4921
4922 if (ctxt->funcLookupFunc != NULL) {
4923 xmlXPathFuncLookupFunc f;
4924
4925 f = ctxt->funcLookupFunc;
4926 ret = f(ctxt->funcLookupData, name, ns_uri);
4927 if (ret != NULL)
4928 return(ret);
4929 }
4930
4931 if (ctxt->funcHash == NULL)
4932 return(NULL);
4933
4934XML_IGNORE_PEDANTIC_WARNINGS
4935 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4936XML_POP_WARNINGS
4937 return(ret);
4938}
4939
4940/**
4941 * xmlXPathRegisteredFuncsCleanup:
4942 * @ctxt: the XPath context
4943 *
4944 * Cleanup the XPath context data associated to registered functions
4945 */
4946void
4947xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4948 if (ctxt == NULL)
4949 return;
4950
4951 xmlHashFree(ctxt->funcHash, NULL);
4952 ctxt->funcHash = NULL;
4953}
4954
4955/************************************************************************
4956 * *
4957 * Routines to handle Variables *
4958 * *
4959 ************************************************************************/
4960
4961/**
4962 * xmlXPathRegisterVariable:
4963 * @ctxt: the XPath context
4964 * @name: the variable name
4965 * @value: the variable value or NULL
4966 *
4967 * Register a new variable value. If @value is NULL it unregisters
4968 * the variable
4969 *
4970 * Returns 0 in case of success, -1 in case of error
4971 */
4972int
4973xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4974 xmlXPathObjectPtr value) {
4975 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4976}
4977
4978/**
4979 * xmlXPathRegisterVariableNS:
4980 * @ctxt: the XPath context
4981 * @name: the variable name
4982 * @ns_uri: the variable namespace URI
4983 * @value: the variable value or NULL
4984 *
4985 * Register a new variable value. If @value is NULL it unregisters
4986 * the variable
4987 *
4988 * Returns 0 in case of success, -1 in case of error
4989 */
4990int
4991xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4992 const xmlChar *ns_uri,
4993 xmlXPathObjectPtr value) {
4994 if (ctxt == NULL)
4995 return(-1);
4996 if (name == NULL)
4997 return(-1);
4998
4999 if (ctxt->varHash == NULL)
5000 ctxt->varHash = xmlHashCreate(0);
5001 if (ctxt->varHash == NULL)
5002 return(-1);
5003 if (value == NULL)
5004 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5005 xmlXPathFreeObjectEntry));
5006 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5007 (void *) value, xmlXPathFreeObjectEntry));
5008}
5009
5010/**
5011 * xmlXPathRegisterVariableLookup:
5012 * @ctxt: the XPath context
5013 * @f: the lookup function
5014 * @data: the lookup data
5015 *
5016 * register an external mechanism to do variable lookup
5017 */
5018void
5019xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5020 xmlXPathVariableLookupFunc f, void *data) {
5021 if (ctxt == NULL)
5022 return;
5023 ctxt->varLookupFunc = f;
5024 ctxt->varLookupData = data;
5025}
5026
5027/**
5028 * xmlXPathVariableLookup:
5029 * @ctxt: the XPath context
5030 * @name: the variable name
5031 *
5032 * Search in the Variable array of the context for the given
5033 * variable value.
5034 *
5035 * Returns a copy of the value or NULL if not found
5036 */
5037xmlXPathObjectPtr
5038xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5039 if (ctxt == NULL)
5040 return(NULL);
5041
5042 if (ctxt->varLookupFunc != NULL) {
5043 xmlXPathObjectPtr ret;
5044
5045 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5046 (ctxt->varLookupData, name, NULL);
5047 return(ret);
5048 }
5049 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5050}
5051
5052/**
5053 * xmlXPathVariableLookupNS:
5054 * @ctxt: the XPath context
5055 * @name: the variable name
5056 * @ns_uri: the variable namespace URI
5057 *
5058 * Search in the Variable array of the context for the given
5059 * variable value.
5060 *
5061 * Returns the a copy of the value or NULL if not found
5062 */
5063xmlXPathObjectPtr
5064xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5065 const xmlChar *ns_uri) {
5066 if (ctxt == NULL)
5067 return(NULL);
5068
5069 if (ctxt->varLookupFunc != NULL) {
5070 xmlXPathObjectPtr ret;
5071
5072 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5073 (ctxt->varLookupData, name, ns_uri);
5074 if (ret != NULL) return(ret);
5075 }
5076
5077 if (ctxt->varHash == NULL)
5078 return(NULL);
5079 if (name == NULL)
5080 return(NULL);
5081
5082 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5083 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5084}
5085
5086/**
5087 * xmlXPathRegisteredVariablesCleanup:
5088 * @ctxt: the XPath context
5089 *
5090 * Cleanup the XPath context data associated to registered variables
5091 */
5092void
5093xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5094 if (ctxt == NULL)
5095 return;
5096
5097 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5098 ctxt->varHash = NULL;
5099}
5100
5101/**
5102 * xmlXPathRegisterNs:
5103 * @ctxt: the XPath context
5104 * @prefix: the namespace prefix cannot be NULL or empty string
5105 * @ns_uri: the namespace name
5106 *
5107 * Register a new namespace. If @ns_uri is NULL it unregisters
5108 * the namespace
5109 *
5110 * Returns 0 in case of success, -1 in case of error
5111 */
5112int
5113xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5114 const xmlChar *ns_uri) {
5115 if (ctxt == NULL)
5116 return(-1);
5117 if (prefix == NULL)
5118 return(-1);
5119 if (prefix[0] == 0)
5120 return(-1);
5121
5122 if (ctxt->nsHash == NULL)
5123 ctxt->nsHash = xmlHashCreate(10);
5124 if (ctxt->nsHash == NULL)
5125 return(-1);
5126 if (ns_uri == NULL)
5127 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5128 xmlHashDefaultDeallocator));
5129 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5130 xmlHashDefaultDeallocator));
5131}
5132
5133/**
5134 * xmlXPathNsLookup:
5135 * @ctxt: the XPath context
5136 * @prefix: the namespace prefix value
5137 *
5138 * Search in the namespace declaration array of the context for the given
5139 * namespace name associated to the given prefix
5140 *
5141 * Returns the value or NULL if not found
5142 */
5143const xmlChar *
5144xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5145 if (ctxt == NULL)
5146 return(NULL);
5147 if (prefix == NULL)
5148 return(NULL);
5149
5150#ifdef XML_XML_NAMESPACE
5151 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5152 return(XML_XML_NAMESPACE);
5153#endif
5154
5155 if (ctxt->namespaces != NULL) {
5156 int i;
5157
5158 for (i = 0;i < ctxt->nsNr;i++) {
5159 if ((ctxt->namespaces[i] != NULL) &&
5160 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5161 return(ctxt->namespaces[i]->href);
5162 }
5163 }
5164
5165 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5166}
5167
5168/**
5169 * xmlXPathRegisteredNsCleanup:
5170 * @ctxt: the XPath context
5171 *
5172 * Cleanup the XPath context data associated to registered variables
5173 */
5174void
5175xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5176 if (ctxt == NULL)
5177 return;
5178
5179 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5180 ctxt->nsHash = NULL;
5181}
5182
5183/************************************************************************
5184 * *
5185 * Routines to handle Values *
5186 * *
5187 ************************************************************************/
5188
5189/* Allocations are terrible, one needs to optimize all this !!! */
5190
5191/**
5192 * xmlXPathNewFloat:
5193 * @val: the double value
5194 *
5195 * Create a new xmlXPathObjectPtr of type double and of value @val
5196 *
5197 * Returns the newly created object.
5198 */
5199xmlXPathObjectPtr
5200xmlXPathNewFloat(double val) {
5201 xmlXPathObjectPtr ret;
5202
5203 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5204 if (ret == NULL) {
5205 xmlXPathErrMemory(NULL, "creating float object\n");
5206 return(NULL);
5207 }
5208 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5209 ret->type = XPATH_NUMBER;
5210 ret->floatval = val;
5211#ifdef XP_DEBUG_OBJ_USAGE
5212 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5213#endif
5214 return(ret);
5215}
5216
5217/**
5218 * xmlXPathNewBoolean:
5219 * @val: the boolean value
5220 *
5221 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5222 *
5223 * Returns the newly created object.
5224 */
5225xmlXPathObjectPtr
5226xmlXPathNewBoolean(int val) {
5227 xmlXPathObjectPtr ret;
5228
5229 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5230 if (ret == NULL) {
5231 xmlXPathErrMemory(NULL, "creating boolean object\n");
5232 return(NULL);
5233 }
5234 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5235 ret->type = XPATH_BOOLEAN;
5236 ret->boolval = (val != 0);
5237#ifdef XP_DEBUG_OBJ_USAGE
5238 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5239#endif
5240 return(ret);
5241}
5242
5243/**
5244 * xmlXPathNewString:
5245 * @val: the xmlChar * value
5246 *
5247 * Create a new xmlXPathObjectPtr of type string and of value @val
5248 *
5249 * Returns the newly created object.
5250 */
5251xmlXPathObjectPtr
5252xmlXPathNewString(const xmlChar *val) {
5253 xmlXPathObjectPtr ret;
5254
5255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5256 if (ret == NULL) {
5257 xmlXPathErrMemory(NULL, "creating string object\n");
5258 return(NULL);
5259 }
5260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5261 ret->type = XPATH_STRING;
5262 if (val != NULL)
5263 ret->stringval = xmlStrdup(val);
5264 else
5265 ret->stringval = xmlStrdup((const xmlChar *)"");
5266#ifdef XP_DEBUG_OBJ_USAGE
5267 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5268#endif
5269 return(ret);
5270}
5271
5272/**
5273 * xmlXPathWrapString:
5274 * @val: the xmlChar * value
5275 *
5276 * Wraps the @val string into an XPath object.
5277 *
5278 * Returns the newly created object.
5279 */
5280xmlXPathObjectPtr
5281xmlXPathWrapString (xmlChar *val) {
5282 xmlXPathObjectPtr ret;
5283
5284 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5285 if (ret == NULL) {
5286 xmlXPathErrMemory(NULL, "creating string object\n");
5287 return(NULL);
5288 }
5289 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5290 ret->type = XPATH_STRING;
5291 ret->stringval = val;
5292#ifdef XP_DEBUG_OBJ_USAGE
5293 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5294#endif
5295 return(ret);
5296}
5297
5298/**
5299 * xmlXPathNewCString:
5300 * @val: the char * value
5301 *
5302 * Create a new xmlXPathObjectPtr of type string and of value @val
5303 *
5304 * Returns the newly created object.
5305 */
5306xmlXPathObjectPtr
5307xmlXPathNewCString(const char *val) {
5308 xmlXPathObjectPtr ret;
5309
5310 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5311 if (ret == NULL) {
5312 xmlXPathErrMemory(NULL, "creating string object\n");
5313 return(NULL);
5314 }
5315 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5316 ret->type = XPATH_STRING;
5317 ret->stringval = xmlStrdup(BAD_CAST val);
5318#ifdef XP_DEBUG_OBJ_USAGE
5319 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5320#endif
5321 return(ret);
5322}
5323
5324/**
5325 * xmlXPathWrapCString:
5326 * @val: the char * value
5327 *
5328 * Wraps a string into an XPath object.
5329 *
5330 * Returns the newly created object.
5331 */
5332xmlXPathObjectPtr
5333xmlXPathWrapCString (char * val) {
5334 return(xmlXPathWrapString((xmlChar *)(val)));
5335}
5336
5337/**
5338 * xmlXPathWrapExternal:
5339 * @val: the user data
5340 *
5341 * Wraps the @val data into an XPath object.
5342 *
5343 * Returns the newly created object.
5344 */
5345xmlXPathObjectPtr
5346xmlXPathWrapExternal (void *val) {
5347 xmlXPathObjectPtr ret;
5348
5349 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5350 if (ret == NULL) {
5351 xmlXPathErrMemory(NULL, "creating user object\n");
5352 return(NULL);
5353 }
5354 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5355 ret->type = XPATH_USERS;
5356 ret->user = val;
5357#ifdef XP_DEBUG_OBJ_USAGE
5358 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5359#endif
5360 return(ret);
5361}
5362
5363/**
5364 * xmlXPathObjectCopy:
5365 * @val: the original object
5366 *
5367 * allocate a new copy of a given object
5368 *
5369 * Returns the newly created object.
5370 */
5371xmlXPathObjectPtr
5372xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5373 xmlXPathObjectPtr ret;
5374
5375 if (val == NULL)
5376 return(NULL);
5377
5378 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5379 if (ret == NULL) {
5380 xmlXPathErrMemory(NULL, "copying object\n");
5381 return(NULL);
5382 }
5383 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5384#ifdef XP_DEBUG_OBJ_USAGE
5385 xmlXPathDebugObjUsageRequested(NULL, val->type);
5386#endif
5387 switch (val->type) {
5388 case XPATH_BOOLEAN:
5389 case XPATH_NUMBER:
5390 case XPATH_POINT:
5391 case XPATH_RANGE:
5392 break;
5393 case XPATH_STRING:
5394 ret->stringval = xmlStrdup(val->stringval);
5395 break;
5396 case XPATH_XSLT_TREE:
5397#if 0
5398/*
5399 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5400 this previous handling is no longer correct, and can cause some serious
5401 problems (ref. bug 145547)
5402*/
5403 if ((val->nodesetval != NULL) &&
5404 (val->nodesetval->nodeTab != NULL)) {
5405 xmlNodePtr cur, tmp;
5406 xmlDocPtr top;
5407
5408 ret->boolval = 1;
5409 top = xmlNewDoc(NULL);
5410 top->name = (char *)
5411 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5412 ret->user = top;
5413 if (top != NULL) {
5414 top->doc = top;
5415 cur = val->nodesetval->nodeTab[0]->children;
5416 while (cur != NULL) {
5417 tmp = xmlDocCopyNode(cur, top, 1);
5418 xmlAddChild((xmlNodePtr) top, tmp);
5419 cur = cur->next;
5420 }
5421 }
5422
5423 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5424 } else
5425 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5426 /* Deallocate the copied tree value */
5427 break;
5428#endif
5429 case XPATH_NODESET:
5430 /* TODO: Check memory error. */
5431 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5432 /* Do not deallocate the copied tree value */
5433 ret->boolval = 0;
5434 break;
5435 case XPATH_LOCATIONSET:
5436#ifdef LIBXML_XPTR_ENABLED
5437 {
5438 xmlLocationSetPtr loc = val->user;
5439 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5440 break;
5441 }
5442#endif
5443 case XPATH_USERS:
5444 ret->user = val->user;
5445 break;
5446 case XPATH_UNDEFINED:
5447 xmlGenericError(xmlGenericErrorContext,
5448 "xmlXPathObjectCopy: unsupported type %d\n",
5449 val->type);
5450 break;
5451 }
5452 return(ret);
5453}
5454
5455/**
5456 * xmlXPathFreeObject:
5457 * @obj: the object to free
5458 *
5459 * Free up an xmlXPathObjectPtr object.
5460 */
5461void
5462xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5463 if (obj == NULL) return;
5464 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5465 if (obj->boolval) {
5466#if 0
5467 if (obj->user != NULL) {
5468 xmlXPathFreeNodeSet(obj->nodesetval);
5469 xmlFreeNodeList((xmlNodePtr) obj->user);
5470 } else
5471#endif
5472 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5473 if (obj->nodesetval != NULL)
5474 xmlXPathFreeValueTree(obj->nodesetval);
5475 } else {
5476 if (obj->nodesetval != NULL)
5477 xmlXPathFreeNodeSet(obj->nodesetval);
5478 }
5479#ifdef LIBXML_XPTR_ENABLED
5480 } else if (obj->type == XPATH_LOCATIONSET) {
5481 if (obj->user != NULL)
5482 xmlXPtrFreeLocationSet(obj->user);
5483#endif
5484 } else if (obj->type == XPATH_STRING) {
5485 if (obj->stringval != NULL)
5486 xmlFree(obj->stringval);
5487 }
5488#ifdef XP_DEBUG_OBJ_USAGE
5489 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5490#endif
5491 xmlFree(obj);
5492}
5493
5494static void
5495xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5496 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5497}
5498
5499/**
5500 * xmlXPathReleaseObject:
5501 * @obj: the xmlXPathObjectPtr to free or to cache
5502 *
5503 * Depending on the state of the cache this frees the given
5504 * XPath object or stores it in the cache.
5505 */
5506static void
5507xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5508{
5509#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5510 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5511 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5512
5513#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5514
5515 if (obj == NULL)
5516 return;
5517 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5518 xmlXPathFreeObject(obj);
5519 } else {
5520 xmlXPathContextCachePtr cache =
5521 (xmlXPathContextCachePtr) ctxt->cache;
5522
5523 switch (obj->type) {
5524 case XPATH_NODESET:
5525 case XPATH_XSLT_TREE:
5526 if (obj->nodesetval != NULL) {
5527 if (obj->boolval) {
5528 /*
5529 * It looks like the @boolval is used for
5530 * evaluation if this an XSLT Result Tree Fragment.
5531 * TODO: Check if this assumption is correct.
5532 */
5533 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5534 xmlXPathFreeValueTree(obj->nodesetval);
5535 obj->nodesetval = NULL;
5536 } else if ((obj->nodesetval->nodeMax <= 40) &&
5537 (XP_CACHE_WANTS(cache->nodesetObjs,
5538 cache->maxNodeset)))
5539 {
5540 XP_CACHE_ADD(cache->nodesetObjs, obj);
5541 goto obj_cached;
5542 } else {
5543 xmlXPathFreeNodeSet(obj->nodesetval);
5544 obj->nodesetval = NULL;
5545 }
5546 }
5547 break;
5548 case XPATH_STRING:
5549 if (obj->stringval != NULL)
5550 xmlFree(obj->stringval);
5551
5552 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5553 XP_CACHE_ADD(cache->stringObjs, obj);
5554 goto obj_cached;
5555 }
5556 break;
5557 case XPATH_BOOLEAN:
5558 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5559 XP_CACHE_ADD(cache->booleanObjs, obj);
5560 goto obj_cached;
5561 }
5562 break;
5563 case XPATH_NUMBER:
5564 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5565 XP_CACHE_ADD(cache->numberObjs, obj);
5566 goto obj_cached;
5567 }
5568 break;
5569#ifdef LIBXML_XPTR_ENABLED
5570 case XPATH_LOCATIONSET:
5571 if (obj->user != NULL) {
5572 xmlXPtrFreeLocationSet(obj->user);
5573 }
5574 goto free_obj;
5575#endif
5576 default:
5577 goto free_obj;
5578 }
5579
5580 /*
5581 * Fallback to adding to the misc-objects slot.
5582 */
5583 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5584 XP_CACHE_ADD(cache->miscObjs, obj);
5585 } else
5586 goto free_obj;
5587
5588obj_cached:
5589
5590#ifdef XP_DEBUG_OBJ_USAGE
5591 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5592#endif
5593
5594 if (obj->nodesetval != NULL) {
5595 xmlNodeSetPtr tmpset = obj->nodesetval;
5596
5597 /*
5598 * TODO: Due to those nasty ns-nodes, we need to traverse
5599 * the list and free the ns-nodes.
5600 * URGENT TODO: Check if it's actually slowing things down.
5601 * Maybe we shouldn't try to preserve the list.
5602 */
5603 if (tmpset->nodeNr > 1) {
5604 int i;
5605 xmlNodePtr node;
5606
5607 for (i = 0; i < tmpset->nodeNr; i++) {
5608 node = tmpset->nodeTab[i];
5609 if ((node != NULL) &&
5610 (node->type == XML_NAMESPACE_DECL))
5611 {
5612 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5613 }
5614 }
5615 } else if (tmpset->nodeNr == 1) {
5616 if ((tmpset->nodeTab[0] != NULL) &&
5617 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5618 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5619 }
5620 tmpset->nodeNr = 0;
5621 memset(obj, 0, sizeof(xmlXPathObject));
5622 obj->nodesetval = tmpset;
5623 } else
5624 memset(obj, 0, sizeof(xmlXPathObject));
5625
5626 return;
5627
5628free_obj:
5629 /*
5630 * Cache is full; free the object.
5631 */
5632 if (obj->nodesetval != NULL)
5633 xmlXPathFreeNodeSet(obj->nodesetval);
5634#ifdef XP_DEBUG_OBJ_USAGE
5635 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5636#endif
5637 xmlFree(obj);
5638 }
5639 return;
5640}
5641
5642
5643/************************************************************************
5644 * *
5645 * Type Casting Routines *
5646 * *
5647 ************************************************************************/
5648
5649/**
5650 * xmlXPathCastBooleanToString:
5651 * @val: a boolean
5652 *
5653 * Converts a boolean to its string value.
5654 *
5655 * Returns a newly allocated string.
5656 */
5657xmlChar *
5658xmlXPathCastBooleanToString (int val) {
5659 xmlChar *ret;
5660 if (val)
5661 ret = xmlStrdup((const xmlChar *) "true");
5662 else
5663 ret = xmlStrdup((const xmlChar *) "false");
5664 return(ret);
5665}
5666
5667/**
5668 * xmlXPathCastNumberToString:
5669 * @val: a number
5670 *
5671 * Converts a number to its string value.
5672 *
5673 * Returns a newly allocated string.
5674 */
5675xmlChar *
5676xmlXPathCastNumberToString (double val) {
5677 xmlChar *ret;
5678 switch (xmlXPathIsInf(val)) {
5679 case 1:
5680 ret = xmlStrdup((const xmlChar *) "Infinity");
5681 break;
5682 case -1:
5683 ret = xmlStrdup((const xmlChar *) "-Infinity");
5684 break;
5685 default:
5686 if (xmlXPathIsNaN(val)) {
5687 ret = xmlStrdup((const xmlChar *) "NaN");
5688 } else if (val == 0) {
5689 /* Omit sign for negative zero. */
5690 ret = xmlStrdup((const xmlChar *) "0");
5691 } else {
5692 /* could be improved */
5693 char buf[100];
5694 xmlXPathFormatNumber(val, buf, 99);
5695 buf[99] = 0;
5696 ret = xmlStrdup((const xmlChar *) buf);
5697 }
5698 }
5699 return(ret);
5700}
5701
5702/**
5703 * xmlXPathCastNodeToString:
5704 * @node: a node
5705 *
5706 * Converts a node to its string value.
5707 *
5708 * Returns a newly allocated string.
5709 */
5710xmlChar *
5711xmlXPathCastNodeToString (xmlNodePtr node) {
5712xmlChar *ret;
5713 if ((ret = xmlNodeGetContent(node)) == NULL)
5714 ret = xmlStrdup((const xmlChar *) "");
5715 return(ret);
5716}
5717
5718/**
5719 * xmlXPathCastNodeSetToString:
5720 * @ns: a node-set
5721 *
5722 * Converts a node-set to its string value.
5723 *
5724 * Returns a newly allocated string.
5725 */
5726xmlChar *
5727xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5728 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5729 return(xmlStrdup((const xmlChar *) ""));
5730
5731 if (ns->nodeNr > 1)
5732 xmlXPathNodeSetSort(ns);
5733 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5734}
5735
5736/**
5737 * xmlXPathCastToString:
5738 * @val: an XPath object
5739 *
5740 * Converts an existing object to its string() equivalent
5741 *
5742 * Returns the allocated string value of the object, NULL in case of error.
5743 * It's up to the caller to free the string memory with xmlFree().
5744 */
5745xmlChar *
5746xmlXPathCastToString(xmlXPathObjectPtr val) {
5747 xmlChar *ret = NULL;
5748
5749 if (val == NULL)
5750 return(xmlStrdup((const xmlChar *) ""));
5751 switch (val->type) {
5752 case XPATH_UNDEFINED:
5753#ifdef DEBUG_EXPR
5754 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5755#endif
5756 ret = xmlStrdup((const xmlChar *) "");
5757 break;
5758 case XPATH_NODESET:
5759 case XPATH_XSLT_TREE:
5760 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5761 break;
5762 case XPATH_STRING:
5763 return(xmlStrdup(val->stringval));
5764 case XPATH_BOOLEAN:
5765 ret = xmlXPathCastBooleanToString(val->boolval);
5766 break;
5767 case XPATH_NUMBER: {
5768 ret = xmlXPathCastNumberToString(val->floatval);
5769 break;
5770 }
5771 case XPATH_USERS:
5772 case XPATH_POINT:
5773 case XPATH_RANGE:
5774 case XPATH_LOCATIONSET:
5775 TODO
5776 ret = xmlStrdup((const xmlChar *) "");
5777 break;
5778 }
5779 return(ret);
5780}
5781
5782/**
5783 * xmlXPathConvertString:
5784 * @val: an XPath object
5785 *
5786 * Converts an existing object to its string() equivalent
5787 *
5788 * Returns the new object, the old one is freed (or the operation
5789 * is done directly on @val)
5790 */
5791xmlXPathObjectPtr
5792xmlXPathConvertString(xmlXPathObjectPtr val) {
5793 xmlChar *res = NULL;
5794
5795 if (val == NULL)
5796 return(xmlXPathNewCString(""));
5797
5798 switch (val->type) {
5799 case XPATH_UNDEFINED:
5800#ifdef DEBUG_EXPR
5801 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5802#endif
5803 break;
5804 case XPATH_NODESET:
5805 case XPATH_XSLT_TREE:
5806 res = xmlXPathCastNodeSetToString(val->nodesetval);
5807 break;
5808 case XPATH_STRING:
5809 return(val);
5810 case XPATH_BOOLEAN:
5811 res = xmlXPathCastBooleanToString(val->boolval);
5812 break;
5813 case XPATH_NUMBER:
5814 res = xmlXPathCastNumberToString(val->floatval);
5815 break;
5816 case XPATH_USERS:
5817 case XPATH_POINT:
5818 case XPATH_RANGE:
5819 case XPATH_LOCATIONSET:
5820 TODO;
5821 break;
5822 }
5823 xmlXPathFreeObject(val);
5824 if (res == NULL)
5825 return(xmlXPathNewCString(""));
5826 return(xmlXPathWrapString(res));
5827}
5828
5829/**
5830 * xmlXPathCastBooleanToNumber:
5831 * @val: a boolean
5832 *
5833 * Converts a boolean to its number value
5834 *
5835 * Returns the number value
5836 */
5837double
5838xmlXPathCastBooleanToNumber(int val) {
5839 if (val)
5840 return(1.0);
5841 return(0.0);
5842}
5843
5844/**
5845 * xmlXPathCastStringToNumber:
5846 * @val: a string
5847 *
5848 * Converts a string to its number value
5849 *
5850 * Returns the number value
5851 */
5852double
5853xmlXPathCastStringToNumber(const xmlChar * val) {
5854 return(xmlXPathStringEvalNumber(val));
5855}
5856
5857/**
5858 * xmlXPathCastNodeToNumber:
5859 * @node: a node
5860 *
5861 * Converts a node to its number value
5862 *
5863 * Returns the number value
5864 */
5865double
5866xmlXPathCastNodeToNumber (xmlNodePtr node) {
5867 xmlChar *strval;
5868 double ret;
5869
5870 if (node == NULL)
5871 return(xmlXPathNAN);
5872 strval = xmlXPathCastNodeToString(node);
5873 if (strval == NULL)
5874 return(xmlXPathNAN);
5875 ret = xmlXPathCastStringToNumber(strval);
5876 xmlFree(strval);
5877
5878 return(ret);
5879}
5880
5881/**
5882 * xmlXPathCastNodeSetToNumber:
5883 * @ns: a node-set
5884 *
5885 * Converts a node-set to its number value
5886 *
5887 * Returns the number value
5888 */
5889double
5890xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5891 xmlChar *str;
5892 double ret;
5893
5894 if (ns == NULL)
5895 return(xmlXPathNAN);
5896 str = xmlXPathCastNodeSetToString(ns);
5897 ret = xmlXPathCastStringToNumber(str);
5898 xmlFree(str);
5899 return(ret);
5900}
5901
5902/**
5903 * xmlXPathCastToNumber:
5904 * @val: an XPath object
5905 *
5906 * Converts an XPath object to its number value
5907 *
5908 * Returns the number value
5909 */
5910double
5911xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5912 double ret = 0.0;
5913
5914 if (val == NULL)
5915 return(xmlXPathNAN);
5916 switch (val->type) {
5917 case XPATH_UNDEFINED:
5918#ifdef DEBUG_EXPR
5919 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5920#endif
5921 ret = xmlXPathNAN;
5922 break;
5923 case XPATH_NODESET:
5924 case XPATH_XSLT_TREE:
5925 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5926 break;
5927 case XPATH_STRING:
5928 ret = xmlXPathCastStringToNumber(val->stringval);
5929 break;
5930 case XPATH_NUMBER:
5931 ret = val->floatval;
5932 break;
5933 case XPATH_BOOLEAN:
5934 ret = xmlXPathCastBooleanToNumber(val->boolval);
5935 break;
5936 case XPATH_USERS:
5937 case XPATH_POINT:
5938 case XPATH_RANGE:
5939 case XPATH_LOCATIONSET:
5940 TODO;
5941 ret = xmlXPathNAN;
5942 break;
5943 }
5944 return(ret);
5945}
5946
5947/**
5948 * xmlXPathConvertNumber:
5949 * @val: an XPath object
5950 *
5951 * Converts an existing object to its number() equivalent
5952 *
5953 * Returns the new object, the old one is freed (or the operation
5954 * is done directly on @val)
5955 */
5956xmlXPathObjectPtr
5957xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5958 xmlXPathObjectPtr ret;
5959
5960 if (val == NULL)
5961 return(xmlXPathNewFloat(0.0));
5962 if (val->type == XPATH_NUMBER)
5963 return(val);
5964 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5965 xmlXPathFreeObject(val);
5966 return(ret);
5967}
5968
5969/**
5970 * xmlXPathCastNumberToBoolean:
5971 * @val: a number
5972 *
5973 * Converts a number to its boolean value
5974 *
5975 * Returns the boolean value
5976 */
5977int
5978xmlXPathCastNumberToBoolean (double val) {
5979 if (xmlXPathIsNaN(val) || (val == 0.0))
5980 return(0);
5981 return(1);
5982}
5983
5984/**
5985 * xmlXPathCastStringToBoolean:
5986 * @val: a string
5987 *
5988 * Converts a string to its boolean value
5989 *
5990 * Returns the boolean value
5991 */
5992int
5993xmlXPathCastStringToBoolean (const xmlChar *val) {
5994 if ((val == NULL) || (xmlStrlen(val) == 0))
5995 return(0);
5996 return(1);
5997}
5998
5999/**
6000 * xmlXPathCastNodeSetToBoolean:
6001 * @ns: a node-set
6002 *
6003 * Converts a node-set to its boolean value
6004 *
6005 * Returns the boolean value
6006 */
6007int
6008xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6009 if ((ns == NULL) || (ns->nodeNr == 0))
6010 return(0);
6011 return(1);
6012}
6013
6014/**
6015 * xmlXPathCastToBoolean:
6016 * @val: an XPath object
6017 *
6018 * Converts an XPath object to its boolean value
6019 *
6020 * Returns the boolean value
6021 */
6022int
6023xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6024 int ret = 0;
6025
6026 if (val == NULL)
6027 return(0);
6028 switch (val->type) {
6029 case XPATH_UNDEFINED:
6030#ifdef DEBUG_EXPR
6031 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6032#endif
6033 ret = 0;
6034 break;
6035 case XPATH_NODESET:
6036 case XPATH_XSLT_TREE:
6037 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6038 break;
6039 case XPATH_STRING:
6040 ret = xmlXPathCastStringToBoolean(val->stringval);
6041 break;
6042 case XPATH_NUMBER:
6043 ret = xmlXPathCastNumberToBoolean(val->floatval);
6044 break;
6045 case XPATH_BOOLEAN:
6046 ret = val->boolval;
6047 break;
6048 case XPATH_USERS:
6049 case XPATH_POINT:
6050 case XPATH_RANGE:
6051 case XPATH_LOCATIONSET:
6052 TODO;
6053 ret = 0;
6054 break;
6055 }
6056 return(ret);
6057}
6058
6059
6060/**
6061 * xmlXPathConvertBoolean:
6062 * @val: an XPath object
6063 *
6064 * Converts an existing object to its boolean() equivalent
6065 *
6066 * Returns the new object, the old one is freed (or the operation
6067 * is done directly on @val)
6068 */
6069xmlXPathObjectPtr
6070xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6071 xmlXPathObjectPtr ret;
6072
6073 if (val == NULL)
6074 return(xmlXPathNewBoolean(0));
6075 if (val->type == XPATH_BOOLEAN)
6076 return(val);
6077 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6078 xmlXPathFreeObject(val);
6079 return(ret);
6080}
6081
6082/************************************************************************
6083 * *
6084 * Routines to handle XPath contexts *
6085 * *
6086 ************************************************************************/
6087
6088/**
6089 * xmlXPathNewContext:
6090 * @doc: the XML document
6091 *
6092 * Create a new xmlXPathContext
6093 *
6094 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6095 */
6096xmlXPathContextPtr
6097xmlXPathNewContext(xmlDocPtr doc) {
6098 xmlXPathContextPtr ret;
6099
6100 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6101 if (ret == NULL) {
6102 xmlXPathErrMemory(NULL, "creating context\n");
6103 return(NULL);
6104 }
6105 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6106 ret->doc = doc;
6107 ret->node = NULL;
6108
6109 ret->varHash = NULL;
6110
6111 ret->nb_types = 0;
6112 ret->max_types = 0;
6113 ret->types = NULL;
6114
6115 ret->funcHash = xmlHashCreate(0);
6116
6117 ret->nb_axis = 0;
6118 ret->max_axis = 0;
6119 ret->axis = NULL;
6120
6121 ret->nsHash = NULL;
6122 ret->user = NULL;
6123
6124 ret->contextSize = -1;
6125 ret->proximityPosition = -1;
6126
6127#ifdef XP_DEFAULT_CACHE_ON
6128 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6129 xmlXPathFreeContext(ret);
6130 return(NULL);
6131 }
6132#endif
6133
6134 xmlXPathRegisterAllFunctions(ret);
6135
6136 return(ret);
6137}
6138
6139/**
6140 * xmlXPathFreeContext:
6141 * @ctxt: the context to free
6142 *
6143 * Free up an xmlXPathContext
6144 */
6145void
6146xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6147 if (ctxt == NULL) return;
6148
6149 if (ctxt->cache != NULL)
6150 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6151 xmlXPathRegisteredNsCleanup(ctxt);
6152 xmlXPathRegisteredFuncsCleanup(ctxt);
6153 xmlXPathRegisteredVariablesCleanup(ctxt);
6154 xmlResetError(&ctxt->lastError);
6155 xmlFree(ctxt);
6156}
6157
6158/************************************************************************
6159 * *
6160 * Routines to handle XPath parser contexts *
6161 * *
6162 ************************************************************************/
6163
6164#define CHECK_CTXT(ctxt) \
6165 if (ctxt == NULL) { \
6166 __xmlRaiseError(NULL, NULL, NULL, \
6167 NULL, NULL, XML_FROM_XPATH, \
6168 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6169 __FILE__, __LINE__, \
6170 NULL, NULL, NULL, 0, 0, \
6171 "NULL context pointer\n"); \
6172 return(NULL); \
6173 } \
6174
6175#define CHECK_CTXT_NEG(ctxt) \
6176 if (ctxt == NULL) { \
6177 __xmlRaiseError(NULL, NULL, NULL, \
6178 NULL, NULL, XML_FROM_XPATH, \
6179 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6180 __FILE__, __LINE__, \
6181 NULL, NULL, NULL, 0, 0, \
6182 "NULL context pointer\n"); \
6183 return(-1); \
6184 } \
6185
6186
6187#define CHECK_CONTEXT(ctxt) \
6188 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6189 (ctxt->doc->children == NULL)) { \
6190 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6191 return(NULL); \
6192 }
6193
6194
6195/**
6196 * xmlXPathNewParserContext:
6197 * @str: the XPath expression
6198 * @ctxt: the XPath context
6199 *
6200 * Create a new xmlXPathParserContext
6201 *
6202 * Returns the xmlXPathParserContext just allocated.
6203 */
6204xmlXPathParserContextPtr
6205xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6206 xmlXPathParserContextPtr ret;
6207
6208 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6209 if (ret == NULL) {
6210 xmlXPathErrMemory(ctxt, "creating parser context\n");
6211 return(NULL);
6212 }
6213 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6214 ret->cur = ret->base = str;
6215 ret->context = ctxt;
6216
6217 ret->comp = xmlXPathNewCompExpr();
6218 if (ret->comp == NULL) {
6219 xmlFree(ret->valueTab);
6220 xmlFree(ret);
6221 return(NULL);
6222 }
6223 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6224 ret->comp->dict = ctxt->dict;
6225 xmlDictReference(ret->comp->dict);
6226 }
6227
6228 return(ret);
6229}
6230
6231/**
6232 * xmlXPathCompParserContext:
6233 * @comp: the XPath compiled expression
6234 * @ctxt: the XPath context
6235 *
6236 * Create a new xmlXPathParserContext when processing a compiled expression
6237 *
6238 * Returns the xmlXPathParserContext just allocated.
6239 */
6240static xmlXPathParserContextPtr
6241xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6242 xmlXPathParserContextPtr ret;
6243
6244 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6245 if (ret == NULL) {
6246 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6247 return(NULL);
6248 }
6249 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6250
6251 /* Allocate the value stack */
6252 ret->valueTab = (xmlXPathObjectPtr *)
6253 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6254 if (ret->valueTab == NULL) {
6255 xmlFree(ret);
6256 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6257 return(NULL);
6258 }
6259 ret->valueNr = 0;
6260 ret->valueMax = 10;
6261 ret->value = NULL;
6262 ret->valueFrame = 0;
6263
6264 ret->context = ctxt;
6265 ret->comp = comp;
6266
6267 return(ret);
6268}
6269
6270/**
6271 * xmlXPathFreeParserContext:
6272 * @ctxt: the context to free
6273 *
6274 * Free up an xmlXPathParserContext
6275 */
6276void
6277xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6278 int i;
6279
6280 if (ctxt->valueTab != NULL) {
6281 for (i = 0; i < ctxt->valueNr; i++) {
6282 if (ctxt->context)
6283 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6284 else
6285 xmlXPathFreeObject(ctxt->valueTab[i]);
6286 }
6287 xmlFree(ctxt->valueTab);
6288 }
6289 if (ctxt->comp != NULL) {
6290#ifdef XPATH_STREAMING
6291 if (ctxt->comp->stream != NULL) {
6292 xmlFreePatternList(ctxt->comp->stream);
6293 ctxt->comp->stream = NULL;
6294 }
6295#endif
6296 xmlXPathFreeCompExpr(ctxt->comp);
6297 }
6298 xmlFree(ctxt);
6299}
6300
6301/************************************************************************
6302 * *
6303 * The implicit core function library *
6304 * *
6305 ************************************************************************/
6306
6307/**
6308 * xmlXPathNodeValHash:
6309 * @node: a node pointer
6310 *
6311 * Function computing the beginning of the string value of the node,
6312 * used to speed up comparisons
6313 *
6314 * Returns an int usable as a hash
6315 */
6316static unsigned int
6317xmlXPathNodeValHash(xmlNodePtr node) {
6318 int len = 2;
6319 const xmlChar * string = NULL;
6320 xmlNodePtr tmp = NULL;
6321 unsigned int ret = 0;
6322
6323 if (node == NULL)
6324 return(0);
6325
6326 if (node->type == XML_DOCUMENT_NODE) {
6327 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6328 if (tmp == NULL)
6329 node = node->children;
6330 else
6331 node = tmp;
6332
6333 if (node == NULL)
6334 return(0);
6335 }
6336
6337 switch (node->type) {
6338 case XML_COMMENT_NODE:
6339 case XML_PI_NODE:
6340 case XML_CDATA_SECTION_NODE:
6341 case XML_TEXT_NODE:
6342 string = node->content;
6343 if (string == NULL)
6344 return(0);
6345 if (string[0] == 0)
6346 return(0);
6347 return(((unsigned int) string[0]) +
6348 (((unsigned int) string[1]) << 8));
6349 case XML_NAMESPACE_DECL:
6350 string = ((xmlNsPtr)node)->href;
6351 if (string == NULL)
6352 return(0);
6353 if (string[0] == 0)
6354 return(0);
6355 return(((unsigned int) string[0]) +
6356 (((unsigned int) string[1]) << 8));
6357 case XML_ATTRIBUTE_NODE:
6358 tmp = ((xmlAttrPtr) node)->children;
6359 break;
6360 case XML_ELEMENT_NODE:
6361 tmp = node->children;
6362 break;
6363 default:
6364 return(0);
6365 }
6366 while (tmp != NULL) {
6367 switch (tmp->type) {
6368 case XML_CDATA_SECTION_NODE:
6369 case XML_TEXT_NODE:
6370 string = tmp->content;
6371 break;
6372 default:
6373 string = NULL;
6374 break;
6375 }
6376 if ((string != NULL) && (string[0] != 0)) {
6377 if (len == 1) {
6378 return(ret + (((unsigned int) string[0]) << 8));
6379 }
6380 if (string[1] == 0) {
6381 len = 1;
6382 ret = (unsigned int) string[0];
6383 } else {
6384 return(((unsigned int) string[0]) +
6385 (((unsigned int) string[1]) << 8));
6386 }
6387 }
6388 /*
6389 * Skip to next node
6390 */
6391 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6392 if (tmp->children->type != XML_ENTITY_DECL) {
6393 tmp = tmp->children;
6394 continue;
6395 }
6396 }
6397 if (tmp == node)
6398 break;
6399
6400 if (tmp->next != NULL) {
6401 tmp = tmp->next;
6402 continue;
6403 }
6404
6405 do {
6406 tmp = tmp->parent;
6407 if (tmp == NULL)
6408 break;
6409 if (tmp == node) {
6410 tmp = NULL;
6411 break;
6412 }
6413 if (tmp->next != NULL) {
6414 tmp = tmp->next;
6415 break;
6416 }
6417 } while (tmp != NULL);
6418 }
6419 return(ret);
6420}
6421
6422/**
6423 * xmlXPathStringHash:
6424 * @string: a string
6425 *
6426 * Function computing the beginning of the string value of the node,
6427 * used to speed up comparisons
6428 *
6429 * Returns an int usable as a hash
6430 */
6431static unsigned int
6432xmlXPathStringHash(const xmlChar * string) {
6433 if (string == NULL)
6434 return((unsigned int) 0);
6435 if (string[0] == 0)
6436 return(0);
6437 return(((unsigned int) string[0]) +
6438 (((unsigned int) string[1]) << 8));
6439}
6440
6441/**
6442 * xmlXPathCompareNodeSetFloat:
6443 * @ctxt: the XPath Parser context
6444 * @inf: less than (1) or greater than (0)
6445 * @strict: is the comparison strict
6446 * @arg: the node set
6447 * @f: the value
6448 *
6449 * Implement the compare operation between a nodeset and a number
6450 * @ns < @val (1, 1, ...
6451 * @ns <= @val (1, 0, ...
6452 * @ns > @val (0, 1, ...
6453 * @ns >= @val (0, 0, ...
6454 *
6455 * If one object to be compared is a node-set and the other is a number,
6456 * then the comparison will be true if and only if there is a node in the
6457 * node-set such that the result of performing the comparison on the number
6458 * to be compared and on the result of converting the string-value of that
6459 * node to a number using the number function is true.
6460 *
6461 * Returns 0 or 1 depending on the results of the test.
6462 */
6463static int
6464xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6465 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6466 int i, ret = 0;
6467 xmlNodeSetPtr ns;
6468 xmlChar *str2;
6469
6470 if ((f == NULL) || (arg == NULL) ||
6471 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6472 xmlXPathReleaseObject(ctxt->context, arg);
6473 xmlXPathReleaseObject(ctxt->context, f);
6474 return(0);
6475 }
6476 ns = arg->nodesetval;
6477 if (ns != NULL) {
6478 for (i = 0;i < ns->nodeNr;i++) {
6479 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6480 if (str2 != NULL) {
6481 valuePush(ctxt,
6482 xmlXPathCacheNewString(ctxt->context, str2));
6483 xmlFree(str2);
6484 xmlXPathNumberFunction(ctxt, 1);
6485 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6486 ret = xmlXPathCompareValues(ctxt, inf, strict);
6487 if (ret)
6488 break;
6489 }
6490 }
6491 }
6492 xmlXPathReleaseObject(ctxt->context, arg);
6493 xmlXPathReleaseObject(ctxt->context, f);
6494 return(ret);
6495}
6496
6497/**
6498 * xmlXPathCompareNodeSetString:
6499 * @ctxt: the XPath Parser context
6500 * @inf: less than (1) or greater than (0)
6501 * @strict: is the comparison strict
6502 * @arg: the node set
6503 * @s: the value
6504 *
6505 * Implement the compare operation between a nodeset and a string
6506 * @ns < @val (1, 1, ...
6507 * @ns <= @val (1, 0, ...
6508 * @ns > @val (0, 1, ...
6509 * @ns >= @val (0, 0, ...
6510 *
6511 * If one object to be compared is a node-set and the other is a string,
6512 * then the comparison will be true if and only if there is a node in
6513 * the node-set such that the result of performing the comparison on the
6514 * string-value of the node and the other string is true.
6515 *
6516 * Returns 0 or 1 depending on the results of the test.
6517 */
6518static int
6519xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6520 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6521 int i, ret = 0;
6522 xmlNodeSetPtr ns;
6523 xmlChar *str2;
6524
6525 if ((s == NULL) || (arg == NULL) ||
6526 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6527 xmlXPathReleaseObject(ctxt->context, arg);
6528 xmlXPathReleaseObject(ctxt->context, s);
6529 return(0);
6530 }
6531 ns = arg->nodesetval;
6532 if (ns != NULL) {
6533 for (i = 0;i < ns->nodeNr;i++) {
6534 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6535 if (str2 != NULL) {
6536 valuePush(ctxt,
6537 xmlXPathCacheNewString(ctxt->context, str2));
6538 xmlFree(str2);
6539 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6540 ret = xmlXPathCompareValues(ctxt, inf, strict);
6541 if (ret)
6542 break;
6543 }
6544 }
6545 }
6546 xmlXPathReleaseObject(ctxt->context, arg);
6547 xmlXPathReleaseObject(ctxt->context, s);
6548 return(ret);
6549}
6550
6551/**
6552 * xmlXPathCompareNodeSets:
6553 * @inf: less than (1) or greater than (0)
6554 * @strict: is the comparison strict
6555 * @arg1: the first node set object
6556 * @arg2: the second node set object
6557 *
6558 * Implement the compare operation on nodesets:
6559 *
6560 * If both objects to be compared are node-sets, then the comparison
6561 * will be true if and only if there is a node in the first node-set
6562 * and a node in the second node-set such that the result of performing
6563 * the comparison on the string-values of the two nodes is true.
6564 * ....
6565 * When neither object to be compared is a node-set and the operator
6566 * is <=, <, >= or >, then the objects are compared by converting both
6567 * objects to numbers and comparing the numbers according to IEEE 754.
6568 * ....
6569 * The number function converts its argument to a number as follows:
6570 * - a string that consists of optional whitespace followed by an
6571 * optional minus sign followed by a Number followed by whitespace
6572 * is converted to the IEEE 754 number that is nearest (according
6573 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6574 * represented by the string; any other string is converted to NaN
6575 *
6576 * Conclusion all nodes need to be converted first to their string value
6577 * and then the comparison must be done when possible
6578 */
6579static int
6580xmlXPathCompareNodeSets(int inf, int strict,
6581 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6582 int i, j, init = 0;
6583 double val1;
6584 double *values2;
6585 int ret = 0;
6586 xmlNodeSetPtr ns1;
6587 xmlNodeSetPtr ns2;
6588
6589 if ((arg1 == NULL) ||
6590 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6591 xmlXPathFreeObject(arg2);
6592 return(0);
6593 }
6594 if ((arg2 == NULL) ||
6595 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6596 xmlXPathFreeObject(arg1);
6597 xmlXPathFreeObject(arg2);
6598 return(0);
6599 }
6600
6601 ns1 = arg1->nodesetval;
6602 ns2 = arg2->nodesetval;
6603
6604 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6605 xmlXPathFreeObject(arg1);
6606 xmlXPathFreeObject(arg2);
6607 return(0);
6608 }
6609 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6610 xmlXPathFreeObject(arg1);
6611 xmlXPathFreeObject(arg2);
6612 return(0);
6613 }
6614
6615 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6616 if (values2 == NULL) {
6617 /* TODO: Propagate memory error. */
6618 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6619 xmlXPathFreeObject(arg1);
6620 xmlXPathFreeObject(arg2);
6621 return(0);
6622 }
6623 for (i = 0;i < ns1->nodeNr;i++) {
6624 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6625 if (xmlXPathIsNaN(val1))
6626 continue;
6627 for (j = 0;j < ns2->nodeNr;j++) {
6628 if (init == 0) {
6629 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6630 }
6631 if (xmlXPathIsNaN(values2[j]))
6632 continue;
6633 if (inf && strict)
6634 ret = (val1 < values2[j]);
6635 else if (inf && !strict)
6636 ret = (val1 <= values2[j]);
6637 else if (!inf && strict)
6638 ret = (val1 > values2[j]);
6639 else if (!inf && !strict)
6640 ret = (val1 >= values2[j]);
6641 if (ret)
6642 break;
6643 }
6644 if (ret)
6645 break;
6646 init = 1;
6647 }
6648 xmlFree(values2);
6649 xmlXPathFreeObject(arg1);
6650 xmlXPathFreeObject(arg2);
6651 return(ret);
6652}
6653
6654/**
6655 * xmlXPathCompareNodeSetValue:
6656 * @ctxt: the XPath Parser context
6657 * @inf: less than (1) or greater than (0)
6658 * @strict: is the comparison strict
6659 * @arg: the node set
6660 * @val: the value
6661 *
6662 * Implement the compare operation between a nodeset and a value
6663 * @ns < @val (1, 1, ...
6664 * @ns <= @val (1, 0, ...
6665 * @ns > @val (0, 1, ...
6666 * @ns >= @val (0, 0, ...
6667 *
6668 * If one object to be compared is a node-set and the other is a boolean,
6669 * then the comparison will be true if and only if the result of performing
6670 * the comparison on the boolean and on the result of converting
6671 * the node-set to a boolean using the boolean function is true.
6672 *
6673 * Returns 0 or 1 depending on the results of the test.
6674 */
6675static int
6676xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6677 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6678 if ((val == NULL) || (arg == NULL) ||
6679 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6680 return(0);
6681
6682 switch(val->type) {
6683 case XPATH_NUMBER:
6684 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6685 case XPATH_NODESET:
6686 case XPATH_XSLT_TREE:
6687 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6688 case XPATH_STRING:
6689 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6690 case XPATH_BOOLEAN:
6691 valuePush(ctxt, arg);
6692 xmlXPathBooleanFunction(ctxt, 1);
6693 valuePush(ctxt, val);
6694 return(xmlXPathCompareValues(ctxt, inf, strict));
6695 default:
6696 xmlGenericError(xmlGenericErrorContext,
6697 "xmlXPathCompareNodeSetValue: Can't compare node set "
6698 "and object of type %d\n",
6699 val->type);
6700 xmlXPathReleaseObject(ctxt->context, arg);
6701 xmlXPathReleaseObject(ctxt->context, val);
6702 XP_ERROR0(XPATH_INVALID_TYPE);
6703 }
6704 return(0);
6705}
6706
6707/**
6708 * xmlXPathEqualNodeSetString:
6709 * @arg: the nodeset object argument
6710 * @str: the string to compare to.
6711 * @neq: flag to show whether for '=' (0) or '!=' (1)
6712 *
6713 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6714 * If one object to be compared is a node-set and the other is a string,
6715 * then the comparison will be true if and only if there is a node in
6716 * the node-set such that the result of performing the comparison on the
6717 * string-value of the node and the other string is true.
6718 *
6719 * Returns 0 or 1 depending on the results of the test.
6720 */
6721static int
6722xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6723{
6724 int i;
6725 xmlNodeSetPtr ns;
6726 xmlChar *str2;
6727 unsigned int hash;
6728
6729 if ((str == NULL) || (arg == NULL) ||
6730 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6731 return (0);
6732 ns = arg->nodesetval;
6733 /*
6734 * A NULL nodeset compared with a string is always false
6735 * (since there is no node equal, and no node not equal)
6736 */
6737 if ((ns == NULL) || (ns->nodeNr <= 0) )
6738 return (0);
6739 hash = xmlXPathStringHash(str);
6740 for (i = 0; i < ns->nodeNr; i++) {
6741 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6742 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6743 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6744 xmlFree(str2);
6745 if (neq)
6746 continue;
6747 return (1);
6748 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6749 if (neq)
6750 continue;
6751 return (1);
6752 } else if (neq) {
6753 if (str2 != NULL)
6754 xmlFree(str2);
6755 return (1);
6756 }
6757 if (str2 != NULL)
6758 xmlFree(str2);
6759 } else if (neq)
6760 return (1);
6761 }
6762 return (0);
6763}
6764
6765/**
6766 * xmlXPathEqualNodeSetFloat:
6767 * @arg: the nodeset object argument
6768 * @f: the float to compare to
6769 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6770 *
6771 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6772 * If one object to be compared is a node-set and the other is a number,
6773 * then the comparison will be true if and only if there is a node in
6774 * the node-set such that the result of performing the comparison on the
6775 * number to be compared and on the result of converting the string-value
6776 * of that node to a number using the number function is true.
6777 *
6778 * Returns 0 or 1 depending on the results of the test.
6779 */
6780static int
6781xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6782 xmlXPathObjectPtr arg, double f, int neq) {
6783 int i, ret=0;
6784 xmlNodeSetPtr ns;
6785 xmlChar *str2;
6786 xmlXPathObjectPtr val;
6787 double v;
6788
6789 if ((arg == NULL) ||
6790 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6791 return(0);
6792
6793 ns = arg->nodesetval;
6794 if (ns != NULL) {
6795 for (i=0;i<ns->nodeNr;i++) {
6796 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6797 if (str2 != NULL) {
6798 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6799 xmlFree(str2);
6800 xmlXPathNumberFunction(ctxt, 1);
6801 val = valuePop(ctxt);
6802 v = val->floatval;
6803 xmlXPathReleaseObject(ctxt->context, val);
6804 if (!xmlXPathIsNaN(v)) {
6805 if ((!neq) && (v==f)) {
6806 ret = 1;
6807 break;
6808 } else if ((neq) && (v!=f)) {
6809 ret = 1;
6810 break;
6811 }
6812 } else { /* NaN is unequal to any value */
6813 if (neq)
6814 ret = 1;
6815 }
6816 }
6817 }
6818 }
6819
6820 return(ret);
6821}
6822
6823
6824/**
6825 * xmlXPathEqualNodeSets:
6826 * @arg1: first nodeset object argument
6827 * @arg2: second nodeset object argument
6828 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6829 *
6830 * Implement the equal / not equal operation on XPath nodesets:
6831 * @arg1 == @arg2 or @arg1 != @arg2
6832 * If both objects to be compared are node-sets, then the comparison
6833 * will be true if and only if there is a node in the first node-set and
6834 * a node in the second node-set such that the result of performing the
6835 * comparison on the string-values of the two nodes is true.
6836 *
6837 * (needless to say, this is a costly operation)
6838 *
6839 * Returns 0 or 1 depending on the results of the test.
6840 */
6841static int
6842xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6843 int i, j;
6844 unsigned int *hashs1;
6845 unsigned int *hashs2;
6846 xmlChar **values1;
6847 xmlChar **values2;
6848 int ret = 0;
6849 xmlNodeSetPtr ns1;
6850 xmlNodeSetPtr ns2;
6851
6852 if ((arg1 == NULL) ||
6853 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6854 return(0);
6855 if ((arg2 == NULL) ||
6856 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6857 return(0);
6858
6859 ns1 = arg1->nodesetval;
6860 ns2 = arg2->nodesetval;
6861
6862 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6863 return(0);
6864 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6865 return(0);
6866
6867 /*
6868 * for equal, check if there is a node pertaining to both sets
6869 */
6870 if (neq == 0)
6871 for (i = 0;i < ns1->nodeNr;i++)
6872 for (j = 0;j < ns2->nodeNr;j++)
6873 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6874 return(1);
6875
6876 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6877 if (values1 == NULL) {
6878 /* TODO: Propagate memory error. */
6879 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6880 return(0);
6881 }
6882 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6883 if (hashs1 == NULL) {
6884 /* TODO: Propagate memory error. */
6885 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6886 xmlFree(values1);
6887 return(0);
6888 }
6889 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6890 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6891 if (values2 == NULL) {
6892 /* TODO: Propagate memory error. */
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 /* TODO: Propagate memory error. */
6901 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6902 xmlFree(hashs1);
6903 xmlFree(values1);
6904 xmlFree(values2);
6905 return(0);
6906 }
6907 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6908 for (i = 0;i < ns1->nodeNr;i++) {
6909 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6910 for (j = 0;j < ns2->nodeNr;j++) {
6911 if (i == 0)
6912 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6913 if (hashs1[i] != hashs2[j]) {
6914 if (neq) {
6915 ret = 1;
6916 break;
6917 }
6918 }
6919 else {
6920 if (values1[i] == NULL)
6921 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6922 if (values2[j] == NULL)
6923 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6924 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6925 if (ret)
6926 break;
6927 }
6928 }
6929 if (ret)
6930 break;
6931 }
6932 for (i = 0;i < ns1->nodeNr;i++)
6933 if (values1[i] != NULL)
6934 xmlFree(values1[i]);
6935 for (j = 0;j < ns2->nodeNr;j++)
6936 if (values2[j] != NULL)
6937 xmlFree(values2[j]);
6938 xmlFree(values1);
6939 xmlFree(values2);
6940 xmlFree(hashs1);
6941 xmlFree(hashs2);
6942 return(ret);
6943}
6944
6945static int
6946xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6947 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6948 int ret = 0;
6949 /*
6950 *At this point we are assured neither arg1 nor arg2
6951 *is a nodeset, so we can just pick the appropriate routine.
6952 */
6953 switch (arg1->type) {
6954 case XPATH_UNDEFINED:
6955#ifdef DEBUG_EXPR
6956 xmlGenericError(xmlGenericErrorContext,
6957 "Equal: undefined\n");
6958#endif
6959 break;
6960 case XPATH_BOOLEAN:
6961 switch (arg2->type) {
6962 case XPATH_UNDEFINED:
6963#ifdef DEBUG_EXPR
6964 xmlGenericError(xmlGenericErrorContext,
6965 "Equal: undefined\n");
6966#endif
6967 break;
6968 case XPATH_BOOLEAN:
6969#ifdef DEBUG_EXPR
6970 xmlGenericError(xmlGenericErrorContext,
6971 "Equal: %d boolean %d \n",
6972 arg1->boolval, arg2->boolval);
6973#endif
6974 ret = (arg1->boolval == arg2->boolval);
6975 break;
6976 case XPATH_NUMBER:
6977 ret = (arg1->boolval ==
6978 xmlXPathCastNumberToBoolean(arg2->floatval));
6979 break;
6980 case XPATH_STRING:
6981 if ((arg2->stringval == NULL) ||
6982 (arg2->stringval[0] == 0)) ret = 0;
6983 else
6984 ret = 1;
6985 ret = (arg1->boolval == ret);
6986 break;
6987 case XPATH_USERS:
6988 case XPATH_POINT:
6989 case XPATH_RANGE:
6990 case XPATH_LOCATIONSET:
6991 TODO
6992 break;
6993 case XPATH_NODESET:
6994 case XPATH_XSLT_TREE:
6995 break;
6996 }
6997 break;
6998 case XPATH_NUMBER:
6999 switch (arg2->type) {
7000 case XPATH_UNDEFINED:
7001#ifdef DEBUG_EXPR
7002 xmlGenericError(xmlGenericErrorContext,
7003 "Equal: undefined\n");
7004#endif
7005 break;
7006 case XPATH_BOOLEAN:
7007 ret = (arg2->boolval==
7008 xmlXPathCastNumberToBoolean(arg1->floatval));
7009 break;
7010 case XPATH_STRING:
7011 valuePush(ctxt, arg2);
7012 xmlXPathNumberFunction(ctxt, 1);
7013 arg2 = valuePop(ctxt);
7014 /* Falls through. */
7015 case XPATH_NUMBER:
7016 /* Hand check NaN and Infinity equalities */
7017 if (xmlXPathIsNaN(arg1->floatval) ||
7018 xmlXPathIsNaN(arg2->floatval)) {
7019 ret = 0;
7020 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7021 if (xmlXPathIsInf(arg2->floatval) == 1)
7022 ret = 1;
7023 else
7024 ret = 0;
7025 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7026 if (xmlXPathIsInf(arg2->floatval) == -1)
7027 ret = 1;
7028 else
7029 ret = 0;
7030 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7031 if (xmlXPathIsInf(arg1->floatval) == 1)
7032 ret = 1;
7033 else
7034 ret = 0;
7035 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7036 if (xmlXPathIsInf(arg1->floatval) == -1)
7037 ret = 1;
7038 else
7039 ret = 0;
7040 } else {
7041 ret = (arg1->floatval == arg2->floatval);
7042 }
7043 break;
7044 case XPATH_USERS:
7045 case XPATH_POINT:
7046 case XPATH_RANGE:
7047 case XPATH_LOCATIONSET:
7048 TODO
7049 break;
7050 case XPATH_NODESET:
7051 case XPATH_XSLT_TREE:
7052 break;
7053 }
7054 break;
7055 case XPATH_STRING:
7056 switch (arg2->type) {
7057 case XPATH_UNDEFINED:
7058#ifdef DEBUG_EXPR
7059 xmlGenericError(xmlGenericErrorContext,
7060 "Equal: undefined\n");
7061#endif
7062 break;
7063 case XPATH_BOOLEAN:
7064 if ((arg1->stringval == NULL) ||
7065 (arg1->stringval[0] == 0)) ret = 0;
7066 else
7067 ret = 1;
7068 ret = (arg2->boolval == ret);
7069 break;
7070 case XPATH_STRING:
7071 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7072 break;
7073 case XPATH_NUMBER:
7074 valuePush(ctxt, arg1);
7075 xmlXPathNumberFunction(ctxt, 1);
7076 arg1 = valuePop(ctxt);
7077 /* Hand check NaN and Infinity equalities */
7078 if (xmlXPathIsNaN(arg1->floatval) ||
7079 xmlXPathIsNaN(arg2->floatval)) {
7080 ret = 0;
7081 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7082 if (xmlXPathIsInf(arg2->floatval) == 1)
7083 ret = 1;
7084 else
7085 ret = 0;
7086 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7087 if (xmlXPathIsInf(arg2->floatval) == -1)
7088 ret = 1;
7089 else
7090 ret = 0;
7091 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7092 if (xmlXPathIsInf(arg1->floatval) == 1)
7093 ret = 1;
7094 else
7095 ret = 0;
7096 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7097 if (xmlXPathIsInf(arg1->floatval) == -1)
7098 ret = 1;
7099 else
7100 ret = 0;
7101 } else {
7102 ret = (arg1->floatval == arg2->floatval);
7103 }
7104 break;
7105 case XPATH_USERS:
7106 case XPATH_POINT:
7107 case XPATH_RANGE:
7108 case XPATH_LOCATIONSET:
7109 TODO
7110 break;
7111 case XPATH_NODESET:
7112 case XPATH_XSLT_TREE:
7113 break;
7114 }
7115 break;
7116 case XPATH_USERS:
7117 case XPATH_POINT:
7118 case XPATH_RANGE:
7119 case XPATH_LOCATIONSET:
7120 TODO
7121 break;
7122 case XPATH_NODESET:
7123 case XPATH_XSLT_TREE:
7124 break;
7125 }
7126 xmlXPathReleaseObject(ctxt->context, arg1);
7127 xmlXPathReleaseObject(ctxt->context, arg2);
7128 return(ret);
7129}
7130
7131/**
7132 * xmlXPathEqualValues:
7133 * @ctxt: the XPath Parser context
7134 *
7135 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7136 *
7137 * Returns 0 or 1 depending on the results of the test.
7138 */
7139int
7140xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7141 xmlXPathObjectPtr arg1, arg2, argtmp;
7142 int ret = 0;
7143
7144 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7145 arg2 = valuePop(ctxt);
7146 arg1 = valuePop(ctxt);
7147 if ((arg1 == NULL) || (arg2 == NULL)) {
7148 if (arg1 != NULL)
7149 xmlXPathReleaseObject(ctxt->context, arg1);
7150 else
7151 xmlXPathReleaseObject(ctxt->context, arg2);
7152 XP_ERROR0(XPATH_INVALID_OPERAND);
7153 }
7154
7155 if (arg1 == arg2) {
7156#ifdef DEBUG_EXPR
7157 xmlGenericError(xmlGenericErrorContext,
7158 "Equal: by pointer\n");
7159#endif
7160 xmlXPathFreeObject(arg1);
7161 return(1);
7162 }
7163
7164 /*
7165 *If either argument is a nodeset, it's a 'special case'
7166 */
7167 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7168 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7169 /*
7170 *Hack it to assure arg1 is the nodeset
7171 */
7172 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7173 argtmp = arg2;
7174 arg2 = arg1;
7175 arg1 = argtmp;
7176 }
7177 switch (arg2->type) {
7178 case XPATH_UNDEFINED:
7179#ifdef DEBUG_EXPR
7180 xmlGenericError(xmlGenericErrorContext,
7181 "Equal: undefined\n");
7182#endif
7183 break;
7184 case XPATH_NODESET:
7185 case XPATH_XSLT_TREE:
7186 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7187 break;
7188 case XPATH_BOOLEAN:
7189 if ((arg1->nodesetval == NULL) ||
7190 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7191 else
7192 ret = 1;
7193 ret = (ret == arg2->boolval);
7194 break;
7195 case XPATH_NUMBER:
7196 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7197 break;
7198 case XPATH_STRING:
7199 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7200 break;
7201 case XPATH_USERS:
7202 case XPATH_POINT:
7203 case XPATH_RANGE:
7204 case XPATH_LOCATIONSET:
7205 TODO
7206 break;
7207 }
7208 xmlXPathReleaseObject(ctxt->context, arg1);
7209 xmlXPathReleaseObject(ctxt->context, arg2);
7210 return(ret);
7211 }
7212
7213 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7214}
7215
7216/**
7217 * xmlXPathNotEqualValues:
7218 * @ctxt: the XPath Parser context
7219 *
7220 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7221 *
7222 * Returns 0 or 1 depending on the results of the test.
7223 */
7224int
7225xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7226 xmlXPathObjectPtr arg1, arg2, argtmp;
7227 int ret = 0;
7228
7229 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7230 arg2 = valuePop(ctxt);
7231 arg1 = valuePop(ctxt);
7232 if ((arg1 == NULL) || (arg2 == NULL)) {
7233 if (arg1 != NULL)
7234 xmlXPathReleaseObject(ctxt->context, arg1);
7235 else
7236 xmlXPathReleaseObject(ctxt->context, arg2);
7237 XP_ERROR0(XPATH_INVALID_OPERAND);
7238 }
7239
7240 if (arg1 == arg2) {
7241#ifdef DEBUG_EXPR
7242 xmlGenericError(xmlGenericErrorContext,
7243 "NotEqual: by pointer\n");
7244#endif
7245 xmlXPathReleaseObject(ctxt->context, arg1);
7246 return(0);
7247 }
7248
7249 /*
7250 *If either argument is a nodeset, it's a 'special case'
7251 */
7252 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7253 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7254 /*
7255 *Hack it to assure arg1 is the nodeset
7256 */
7257 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7258 argtmp = arg2;
7259 arg2 = arg1;
7260 arg1 = argtmp;
7261 }
7262 switch (arg2->type) {
7263 case XPATH_UNDEFINED:
7264#ifdef DEBUG_EXPR
7265 xmlGenericError(xmlGenericErrorContext,
7266 "NotEqual: undefined\n");
7267#endif
7268 break;
7269 case XPATH_NODESET:
7270 case XPATH_XSLT_TREE:
7271 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7272 break;
7273 case XPATH_BOOLEAN:
7274 if ((arg1->nodesetval == NULL) ||
7275 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7276 else
7277 ret = 1;
7278 ret = (ret != arg2->boolval);
7279 break;
7280 case XPATH_NUMBER:
7281 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7282 break;
7283 case XPATH_STRING:
7284 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7285 break;
7286 case XPATH_USERS:
7287 case XPATH_POINT:
7288 case XPATH_RANGE:
7289 case XPATH_LOCATIONSET:
7290 TODO
7291 break;
7292 }
7293 xmlXPathReleaseObject(ctxt->context, arg1);
7294 xmlXPathReleaseObject(ctxt->context, arg2);
7295 return(ret);
7296 }
7297
7298 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7299}
7300
7301/**
7302 * xmlXPathCompareValues:
7303 * @ctxt: the XPath Parser context
7304 * @inf: less than (1) or greater than (0)
7305 * @strict: is the comparison strict
7306 *
7307 * Implement the compare operation on XPath objects:
7308 * @arg1 < @arg2 (1, 1, ...
7309 * @arg1 <= @arg2 (1, 0, ...
7310 * @arg1 > @arg2 (0, 1, ...
7311 * @arg1 >= @arg2 (0, 0, ...
7312 *
7313 * When neither object to be compared is a node-set and the operator is
7314 * <=, <, >=, >, then the objects are compared by converted both objects
7315 * to numbers and comparing the numbers according to IEEE 754. The <
7316 * comparison will be true if and only if the first number is less than the
7317 * second number. The <= comparison will be true if and only if the first
7318 * number is less than or equal to the second number. The > comparison
7319 * will be true if and only if the first number is greater than the second
7320 * number. The >= comparison will be true if and only if the first number
7321 * is greater than or equal to the second number.
7322 *
7323 * Returns 1 if the comparison succeeded, 0 if it failed
7324 */
7325int
7326xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7327 int ret = 0, arg1i = 0, arg2i = 0;
7328 xmlXPathObjectPtr arg1, arg2;
7329
7330 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7331 arg2 = valuePop(ctxt);
7332 arg1 = valuePop(ctxt);
7333 if ((arg1 == NULL) || (arg2 == NULL)) {
7334 if (arg1 != NULL)
7335 xmlXPathReleaseObject(ctxt->context, arg1);
7336 else
7337 xmlXPathReleaseObject(ctxt->context, arg2);
7338 XP_ERROR0(XPATH_INVALID_OPERAND);
7339 }
7340
7341 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7342 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7343 /*
7344 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7345 * are not freed from within this routine; they will be freed from the
7346 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7347 */
7348 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7349 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7350 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7351 } else {
7352 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7353 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7354 arg1, arg2);
7355 } else {
7356 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7357 arg2, arg1);
7358 }
7359 }
7360 return(ret);
7361 }
7362
7363 if (arg1->type != XPATH_NUMBER) {
7364 valuePush(ctxt, arg1);
7365 xmlXPathNumberFunction(ctxt, 1);
7366 arg1 = valuePop(ctxt);
7367 }
7368 if (arg1->type != XPATH_NUMBER) {
7369 xmlXPathFreeObject(arg1);
7370 xmlXPathFreeObject(arg2);
7371 XP_ERROR0(XPATH_INVALID_OPERAND);
7372 }
7373 if (arg2->type != XPATH_NUMBER) {
7374 valuePush(ctxt, arg2);
7375 xmlXPathNumberFunction(ctxt, 1);
7376 arg2 = valuePop(ctxt);
7377 }
7378 if (arg2->type != XPATH_NUMBER) {
7379 xmlXPathReleaseObject(ctxt->context, arg1);
7380 xmlXPathReleaseObject(ctxt->context, arg2);
7381 XP_ERROR0(XPATH_INVALID_OPERAND);
7382 }
7383 /*
7384 * Add tests for infinity and nan
7385 * => feedback on 3.4 for Inf and NaN
7386 */
7387 /* Hand check NaN and Infinity comparisons */
7388 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7389 ret=0;
7390 } else {
7391 arg1i=xmlXPathIsInf(arg1->floatval);
7392 arg2i=xmlXPathIsInf(arg2->floatval);
7393 if (inf && strict) {
7394 if ((arg1i == -1 && arg2i != -1) ||
7395 (arg2i == 1 && arg1i != 1)) {
7396 ret = 1;
7397 } else if (arg1i == 0 && arg2i == 0) {
7398 ret = (arg1->floatval < arg2->floatval);
7399 } else {
7400 ret = 0;
7401 }
7402 }
7403 else if (inf && !strict) {
7404 if (arg1i == -1 || arg2i == 1) {
7405 ret = 1;
7406 } else if (arg1i == 0 && arg2i == 0) {
7407 ret = (arg1->floatval <= arg2->floatval);
7408 } else {
7409 ret = 0;
7410 }
7411 }
7412 else if (!inf && strict) {
7413 if ((arg1i == 1 && arg2i != 1) ||
7414 (arg2i == -1 && arg1i != -1)) {
7415 ret = 1;
7416 } else if (arg1i == 0 && arg2i == 0) {
7417 ret = (arg1->floatval > arg2->floatval);
7418 } else {
7419 ret = 0;
7420 }
7421 }
7422 else if (!inf && !strict) {
7423 if (arg1i == 1 || arg2i == -1) {
7424 ret = 1;
7425 } else if (arg1i == 0 && arg2i == 0) {
7426 ret = (arg1->floatval >= arg2->floatval);
7427 } else {
7428 ret = 0;
7429 }
7430 }
7431 }
7432 xmlXPathReleaseObject(ctxt->context, arg1);
7433 xmlXPathReleaseObject(ctxt->context, arg2);
7434 return(ret);
7435}
7436
7437/**
7438 * xmlXPathValueFlipSign:
7439 * @ctxt: the XPath Parser context
7440 *
7441 * Implement the unary - operation on an XPath object
7442 * The numeric operators convert their operands to numbers as if
7443 * by calling the number function.
7444 */
7445void
7446xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7447 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7448 CAST_TO_NUMBER;
7449 CHECK_TYPE(XPATH_NUMBER);
7450 ctxt->value->floatval = -ctxt->value->floatval;
7451}
7452
7453/**
7454 * xmlXPathAddValues:
7455 * @ctxt: the XPath Parser context
7456 *
7457 * Implement the add operation on XPath objects:
7458 * The numeric operators convert their operands to numbers as if
7459 * by calling the number function.
7460 */
7461void
7462xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7463 xmlXPathObjectPtr arg;
7464 double val;
7465
7466 arg = valuePop(ctxt);
7467 if (arg == NULL)
7468 XP_ERROR(XPATH_INVALID_OPERAND);
7469 val = xmlXPathCastToNumber(arg);
7470 xmlXPathReleaseObject(ctxt->context, arg);
7471 CAST_TO_NUMBER;
7472 CHECK_TYPE(XPATH_NUMBER);
7473 ctxt->value->floatval += val;
7474}
7475
7476/**
7477 * xmlXPathSubValues:
7478 * @ctxt: the XPath Parser context
7479 *
7480 * Implement the subtraction operation on XPath objects:
7481 * The numeric operators convert their operands to numbers as if
7482 * by calling the number function.
7483 */
7484void
7485xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7486 xmlXPathObjectPtr arg;
7487 double val;
7488
7489 arg = valuePop(ctxt);
7490 if (arg == NULL)
7491 XP_ERROR(XPATH_INVALID_OPERAND);
7492 val = xmlXPathCastToNumber(arg);
7493 xmlXPathReleaseObject(ctxt->context, arg);
7494 CAST_TO_NUMBER;
7495 CHECK_TYPE(XPATH_NUMBER);
7496 ctxt->value->floatval -= val;
7497}
7498
7499/**
7500 * xmlXPathMultValues:
7501 * @ctxt: the XPath Parser context
7502 *
7503 * Implement the multiply operation on XPath objects:
7504 * The numeric operators convert their operands to numbers as if
7505 * by calling the number function.
7506 */
7507void
7508xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7509 xmlXPathObjectPtr arg;
7510 double val;
7511
7512 arg = valuePop(ctxt);
7513 if (arg == NULL)
7514 XP_ERROR(XPATH_INVALID_OPERAND);
7515 val = xmlXPathCastToNumber(arg);
7516 xmlXPathReleaseObject(ctxt->context, arg);
7517 CAST_TO_NUMBER;
7518 CHECK_TYPE(XPATH_NUMBER);
7519 ctxt->value->floatval *= val;
7520}
7521
7522/**
7523 * xmlXPathDivValues:
7524 * @ctxt: the XPath Parser context
7525 *
7526 * Implement the div operation on XPath objects @arg1 / @arg2:
7527 * The numeric operators convert their operands to numbers as if
7528 * by calling the number function.
7529 */
7530ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7531void
7532xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7533 xmlXPathObjectPtr arg;
7534 double val;
7535
7536 arg = valuePop(ctxt);
7537 if (arg == NULL)
7538 XP_ERROR(XPATH_INVALID_OPERAND);
7539 val = xmlXPathCastToNumber(arg);
7540 xmlXPathReleaseObject(ctxt->context, arg);
7541 CAST_TO_NUMBER;
7542 CHECK_TYPE(XPATH_NUMBER);
7543 ctxt->value->floatval /= val;
7544}
7545
7546/**
7547 * xmlXPathModValues:
7548 * @ctxt: the XPath Parser context
7549 *
7550 * Implement the mod operation on XPath objects: @arg1 / @arg2
7551 * The numeric operators convert their operands to numbers as if
7552 * by calling the number function.
7553 */
7554void
7555xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7556 xmlXPathObjectPtr arg;
7557 double arg1, arg2;
7558
7559 arg = valuePop(ctxt);
7560 if (arg == NULL)
7561 XP_ERROR(XPATH_INVALID_OPERAND);
7562 arg2 = xmlXPathCastToNumber(arg);
7563 xmlXPathReleaseObject(ctxt->context, arg);
7564 CAST_TO_NUMBER;
7565 CHECK_TYPE(XPATH_NUMBER);
7566 arg1 = ctxt->value->floatval;
7567 if (arg2 == 0)
7568 ctxt->value->floatval = xmlXPathNAN;
7569 else {
7570 ctxt->value->floatval = fmod(arg1, arg2);
7571 }
7572}
7573
7574/************************************************************************
7575 * *
7576 * The traversal functions *
7577 * *
7578 ************************************************************************/
7579
7580/*
7581 * A traversal function enumerates nodes along an axis.
7582 * Initially it must be called with NULL, and it indicates
7583 * termination on the axis by returning NULL.
7584 */
7585typedef xmlNodePtr (*xmlXPathTraversalFunction)
7586 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7587
7588/*
7589 * xmlXPathTraversalFunctionExt:
7590 * A traversal function enumerates nodes along an axis.
7591 * Initially it must be called with NULL, and it indicates
7592 * termination on the axis by returning NULL.
7593 * The context node of the traversal is specified via @contextNode.
7594 */
7595typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7596 (xmlNodePtr cur, xmlNodePtr contextNode);
7597
7598/*
7599 * xmlXPathNodeSetMergeFunction:
7600 * Used for merging node sets in xmlXPathCollectAndTest().
7601 */
7602typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7603 (xmlNodeSetPtr, xmlNodeSetPtr);
7604
7605
7606/**
7607 * xmlXPathNextSelf:
7608 * @ctxt: the XPath Parser context
7609 * @cur: the current node in the traversal
7610 *
7611 * Traversal function for the "self" direction
7612 * The self axis contains just the context node itself
7613 *
7614 * Returns the next element following that axis
7615 */
7616xmlNodePtr
7617xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7618 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7619 if (cur == NULL)
7620 return(ctxt->context->node);
7621 return(NULL);
7622}
7623
7624/**
7625 * xmlXPathNextChild:
7626 * @ctxt: the XPath Parser context
7627 * @cur: the current node in the traversal
7628 *
7629 * Traversal function for the "child" direction
7630 * The child axis contains the children of the context node in document order.
7631 *
7632 * Returns the next element following that axis
7633 */
7634xmlNodePtr
7635xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7636 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7637 if (cur == NULL) {
7638 if (ctxt->context->node == NULL) return(NULL);
7639 switch (ctxt->context->node->type) {
7640 case XML_ELEMENT_NODE:
7641 case XML_TEXT_NODE:
7642 case XML_CDATA_SECTION_NODE:
7643 case XML_ENTITY_REF_NODE:
7644 case XML_ENTITY_NODE:
7645 case XML_PI_NODE:
7646 case XML_COMMENT_NODE:
7647 case XML_NOTATION_NODE:
7648 case XML_DTD_NODE:
7649 return(ctxt->context->node->children);
7650 case XML_DOCUMENT_NODE:
7651 case XML_DOCUMENT_TYPE_NODE:
7652 case XML_DOCUMENT_FRAG_NODE:
7653 case XML_HTML_DOCUMENT_NODE:
7654#ifdef LIBXML_DOCB_ENABLED
7655 case XML_DOCB_DOCUMENT_NODE:
7656#endif
7657 return(((xmlDocPtr) ctxt->context->node)->children);
7658 case XML_ELEMENT_DECL:
7659 case XML_ATTRIBUTE_DECL:
7660 case XML_ENTITY_DECL:
7661 case XML_ATTRIBUTE_NODE:
7662 case XML_NAMESPACE_DECL:
7663 case XML_XINCLUDE_START:
7664 case XML_XINCLUDE_END:
7665 return(NULL);
7666 }
7667 return(NULL);
7668 }
7669 if ((cur->type == XML_DOCUMENT_NODE) ||
7670 (cur->type == XML_HTML_DOCUMENT_NODE))
7671 return(NULL);
7672 return(cur->next);
7673}
7674
7675/**
7676 * xmlXPathNextChildElement:
7677 * @ctxt: the XPath Parser context
7678 * @cur: the current node in the traversal
7679 *
7680 * Traversal function for the "child" direction and nodes of type element.
7681 * The child axis contains the children of the context node in document order.
7682 *
7683 * Returns the next element following that axis
7684 */
7685static xmlNodePtr
7686xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7687 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7688 if (cur == NULL) {
7689 cur = ctxt->context->node;
7690 if (cur == NULL) return(NULL);
7691 /*
7692 * Get the first element child.
7693 */
7694 switch (cur->type) {
7695 case XML_ELEMENT_NODE:
7696 case XML_DOCUMENT_FRAG_NODE:
7697 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7698 case XML_ENTITY_NODE:
7699 cur = cur->children;
7700 if (cur != NULL) {
7701 if (cur->type == XML_ELEMENT_NODE)
7702 return(cur);
7703 do {
7704 cur = cur->next;
7705 } while ((cur != NULL) &&
7706 (cur->type != XML_ELEMENT_NODE));
7707 return(cur);
7708 }
7709 return(NULL);
7710 case XML_DOCUMENT_NODE:
7711 case XML_HTML_DOCUMENT_NODE:
7712#ifdef LIBXML_DOCB_ENABLED
7713 case XML_DOCB_DOCUMENT_NODE:
7714#endif
7715 return(xmlDocGetRootElement((xmlDocPtr) cur));
7716 default:
7717 return(NULL);
7718 }
7719 return(NULL);
7720 }
7721 /*
7722 * Get the next sibling element node.
7723 */
7724 switch (cur->type) {
7725 case XML_ELEMENT_NODE:
7726 case XML_TEXT_NODE:
7727 case XML_ENTITY_REF_NODE:
7728 case XML_ENTITY_NODE:
7729 case XML_CDATA_SECTION_NODE:
7730 case XML_PI_NODE:
7731 case XML_COMMENT_NODE:
7732 case XML_XINCLUDE_END:
7733 break;
7734 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7735 default:
7736 return(NULL);
7737 }
7738 if (cur->next != NULL) {
7739 if (cur->next->type == XML_ELEMENT_NODE)
7740 return(cur->next);
7741 cur = cur->next;
7742 do {
7743 cur = cur->next;
7744 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7745 return(cur);
7746 }
7747 return(NULL);
7748}
7749
7750#if 0
7751/**
7752 * xmlXPathNextDescendantOrSelfElemParent:
7753 * @ctxt: the XPath Parser context
7754 * @cur: the current node in the traversal
7755 *
7756 * Traversal function for the "descendant-or-self" axis.
7757 * Additionally it returns only nodes which can be parents of
7758 * element nodes.
7759 *
7760 *
7761 * Returns the next element following that axis
7762 */
7763static xmlNodePtr
7764xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7765 xmlNodePtr contextNode)
7766{
7767 if (cur == NULL) {
7768 if (contextNode == NULL)
7769 return(NULL);
7770 switch (contextNode->type) {
7771 case XML_ELEMENT_NODE:
7772 case XML_XINCLUDE_START:
7773 case XML_DOCUMENT_FRAG_NODE:
7774 case XML_DOCUMENT_NODE:
7775#ifdef LIBXML_DOCB_ENABLED
7776 case XML_DOCB_DOCUMENT_NODE:
7777#endif
7778 case XML_HTML_DOCUMENT_NODE:
7779 return(contextNode);
7780 default:
7781 return(NULL);
7782 }
7783 return(NULL);
7784 } else {
7785 xmlNodePtr start = cur;
7786
7787 while (cur != NULL) {
7788 switch (cur->type) {
7789 case XML_ELEMENT_NODE:
7790 /* TODO: OK to have XInclude here? */
7791 case XML_XINCLUDE_START:
7792 case XML_DOCUMENT_FRAG_NODE:
7793 if (cur != start)
7794 return(cur);
7795 if (cur->children != NULL) {
7796 cur = cur->children;
7797 continue;
7798 }
7799 break;
7800 /* Not sure if we need those here. */
7801 case XML_DOCUMENT_NODE:
7802#ifdef LIBXML_DOCB_ENABLED
7803 case XML_DOCB_DOCUMENT_NODE:
7804#endif
7805 case XML_HTML_DOCUMENT_NODE:
7806 if (cur != start)
7807 return(cur);
7808 return(xmlDocGetRootElement((xmlDocPtr) cur));
7809 default:
7810 break;
7811 }
7812
7813next_sibling:
7814 if ((cur == NULL) || (cur == contextNode))
7815 return(NULL);
7816 if (cur->next != NULL) {
7817 cur = cur->next;
7818 } else {
7819 cur = cur->parent;
7820 goto next_sibling;
7821 }
7822 }
7823 }
7824 return(NULL);
7825}
7826#endif
7827
7828/**
7829 * xmlXPathNextDescendant:
7830 * @ctxt: the XPath Parser context
7831 * @cur: the current node in the traversal
7832 *
7833 * Traversal function for the "descendant" direction
7834 * the descendant axis contains the descendants of the context node in document
7835 * order; a descendant is a child or a child of a child and so on.
7836 *
7837 * Returns the next element following that axis
7838 */
7839xmlNodePtr
7840xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7841 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7842 if (cur == NULL) {
7843 if (ctxt->context->node == NULL)
7844 return(NULL);
7845 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7846 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7847 return(NULL);
7848
7849 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7850 return(ctxt->context->doc->children);
7851 return(ctxt->context->node->children);
7852 }
7853
7854 if (cur->type == XML_NAMESPACE_DECL)
7855 return(NULL);
7856 if (cur->children != NULL) {
7857 /*
7858 * Do not descend on entities declarations
7859 */
7860 if (cur->children->type != XML_ENTITY_DECL) {
7861 cur = cur->children;
7862 /*
7863 * Skip DTDs
7864 */
7865 if (cur->type != XML_DTD_NODE)
7866 return(cur);
7867 }
7868 }
7869
7870 if (cur == ctxt->context->node) return(NULL);
7871
7872 while (cur->next != NULL) {
7873 cur = cur->next;
7874 if ((cur->type != XML_ENTITY_DECL) &&
7875 (cur->type != XML_DTD_NODE))
7876 return(cur);
7877 }
7878
7879 do {
7880 cur = cur->parent;
7881 if (cur == NULL) break;
7882 if (cur == ctxt->context->node) return(NULL);
7883 if (cur->next != NULL) {
7884 cur = cur->next;
7885 return(cur);
7886 }
7887 } while (cur != NULL);
7888 return(cur);
7889}
7890
7891/**
7892 * xmlXPathNextDescendantOrSelf:
7893 * @ctxt: the XPath Parser context
7894 * @cur: the current node in the traversal
7895 *
7896 * Traversal function for the "descendant-or-self" direction
7897 * the descendant-or-self axis contains the context node and the descendants
7898 * of the context node in document order; thus the context node is the first
7899 * node on the axis, and the first child of the context node is the second node
7900 * on the axis
7901 *
7902 * Returns the next element following that axis
7903 */
7904xmlNodePtr
7905xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7906 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7907 if (cur == NULL)
7908 return(ctxt->context->node);
7909
7910 if (ctxt->context->node == NULL)
7911 return(NULL);
7912 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7913 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7914 return(NULL);
7915
7916 return(xmlXPathNextDescendant(ctxt, cur));
7917}
7918
7919/**
7920 * xmlXPathNextParent:
7921 * @ctxt: the XPath Parser context
7922 * @cur: the current node in the traversal
7923 *
7924 * Traversal function for the "parent" direction
7925 * The parent axis contains the parent of the context node, if there is one.
7926 *
7927 * Returns the next element following that axis
7928 */
7929xmlNodePtr
7930xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7931 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7932 /*
7933 * the parent of an attribute or namespace node is the element
7934 * to which the attribute or namespace node is attached
7935 * Namespace handling !!!
7936 */
7937 if (cur == NULL) {
7938 if (ctxt->context->node == NULL) return(NULL);
7939 switch (ctxt->context->node->type) {
7940 case XML_ELEMENT_NODE:
7941 case XML_TEXT_NODE:
7942 case XML_CDATA_SECTION_NODE:
7943 case XML_ENTITY_REF_NODE:
7944 case XML_ENTITY_NODE:
7945 case XML_PI_NODE:
7946 case XML_COMMENT_NODE:
7947 case XML_NOTATION_NODE:
7948 case XML_DTD_NODE:
7949 case XML_ELEMENT_DECL:
7950 case XML_ATTRIBUTE_DECL:
7951 case XML_XINCLUDE_START:
7952 case XML_XINCLUDE_END:
7953 case XML_ENTITY_DECL:
7954 if (ctxt->context->node->parent == NULL)
7955 return((xmlNodePtr) ctxt->context->doc);
7956 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7957 ((ctxt->context->node->parent->name[0] == ' ') ||
7958 (xmlStrEqual(ctxt->context->node->parent->name,
7959 BAD_CAST "fake node libxslt"))))
7960 return(NULL);
7961 return(ctxt->context->node->parent);
7962 case XML_ATTRIBUTE_NODE: {
7963 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7964
7965 return(att->parent);
7966 }
7967 case XML_DOCUMENT_NODE:
7968 case XML_DOCUMENT_TYPE_NODE:
7969 case XML_DOCUMENT_FRAG_NODE:
7970 case XML_HTML_DOCUMENT_NODE:
7971#ifdef LIBXML_DOCB_ENABLED
7972 case XML_DOCB_DOCUMENT_NODE:
7973#endif
7974 return(NULL);
7975 case XML_NAMESPACE_DECL: {
7976 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7977
7978 if ((ns->next != NULL) &&
7979 (ns->next->type != XML_NAMESPACE_DECL))
7980 return((xmlNodePtr) ns->next);
7981 return(NULL);
7982 }
7983 }
7984 }
7985 return(NULL);
7986}
7987
7988/**
7989 * xmlXPathNextAncestor:
7990 * @ctxt: the XPath Parser context
7991 * @cur: the current node in the traversal
7992 *
7993 * Traversal function for the "ancestor" direction
7994 * the ancestor axis contains the ancestors of the context node; the ancestors
7995 * of the context node consist of the parent of context node and the parent's
7996 * parent and so on; the nodes are ordered in reverse document order; thus the
7997 * parent is the first node on the axis, and the parent's parent is the second
7998 * node on the axis
7999 *
8000 * Returns the next element following that axis
8001 */
8002xmlNodePtr
8003xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8004 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8005 /*
8006 * the parent of an attribute or namespace node is the element
8007 * to which the attribute or namespace node is attached
8008 * !!!!!!!!!!!!!
8009 */
8010 if (cur == NULL) {
8011 if (ctxt->context->node == NULL) return(NULL);
8012 switch (ctxt->context->node->type) {
8013 case XML_ELEMENT_NODE:
8014 case XML_TEXT_NODE:
8015 case XML_CDATA_SECTION_NODE:
8016 case XML_ENTITY_REF_NODE:
8017 case XML_ENTITY_NODE:
8018 case XML_PI_NODE:
8019 case XML_COMMENT_NODE:
8020 case XML_DTD_NODE:
8021 case XML_ELEMENT_DECL:
8022 case XML_ATTRIBUTE_DECL:
8023 case XML_ENTITY_DECL:
8024 case XML_NOTATION_NODE:
8025 case XML_XINCLUDE_START:
8026 case XML_XINCLUDE_END:
8027 if (ctxt->context->node->parent == NULL)
8028 return((xmlNodePtr) ctxt->context->doc);
8029 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8030 ((ctxt->context->node->parent->name[0] == ' ') ||
8031 (xmlStrEqual(ctxt->context->node->parent->name,
8032 BAD_CAST "fake node libxslt"))))
8033 return(NULL);
8034 return(ctxt->context->node->parent);
8035 case XML_ATTRIBUTE_NODE: {
8036 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8037
8038 return(tmp->parent);
8039 }
8040 case XML_DOCUMENT_NODE:
8041 case XML_DOCUMENT_TYPE_NODE:
8042 case XML_DOCUMENT_FRAG_NODE:
8043 case XML_HTML_DOCUMENT_NODE:
8044#ifdef LIBXML_DOCB_ENABLED
8045 case XML_DOCB_DOCUMENT_NODE:
8046#endif
8047 return(NULL);
8048 case XML_NAMESPACE_DECL: {
8049 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8050
8051 if ((ns->next != NULL) &&
8052 (ns->next->type != XML_NAMESPACE_DECL))
8053 return((xmlNodePtr) ns->next);
8054 /* Bad, how did that namespace end up here ? */
8055 return(NULL);
8056 }
8057 }
8058 return(NULL);
8059 }
8060 if (cur == ctxt->context->doc->children)
8061 return((xmlNodePtr) ctxt->context->doc);
8062 if (cur == (xmlNodePtr) ctxt->context->doc)
8063 return(NULL);
8064 switch (cur->type) {
8065 case XML_ELEMENT_NODE:
8066 case XML_TEXT_NODE:
8067 case XML_CDATA_SECTION_NODE:
8068 case XML_ENTITY_REF_NODE:
8069 case XML_ENTITY_NODE:
8070 case XML_PI_NODE:
8071 case XML_COMMENT_NODE:
8072 case XML_NOTATION_NODE:
8073 case XML_DTD_NODE:
8074 case XML_ELEMENT_DECL:
8075 case XML_ATTRIBUTE_DECL:
8076 case XML_ENTITY_DECL:
8077 case XML_XINCLUDE_START:
8078 case XML_XINCLUDE_END:
8079 if (cur->parent == NULL)
8080 return(NULL);
8081 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8082 ((cur->parent->name[0] == ' ') ||
8083 (xmlStrEqual(cur->parent->name,
8084 BAD_CAST "fake node libxslt"))))
8085 return(NULL);
8086 return(cur->parent);
8087 case XML_ATTRIBUTE_NODE: {
8088 xmlAttrPtr att = (xmlAttrPtr) cur;
8089
8090 return(att->parent);
8091 }
8092 case XML_NAMESPACE_DECL: {
8093 xmlNsPtr ns = (xmlNsPtr) cur;
8094
8095 if ((ns->next != NULL) &&
8096 (ns->next->type != XML_NAMESPACE_DECL))
8097 return((xmlNodePtr) ns->next);
8098 /* Bad, how did that namespace end up here ? */
8099 return(NULL);
8100 }
8101 case XML_DOCUMENT_NODE:
8102 case XML_DOCUMENT_TYPE_NODE:
8103 case XML_DOCUMENT_FRAG_NODE:
8104 case XML_HTML_DOCUMENT_NODE:
8105#ifdef LIBXML_DOCB_ENABLED
8106 case XML_DOCB_DOCUMENT_NODE:
8107#endif
8108 return(NULL);
8109 }
8110 return(NULL);
8111}
8112
8113/**
8114 * xmlXPathNextAncestorOrSelf:
8115 * @ctxt: the XPath Parser context
8116 * @cur: the current node in the traversal
8117 *
8118 * Traversal function for the "ancestor-or-self" direction
8119 * he ancestor-or-self axis contains the context node and ancestors of
8120 * the context node in reverse document order; thus the context node is
8121 * the first node on the axis, and the context node's parent the second;
8122 * parent here is defined the same as with the parent axis.
8123 *
8124 * Returns the next element following that axis
8125 */
8126xmlNodePtr
8127xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8128 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8129 if (cur == NULL)
8130 return(ctxt->context->node);
8131 return(xmlXPathNextAncestor(ctxt, cur));
8132}
8133
8134/**
8135 * xmlXPathNextFollowingSibling:
8136 * @ctxt: the XPath Parser context
8137 * @cur: the current node in the traversal
8138 *
8139 * Traversal function for the "following-sibling" direction
8140 * The following-sibling axis contains the following siblings of the context
8141 * node in document order.
8142 *
8143 * Returns the next element following that axis
8144 */
8145xmlNodePtr
8146xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8147 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8148 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8149 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8150 return(NULL);
8151 if (cur == (xmlNodePtr) ctxt->context->doc)
8152 return(NULL);
8153 if (cur == NULL)
8154 return(ctxt->context->node->next);
8155 return(cur->next);
8156}
8157
8158/**
8159 * xmlXPathNextPrecedingSibling:
8160 * @ctxt: the XPath Parser context
8161 * @cur: the current node in the traversal
8162 *
8163 * Traversal function for the "preceding-sibling" direction
8164 * The preceding-sibling axis contains the preceding siblings of the context
8165 * node in reverse document order; the first preceding sibling is first on the
8166 * axis; the sibling preceding that node is the second on the axis and so on.
8167 *
8168 * Returns the next element following that axis
8169 */
8170xmlNodePtr
8171xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8173 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8174 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8175 return(NULL);
8176 if (cur == (xmlNodePtr) ctxt->context->doc)
8177 return(NULL);
8178 if (cur == NULL)
8179 return(ctxt->context->node->prev);
8180 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8181 cur = cur->prev;
8182 if (cur == NULL)
8183 return(ctxt->context->node->prev);
8184 }
8185 return(cur->prev);
8186}
8187
8188/**
8189 * xmlXPathNextFollowing:
8190 * @ctxt: the XPath Parser context
8191 * @cur: the current node in the traversal
8192 *
8193 * Traversal function for the "following" direction
8194 * The following axis contains all nodes in the same document as the context
8195 * node that are after the context node in document order, excluding any
8196 * descendants and excluding attribute nodes and namespace nodes; the nodes
8197 * are ordered in document order
8198 *
8199 * Returns the next element following that axis
8200 */
8201xmlNodePtr
8202xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8203 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8204 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8205 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8206 return(cur->children);
8207
8208 if (cur == NULL) {
8209 cur = ctxt->context->node;
8210 if (cur->type == XML_ATTRIBUTE_NODE) {
8211 cur = cur->parent;
8212 } else if (cur->type == XML_NAMESPACE_DECL) {
8213 xmlNsPtr ns = (xmlNsPtr) cur;
8214
8215 if ((ns->next == NULL) ||
8216 (ns->next->type == XML_NAMESPACE_DECL))
8217 return (NULL);
8218 cur = (xmlNodePtr) ns->next;
8219 }
8220 }
8221 if (cur == NULL) return(NULL) ; /* ERROR */
8222 if (cur->next != NULL) return(cur->next) ;
8223 do {
8224 cur = cur->parent;
8225 if (cur == NULL) break;
8226 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8227 if (cur->next != NULL) return(cur->next);
8228 } while (cur != NULL);
8229 return(cur);
8230}
8231
8232/*
8233 * xmlXPathIsAncestor:
8234 * @ancestor: the ancestor node
8235 * @node: the current node
8236 *
8237 * Check that @ancestor is a @node's ancestor
8238 *
8239 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8240 */
8241static int
8242xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8243 if ((ancestor == NULL) || (node == NULL)) return(0);
8244 if (node->type == XML_NAMESPACE_DECL)
8245 return(0);
8246 if (ancestor->type == XML_NAMESPACE_DECL)
8247 return(0);
8248 /* nodes need to be in the same document */
8249 if (ancestor->doc != node->doc) return(0);
8250 /* avoid searching if ancestor or node is the root node */
8251 if (ancestor == (xmlNodePtr) node->doc) return(1);
8252 if (node == (xmlNodePtr) ancestor->doc) return(0);
8253 while (node->parent != NULL) {
8254 if (node->parent == ancestor)
8255 return(1);
8256 node = node->parent;
8257 }
8258 return(0);
8259}
8260
8261/**
8262 * xmlXPathNextPreceding:
8263 * @ctxt: the XPath Parser context
8264 * @cur: the current node in the traversal
8265 *
8266 * Traversal function for the "preceding" direction
8267 * the preceding axis contains all nodes in the same document as the context
8268 * node that are before the context node in document order, excluding any
8269 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8270 * ordered in reverse document order
8271 *
8272 * Returns the next element following that axis
8273 */
8274xmlNodePtr
8275xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8276{
8277 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8278 if (cur == NULL) {
8279 cur = ctxt->context->node;
8280 if (cur->type == XML_ATTRIBUTE_NODE) {
8281 cur = cur->parent;
8282 } else if (cur->type == XML_NAMESPACE_DECL) {
8283 xmlNsPtr ns = (xmlNsPtr) cur;
8284
8285 if ((ns->next == NULL) ||
8286 (ns->next->type == XML_NAMESPACE_DECL))
8287 return (NULL);
8288 cur = (xmlNodePtr) ns->next;
8289 }
8290 }
8291 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8292 return (NULL);
8293 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8294 cur = cur->prev;
8295 do {
8296 if (cur->prev != NULL) {
8297 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8298 return (cur);
8299 }
8300
8301 cur = cur->parent;
8302 if (cur == NULL)
8303 return (NULL);
8304 if (cur == ctxt->context->doc->children)
8305 return (NULL);
8306 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8307 return (cur);
8308}
8309
8310/**
8311 * xmlXPathNextPrecedingInternal:
8312 * @ctxt: the XPath Parser context
8313 * @cur: the current node in the traversal
8314 *
8315 * Traversal function for the "preceding" direction
8316 * the preceding axis contains all nodes in the same document as the context
8317 * node that are before the context node in document order, excluding any
8318 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8319 * ordered in reverse document order
8320 * This is a faster implementation but internal only since it requires a
8321 * state kept in the parser context: ctxt->ancestor.
8322 *
8323 * Returns the next element following that axis
8324 */
8325static xmlNodePtr
8326xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8327 xmlNodePtr cur)
8328{
8329 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8330 if (cur == NULL) {
8331 cur = ctxt->context->node;
8332 if (cur == NULL)
8333 return (NULL);
8334 if (cur->type == XML_ATTRIBUTE_NODE) {
8335 cur = cur->parent;
8336 } else if (cur->type == XML_NAMESPACE_DECL) {
8337 xmlNsPtr ns = (xmlNsPtr) cur;
8338
8339 if ((ns->next == NULL) ||
8340 (ns->next->type == XML_NAMESPACE_DECL))
8341 return (NULL);
8342 cur = (xmlNodePtr) ns->next;
8343 }
8344 ctxt->ancestor = cur->parent;
8345 }
8346 if (cur->type == XML_NAMESPACE_DECL)
8347 return(NULL);
8348 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8349 cur = cur->prev;
8350 while (cur->prev == NULL) {
8351 cur = cur->parent;
8352 if (cur == NULL)
8353 return (NULL);
8354 if (cur == ctxt->context->doc->children)
8355 return (NULL);
8356 if (cur != ctxt->ancestor)
8357 return (cur);
8358 ctxt->ancestor = cur->parent;
8359 }
8360 cur = cur->prev;
8361 while (cur->last != NULL)
8362 cur = cur->last;
8363 return (cur);
8364}
8365
8366/**
8367 * xmlXPathNextNamespace:
8368 * @ctxt: the XPath Parser context
8369 * @cur: the current attribute in the traversal
8370 *
8371 * Traversal function for the "namespace" direction
8372 * the namespace axis contains the namespace nodes of the context node;
8373 * the order of nodes on this axis is implementation-defined; the axis will
8374 * be empty unless the context node is an element
8375 *
8376 * We keep the XML namespace node at the end of the list.
8377 *
8378 * Returns the next element following that axis
8379 */
8380xmlNodePtr
8381xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8382 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8383 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8384 if (cur == NULL) {
8385 if (ctxt->context->tmpNsList != NULL)
8386 xmlFree(ctxt->context->tmpNsList);
8387 ctxt->context->tmpNsList =
8388 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8389 ctxt->context->tmpNsNr = 0;
8390 if (ctxt->context->tmpNsList != NULL) {
8391 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8392 ctxt->context->tmpNsNr++;
8393 }
8394 }
8395 return((xmlNodePtr) xmlXPathXMLNamespace);
8396 }
8397 if (ctxt->context->tmpNsNr > 0) {
8398 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8399 } else {
8400 if (ctxt->context->tmpNsList != NULL)
8401 xmlFree(ctxt->context->tmpNsList);
8402 ctxt->context->tmpNsList = NULL;
8403 return(NULL);
8404 }
8405}
8406
8407/**
8408 * xmlXPathNextAttribute:
8409 * @ctxt: the XPath Parser context
8410 * @cur: the current attribute in the traversal
8411 *
8412 * Traversal function for the "attribute" direction
8413 * TODO: support DTD inherited default attributes
8414 *
8415 * Returns the next element following that axis
8416 */
8417xmlNodePtr
8418xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8419 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8420 if (ctxt->context->node == NULL)
8421 return(NULL);
8422 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8423 return(NULL);
8424 if (cur == NULL) {
8425 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8426 return(NULL);
8427 return((xmlNodePtr)ctxt->context->node->properties);
8428 }
8429 return((xmlNodePtr)cur->next);
8430}
8431
8432/************************************************************************
8433 * *
8434 * NodeTest Functions *
8435 * *
8436 ************************************************************************/
8437
8438#define IS_FUNCTION 200
8439
8440
8441/************************************************************************
8442 * *
8443 * Implicit tree core function library *
8444 * *
8445 ************************************************************************/
8446
8447/**
8448 * xmlXPathRoot:
8449 * @ctxt: the XPath Parser context
8450 *
8451 * Initialize the context to the root of the document
8452 */
8453void
8454xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8455 if ((ctxt == NULL) || (ctxt->context == NULL))
8456 return;
8457 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8458 (xmlNodePtr) ctxt->context->doc));
8459}
8460
8461/************************************************************************
8462 * *
8463 * The explicit core function library *
8464 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8465 * *
8466 ************************************************************************/
8467
8468
8469/**
8470 * xmlXPathLastFunction:
8471 * @ctxt: the XPath Parser context
8472 * @nargs: the number of arguments
8473 *
8474 * Implement the last() XPath function
8475 * number last()
8476 * The last function returns the number of nodes in the context node list.
8477 */
8478void
8479xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8480 CHECK_ARITY(0);
8481 if (ctxt->context->contextSize >= 0) {
8482 valuePush(ctxt,
8483 xmlXPathCacheNewFloat(ctxt->context,
8484 (double) ctxt->context->contextSize));
8485#ifdef DEBUG_EXPR
8486 xmlGenericError(xmlGenericErrorContext,
8487 "last() : %d\n", ctxt->context->contextSize);
8488#endif
8489 } else {
8490 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8491 }
8492}
8493
8494/**
8495 * xmlXPathPositionFunction:
8496 * @ctxt: the XPath Parser context
8497 * @nargs: the number of arguments
8498 *
8499 * Implement the position() XPath function
8500 * number position()
8501 * The position function returns the position of the context node in the
8502 * context node list. The first position is 1, and so the last position
8503 * will be equal to last().
8504 */
8505void
8506xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8507 CHECK_ARITY(0);
8508 if (ctxt->context->proximityPosition >= 0) {
8509 valuePush(ctxt,
8510 xmlXPathCacheNewFloat(ctxt->context,
8511 (double) ctxt->context->proximityPosition));
8512#ifdef DEBUG_EXPR
8513 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8514 ctxt->context->proximityPosition);
8515#endif
8516 } else {
8517 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8518 }
8519}
8520
8521/**
8522 * xmlXPathCountFunction:
8523 * @ctxt: the XPath Parser context
8524 * @nargs: the number of arguments
8525 *
8526 * Implement the count() XPath function
8527 * number count(node-set)
8528 */
8529void
8530xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8531 xmlXPathObjectPtr cur;
8532
8533 CHECK_ARITY(1);
8534 if ((ctxt->value == NULL) ||
8535 ((ctxt->value->type != XPATH_NODESET) &&
8536 (ctxt->value->type != XPATH_XSLT_TREE)))
8537 XP_ERROR(XPATH_INVALID_TYPE);
8538 cur = valuePop(ctxt);
8539
8540 if ((cur == NULL) || (cur->nodesetval == NULL))
8541 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8542 else
8543 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8544 (double) cur->nodesetval->nodeNr));
8545 xmlXPathReleaseObject(ctxt->context, cur);
8546}
8547
8548/**
8549 * xmlXPathGetElementsByIds:
8550 * @doc: the document
8551 * @ids: a whitespace separated list of IDs
8552 *
8553 * Selects elements by their unique ID.
8554 *
8555 * Returns a node-set of selected elements.
8556 */
8557static xmlNodeSetPtr
8558xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8559 xmlNodeSetPtr ret;
8560 const xmlChar *cur = ids;
8561 xmlChar *ID;
8562 xmlAttrPtr attr;
8563 xmlNodePtr elem = NULL;
8564
8565 if (ids == NULL) return(NULL);
8566
8567 ret = xmlXPathNodeSetCreate(NULL);
8568 if (ret == NULL)
8569 return(ret);
8570
8571 while (IS_BLANK_CH(*cur)) cur++;
8572 while (*cur != 0) {
8573 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8574 cur++;
8575
8576 ID = xmlStrndup(ids, cur - ids);
8577 if (ID != NULL) {
8578 /*
8579 * We used to check the fact that the value passed
8580 * was an NCName, but this generated much troubles for
8581 * me and Aleksey Sanin, people blatantly violated that
8582 * constraint, like Visa3D spec.
8583 * if (xmlValidateNCName(ID, 1) == 0)
8584 */
8585 attr = xmlGetID(doc, ID);
8586 if (attr != NULL) {
8587 if (attr->type == XML_ATTRIBUTE_NODE)
8588 elem = attr->parent;
8589 else if (attr->type == XML_ELEMENT_NODE)
8590 elem = (xmlNodePtr) attr;
8591 else
8592 elem = NULL;
8593 /* TODO: Check memory error. */
8594 if (elem != NULL)
8595 xmlXPathNodeSetAdd(ret, elem);
8596 }
8597 xmlFree(ID);
8598 }
8599
8600 while (IS_BLANK_CH(*cur)) cur++;
8601 ids = cur;
8602 }
8603 return(ret);
8604}
8605
8606/**
8607 * xmlXPathIdFunction:
8608 * @ctxt: the XPath Parser context
8609 * @nargs: the number of arguments
8610 *
8611 * Implement the id() XPath function
8612 * node-set id(object)
8613 * The id function selects elements by their unique ID
8614 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8615 * then the result is the union of the result of applying id to the
8616 * string value of each of the nodes in the argument node-set. When the
8617 * argument to id is of any other type, the argument is converted to a
8618 * string as if by a call to the string function; the string is split
8619 * into a whitespace-separated list of tokens (whitespace is any sequence
8620 * of characters matching the production S); the result is a node-set
8621 * containing the elements in the same document as the context node that
8622 * have a unique ID equal to any of the tokens in the list.
8623 */
8624void
8625xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8626 xmlChar *tokens;
8627 xmlNodeSetPtr ret;
8628 xmlXPathObjectPtr obj;
8629
8630 CHECK_ARITY(1);
8631 obj = valuePop(ctxt);
8632 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8633 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8634 xmlNodeSetPtr ns;
8635 int i;
8636
8637 /* TODO: Check memory error. */
8638 ret = xmlXPathNodeSetCreate(NULL);
8639
8640 if (obj->nodesetval != NULL) {
8641 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8642 tokens =
8643 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8644 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8645 /* TODO: Check memory error. */
8646 ret = xmlXPathNodeSetMerge(ret, ns);
8647 xmlXPathFreeNodeSet(ns);
8648 if (tokens != NULL)
8649 xmlFree(tokens);
8650 }
8651 }
8652 xmlXPathReleaseObject(ctxt->context, obj);
8653 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8654 return;
8655 }
8656 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8657 if (obj == NULL) return;
8658 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8659 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8660 xmlXPathReleaseObject(ctxt->context, obj);
8661 return;
8662}
8663
8664/**
8665 * xmlXPathLocalNameFunction:
8666 * @ctxt: the XPath Parser context
8667 * @nargs: the number of arguments
8668 *
8669 * Implement the local-name() XPath function
8670 * string local-name(node-set?)
8671 * The local-name function returns a string containing the local part
8672 * of the name of the node in the argument node-set that is first in
8673 * document order. If the node-set is empty or the first node has no
8674 * name, an empty string is returned. If the argument is omitted it
8675 * defaults to the context node.
8676 */
8677void
8678xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8679 xmlXPathObjectPtr cur;
8680
8681 if (ctxt == NULL) return;
8682
8683 if (nargs == 0) {
8684 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8685 ctxt->context->node));
8686 nargs = 1;
8687 }
8688
8689 CHECK_ARITY(1);
8690 if ((ctxt->value == NULL) ||
8691 ((ctxt->value->type != XPATH_NODESET) &&
8692 (ctxt->value->type != XPATH_XSLT_TREE)))
8693 XP_ERROR(XPATH_INVALID_TYPE);
8694 cur = valuePop(ctxt);
8695
8696 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8697 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8698 } else {
8699 int i = 0; /* Should be first in document order !!!!! */
8700 switch (cur->nodesetval->nodeTab[i]->type) {
8701 case XML_ELEMENT_NODE:
8702 case XML_ATTRIBUTE_NODE:
8703 case XML_PI_NODE:
8704 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8705 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8706 else
8707 valuePush(ctxt,
8708 xmlXPathCacheNewString(ctxt->context,
8709 cur->nodesetval->nodeTab[i]->name));
8710 break;
8711 case XML_NAMESPACE_DECL:
8712 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8713 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8714 break;
8715 default:
8716 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8717 }
8718 }
8719 xmlXPathReleaseObject(ctxt->context, cur);
8720}
8721
8722/**
8723 * xmlXPathNamespaceURIFunction:
8724 * @ctxt: the XPath Parser context
8725 * @nargs: the number of arguments
8726 *
8727 * Implement the namespace-uri() XPath function
8728 * string namespace-uri(node-set?)
8729 * The namespace-uri function returns a string containing the
8730 * namespace URI of the expanded name of the node in the argument
8731 * node-set that is first in document order. If the node-set is empty,
8732 * the first node has no name, or the expanded name has no namespace
8733 * URI, an empty string is returned. If the argument is omitted it
8734 * defaults to the context node.
8735 */
8736void
8737xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8738 xmlXPathObjectPtr cur;
8739
8740 if (ctxt == NULL) return;
8741
8742 if (nargs == 0) {
8743 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8744 ctxt->context->node));
8745 nargs = 1;
8746 }
8747 CHECK_ARITY(1);
8748 if ((ctxt->value == NULL) ||
8749 ((ctxt->value->type != XPATH_NODESET) &&
8750 (ctxt->value->type != XPATH_XSLT_TREE)))
8751 XP_ERROR(XPATH_INVALID_TYPE);
8752 cur = valuePop(ctxt);
8753
8754 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8755 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8756 } else {
8757 int i = 0; /* Should be first in document order !!!!! */
8758 switch (cur->nodesetval->nodeTab[i]->type) {
8759 case XML_ELEMENT_NODE:
8760 case XML_ATTRIBUTE_NODE:
8761 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8762 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8763 else
8764 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8765 cur->nodesetval->nodeTab[i]->ns->href));
8766 break;
8767 default:
8768 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8769 }
8770 }
8771 xmlXPathReleaseObject(ctxt->context, cur);
8772}
8773
8774/**
8775 * xmlXPathNameFunction:
8776 * @ctxt: the XPath Parser context
8777 * @nargs: the number of arguments
8778 *
8779 * Implement the name() XPath function
8780 * string name(node-set?)
8781 * The name function returns a string containing a QName representing
8782 * the name of the node in the argument node-set that is first in document
8783 * order. The QName must represent the name with respect to the namespace
8784 * declarations in effect on the node whose name is being represented.
8785 * Typically, this will be the form in which the name occurred in the XML
8786 * source. This need not be the case if there are namespace declarations
8787 * in effect on the node that associate multiple prefixes with the same
8788 * namespace. However, an implementation may include information about
8789 * the original prefix in its representation of nodes; in this case, an
8790 * implementation can ensure that the returned string is always the same
8791 * as the QName used in the XML source. If the argument it omitted it
8792 * defaults to the context node.
8793 * Libxml keep the original prefix so the "real qualified name" used is
8794 * returned.
8795 */
8796static void
8797xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8798{
8799 xmlXPathObjectPtr cur;
8800
8801 if (nargs == 0) {
8802 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8803 ctxt->context->node));
8804 nargs = 1;
8805 }
8806
8807 CHECK_ARITY(1);
8808 if ((ctxt->value == NULL) ||
8809 ((ctxt->value->type != XPATH_NODESET) &&
8810 (ctxt->value->type != XPATH_XSLT_TREE)))
8811 XP_ERROR(XPATH_INVALID_TYPE);
8812 cur = valuePop(ctxt);
8813
8814 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8815 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8816 } else {
8817 int i = 0; /* Should be first in document order !!!!! */
8818
8819 switch (cur->nodesetval->nodeTab[i]->type) {
8820 case XML_ELEMENT_NODE:
8821 case XML_ATTRIBUTE_NODE:
8822 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8823 valuePush(ctxt,
8824 xmlXPathCacheNewCString(ctxt->context, ""));
8825 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8826 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8827 valuePush(ctxt,
8828 xmlXPathCacheNewString(ctxt->context,
8829 cur->nodesetval->nodeTab[i]->name));
8830 } else {
8831 xmlChar *fullname;
8832
8833 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8834 cur->nodesetval->nodeTab[i]->ns->prefix,
8835 NULL, 0);
8836 if (fullname == cur->nodesetval->nodeTab[i]->name)
8837 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8838 if (fullname == NULL) {
8839 XP_ERROR(XPATH_MEMORY_ERROR);
8840 }
8841 valuePush(ctxt, xmlXPathCacheWrapString(
8842 ctxt->context, fullname));
8843 }
8844 break;
8845 default:
8846 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8847 cur->nodesetval->nodeTab[i]));
8848 xmlXPathLocalNameFunction(ctxt, 1);
8849 }
8850 }
8851 xmlXPathReleaseObject(ctxt->context, cur);
8852}
8853
8854
8855/**
8856 * xmlXPathStringFunction:
8857 * @ctxt: the XPath Parser context
8858 * @nargs: the number of arguments
8859 *
8860 * Implement the string() XPath function
8861 * string string(object?)
8862 * The string function converts an object to a string as follows:
8863 * - A node-set is converted to a string by returning the value of
8864 * the node in the node-set that is first in document order.
8865 * If the node-set is empty, an empty string is returned.
8866 * - A number is converted to a string as follows
8867 * + NaN is converted to the string NaN
8868 * + positive zero is converted to the string 0
8869 * + negative zero is converted to the string 0
8870 * + positive infinity is converted to the string Infinity
8871 * + negative infinity is converted to the string -Infinity
8872 * + if the number is an integer, the number is represented in
8873 * decimal form as a Number with no decimal point and no leading
8874 * zeros, preceded by a minus sign (-) if the number is negative
8875 * + otherwise, the number is represented in decimal form as a
8876 * Number including a decimal point with at least one digit
8877 * before the decimal point and at least one digit after the
8878 * decimal point, preceded by a minus sign (-) if the number
8879 * is negative; there must be no leading zeros before the decimal
8880 * point apart possibly from the one required digit immediately
8881 * before the decimal point; beyond the one required digit
8882 * after the decimal point there must be as many, but only as
8883 * many, more digits as are needed to uniquely distinguish the
8884 * number from all other IEEE 754 numeric values.
8885 * - The boolean false value is converted to the string false.
8886 * The boolean true value is converted to the string true.
8887 *
8888 * If the argument is omitted, it defaults to a node-set with the
8889 * context node as its only member.
8890 */
8891void
8892xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8893 xmlXPathObjectPtr cur;
8894
8895 if (ctxt == NULL) return;
8896 if (nargs == 0) {
8897 valuePush(ctxt,
8898 xmlXPathCacheWrapString(ctxt->context,
8899 xmlXPathCastNodeToString(ctxt->context->node)));
8900 return;
8901 }
8902
8903 CHECK_ARITY(1);
8904 cur = valuePop(ctxt);
8905 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8906 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8907}
8908
8909/**
8910 * xmlXPathStringLengthFunction:
8911 * @ctxt: the XPath Parser context
8912 * @nargs: the number of arguments
8913 *
8914 * Implement the string-length() XPath function
8915 * number string-length(string?)
8916 * The string-length returns the number of characters in the string
8917 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8918 * the context node converted to a string, in other words the value
8919 * of the context node.
8920 */
8921void
8922xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8923 xmlXPathObjectPtr cur;
8924
8925 if (nargs == 0) {
8926 if ((ctxt == NULL) || (ctxt->context == NULL))
8927 return;
8928 if (ctxt->context->node == NULL) {
8929 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8930 } else {
8931 xmlChar *content;
8932
8933 content = xmlXPathCastNodeToString(ctxt->context->node);
8934 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8935 xmlUTF8Strlen(content)));
8936 xmlFree(content);
8937 }
8938 return;
8939 }
8940 CHECK_ARITY(1);
8941 CAST_TO_STRING;
8942 CHECK_TYPE(XPATH_STRING);
8943 cur = valuePop(ctxt);
8944 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8945 xmlUTF8Strlen(cur->stringval)));
8946 xmlXPathReleaseObject(ctxt->context, cur);
8947}
8948
8949/**
8950 * xmlXPathConcatFunction:
8951 * @ctxt: the XPath Parser context
8952 * @nargs: the number of arguments
8953 *
8954 * Implement the concat() XPath function
8955 * string concat(string, string, string*)
8956 * The concat function returns the concatenation of its arguments.
8957 */
8958void
8959xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8960 xmlXPathObjectPtr cur, newobj;
8961 xmlChar *tmp;
8962
8963 if (ctxt == NULL) return;
8964 if (nargs < 2) {
8965 CHECK_ARITY(2);
8966 }
8967
8968 CAST_TO_STRING;
8969 cur = valuePop(ctxt);
8970 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8971 xmlXPathReleaseObject(ctxt->context, cur);
8972 return;
8973 }
8974 nargs--;
8975
8976 while (nargs > 0) {
8977 CAST_TO_STRING;
8978 newobj = valuePop(ctxt);
8979 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8980 xmlXPathReleaseObject(ctxt->context, newobj);
8981 xmlXPathReleaseObject(ctxt->context, cur);
8982 XP_ERROR(XPATH_INVALID_TYPE);
8983 }
8984 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8985 newobj->stringval = cur->stringval;
8986 cur->stringval = tmp;
8987 xmlXPathReleaseObject(ctxt->context, newobj);
8988 nargs--;
8989 }
8990 valuePush(ctxt, cur);
8991}
8992
8993/**
8994 * xmlXPathContainsFunction:
8995 * @ctxt: the XPath Parser context
8996 * @nargs: the number of arguments
8997 *
8998 * Implement the contains() XPath function
8999 * boolean contains(string, string)
9000 * The contains function returns true if the first argument string
9001 * contains the second argument string, and otherwise returns false.
9002 */
9003void
9004xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9005 xmlXPathObjectPtr hay, needle;
9006
9007 CHECK_ARITY(2);
9008 CAST_TO_STRING;
9009 CHECK_TYPE(XPATH_STRING);
9010 needle = valuePop(ctxt);
9011 CAST_TO_STRING;
9012 hay = valuePop(ctxt);
9013
9014 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9015 xmlXPathReleaseObject(ctxt->context, hay);
9016 xmlXPathReleaseObject(ctxt->context, needle);
9017 XP_ERROR(XPATH_INVALID_TYPE);
9018 }
9019 if (xmlStrstr(hay->stringval, needle->stringval))
9020 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9021 else
9022 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9023 xmlXPathReleaseObject(ctxt->context, hay);
9024 xmlXPathReleaseObject(ctxt->context, needle);
9025}
9026
9027/**
9028 * xmlXPathStartsWithFunction:
9029 * @ctxt: the XPath Parser context
9030 * @nargs: the number of arguments
9031 *
9032 * Implement the starts-with() XPath function
9033 * boolean starts-with(string, string)
9034 * The starts-with function returns true if the first argument string
9035 * starts with the second argument string, and otherwise returns false.
9036 */
9037void
9038xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9039 xmlXPathObjectPtr hay, needle;
9040 int n;
9041
9042 CHECK_ARITY(2);
9043 CAST_TO_STRING;
9044 CHECK_TYPE(XPATH_STRING);
9045 needle = valuePop(ctxt);
9046 CAST_TO_STRING;
9047 hay = valuePop(ctxt);
9048
9049 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9050 xmlXPathReleaseObject(ctxt->context, hay);
9051 xmlXPathReleaseObject(ctxt->context, needle);
9052 XP_ERROR(XPATH_INVALID_TYPE);
9053 }
9054 n = xmlStrlen(needle->stringval);
9055 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9056 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9057 else
9058 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9059 xmlXPathReleaseObject(ctxt->context, hay);
9060 xmlXPathReleaseObject(ctxt->context, needle);
9061}
9062
9063/**
9064 * xmlXPathSubstringFunction:
9065 * @ctxt: the XPath Parser context
9066 * @nargs: the number of arguments
9067 *
9068 * Implement the substring() XPath function
9069 * string substring(string, number, number?)
9070 * The substring function returns the substring of the first argument
9071 * starting at the position specified in the second argument with
9072 * length specified in the third argument. For example,
9073 * substring("12345",2,3) returns "234". If the third argument is not
9074 * specified, it returns the substring starting at the position specified
9075 * in the second argument and continuing to the end of the string. For
9076 * example, substring("12345",2) returns "2345". More precisely, each
9077 * character in the string (see [3.6 Strings]) is considered to have a
9078 * numeric position: the position of the first character is 1, the position
9079 * of the second character is 2 and so on. The returned substring contains
9080 * those characters for which the position of the character is greater than
9081 * or equal to the second argument and, if the third argument is specified,
9082 * less than the sum of the second and third arguments; the comparisons
9083 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9084 * - substring("12345", 1.5, 2.6) returns "234"
9085 * - substring("12345", 0, 3) returns "12"
9086 * - substring("12345", 0 div 0, 3) returns ""
9087 * - substring("12345", 1, 0 div 0) returns ""
9088 * - substring("12345", -42, 1 div 0) returns "12345"
9089 * - substring("12345", -1 div 0, 1 div 0) returns ""
9090 */
9091void
9092xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9093 xmlXPathObjectPtr str, start, len;
9094 double le=0, in;
9095 int i = 1, j = INT_MAX;
9096
9097 if (nargs < 2) {
9098 CHECK_ARITY(2);
9099 }
9100 if (nargs > 3) {
9101 CHECK_ARITY(3);
9102 }
9103 /*
9104 * take care of possible last (position) argument
9105 */
9106 if (nargs == 3) {
9107 CAST_TO_NUMBER;
9108 CHECK_TYPE(XPATH_NUMBER);
9109 len = valuePop(ctxt);
9110 le = len->floatval;
9111 xmlXPathReleaseObject(ctxt->context, len);
9112 }
9113
9114 CAST_TO_NUMBER;
9115 CHECK_TYPE(XPATH_NUMBER);
9116 start = valuePop(ctxt);
9117 in = start->floatval;
9118 xmlXPathReleaseObject(ctxt->context, start);
9119 CAST_TO_STRING;
9120 CHECK_TYPE(XPATH_STRING);
9121 str = valuePop(ctxt);
9122
9123 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9124 i = INT_MAX;
9125 } else if (in >= 1.0) {
9126 i = (int)in;
9127 if (in - floor(in) >= 0.5)
9128 i += 1;
9129 }
9130
9131 if (nargs == 3) {
9132 double rin, rle, end;
9133
9134 rin = floor(in);
9135 if (in - rin >= 0.5)
9136 rin += 1.0;
9137
9138 rle = floor(le);
9139 if (le - rle >= 0.5)
9140 rle += 1.0;
9141
9142 end = rin + rle;
9143 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9144 j = 1;
9145 } else if (end < INT_MAX) {
9146 j = (int)end;
9147 }
9148 }
9149
9150 if (i < j) {
9151 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9152 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9153 xmlFree(ret);
9154 } else {
9155 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9156 }
9157
9158 xmlXPathReleaseObject(ctxt->context, str);
9159}
9160
9161/**
9162 * xmlXPathSubstringBeforeFunction:
9163 * @ctxt: the XPath Parser context
9164 * @nargs: the number of arguments
9165 *
9166 * Implement the substring-before() XPath function
9167 * string substring-before(string, string)
9168 * The substring-before function returns the substring of the first
9169 * argument string that precedes the first occurrence of the second
9170 * argument string in the first argument string, or the empty string
9171 * if the first argument string does not contain the second argument
9172 * string. For example, substring-before("1999/04/01","/") returns 1999.
9173 */
9174void
9175xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9176 xmlXPathObjectPtr str;
9177 xmlXPathObjectPtr find;
9178 xmlBufPtr target;
9179 const xmlChar *point;
9180 int offset;
9181
9182 CHECK_ARITY(2);
9183 CAST_TO_STRING;
9184 find = valuePop(ctxt);
9185 CAST_TO_STRING;
9186 str = valuePop(ctxt);
9187
9188 target = xmlBufCreate();
9189 if (target) {
9190 point = xmlStrstr(str->stringval, find->stringval);
9191 if (point) {
9192 offset = (int)(point - str->stringval);
9193 xmlBufAdd(target, str->stringval, offset);
9194 }
9195 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9196 xmlBufContent(target)));
9197 xmlBufFree(target);
9198 }
9199 xmlXPathReleaseObject(ctxt->context, str);
9200 xmlXPathReleaseObject(ctxt->context, find);
9201}
9202
9203/**
9204 * xmlXPathSubstringAfterFunction:
9205 * @ctxt: the XPath Parser context
9206 * @nargs: the number of arguments
9207 *
9208 * Implement the substring-after() XPath function
9209 * string substring-after(string, string)
9210 * The substring-after function returns the substring of the first
9211 * argument string that follows the first occurrence of the second
9212 * argument string in the first argument string, or the empty stringi
9213 * if the first argument string does not contain the second argument
9214 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9215 * and substring-after("1999/04/01","19") returns 99/04/01.
9216 */
9217void
9218xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9219 xmlXPathObjectPtr str;
9220 xmlXPathObjectPtr find;
9221 xmlBufPtr target;
9222 const xmlChar *point;
9223 int offset;
9224
9225 CHECK_ARITY(2);
9226 CAST_TO_STRING;
9227 find = valuePop(ctxt);
9228 CAST_TO_STRING;
9229 str = valuePop(ctxt);
9230
9231 target = xmlBufCreate();
9232 if (target) {
9233 point = xmlStrstr(str->stringval, find->stringval);
9234 if (point) {
9235 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9236 xmlBufAdd(target, &str->stringval[offset],
9237 xmlStrlen(str->stringval) - offset);
9238 }
9239 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9240 xmlBufContent(target)));
9241 xmlBufFree(target);
9242 }
9243 xmlXPathReleaseObject(ctxt->context, str);
9244 xmlXPathReleaseObject(ctxt->context, find);
9245}
9246
9247/**
9248 * xmlXPathNormalizeFunction:
9249 * @ctxt: the XPath Parser context
9250 * @nargs: the number of arguments
9251 *
9252 * Implement the normalize-space() XPath function
9253 * string normalize-space(string?)
9254 * The normalize-space function returns the argument string with white
9255 * space normalized by stripping leading and trailing whitespace
9256 * and replacing sequences of whitespace characters by a single
9257 * space. Whitespace characters are the same allowed by the S production
9258 * in XML. If the argument is omitted, it defaults to the context
9259 * node converted to a string, in other words the value of the context node.
9260 */
9261void
9262xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9263 xmlChar *source, *target;
9264 int blank;
9265
9266 if (ctxt == NULL) return;
9267 if (nargs == 0) {
9268 /* Use current context node */
9269 valuePush(ctxt,
9270 xmlXPathCacheWrapString(ctxt->context,
9271 xmlXPathCastNodeToString(ctxt->context->node)));
9272 nargs = 1;
9273 }
9274
9275 CHECK_ARITY(1);
9276 CAST_TO_STRING;
9277 CHECK_TYPE(XPATH_STRING);
9278 source = ctxt->value->stringval;
9279 if (source == NULL)
9280 return;
9281 target = source;
9282
9283 /* Skip leading whitespaces */
9284 while (IS_BLANK_CH(*source))
9285 source++;
9286
9287 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9288 blank = 0;
9289 while (*source) {
9290 if (IS_BLANK_CH(*source)) {
9291 blank = 1;
9292 } else {
9293 if (blank) {
9294 *target++ = 0x20;
9295 blank = 0;
9296 }
9297 *target++ = *source;
9298 }
9299 source++;
9300 }
9301 *target = 0;
9302}
9303
9304/**
9305 * xmlXPathTranslateFunction:
9306 * @ctxt: the XPath Parser context
9307 * @nargs: the number of arguments
9308 *
9309 * Implement the translate() XPath function
9310 * string translate(string, string, string)
9311 * The translate function returns the first argument string with
9312 * occurrences of characters in the second argument string replaced
9313 * by the character at the corresponding position in the third argument
9314 * string. For example, translate("bar","abc","ABC") returns the string
9315 * BAr. If there is a character in the second argument string with no
9316 * character at a corresponding position in the third argument string
9317 * (because the second argument string is longer than the third argument
9318 * string), then occurrences of that character in the first argument
9319 * string are removed. For example, translate("--aaa--","abc-","ABC")
9320 * returns "AAA". If a character occurs more than once in second
9321 * argument string, then the first occurrence determines the replacement
9322 * character. If the third argument string is longer than the second
9323 * argument string, then excess characters are ignored.
9324 */
9325void
9326xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9327 xmlXPathObjectPtr str;
9328 xmlXPathObjectPtr from;
9329 xmlXPathObjectPtr to;
9330 xmlBufPtr target;
9331 int offset, max;
9332 xmlChar ch;
9333 const xmlChar *point;
9334 xmlChar *cptr;
9335
9336 CHECK_ARITY(3);
9337
9338 CAST_TO_STRING;
9339 to = valuePop(ctxt);
9340 CAST_TO_STRING;
9341 from = valuePop(ctxt);
9342 CAST_TO_STRING;
9343 str = valuePop(ctxt);
9344
9345 target = xmlBufCreate();
9346 if (target) {
9347 max = xmlUTF8Strlen(to->stringval);
9348 for (cptr = str->stringval; (ch=*cptr); ) {
9349 offset = xmlUTF8Strloc(from->stringval, cptr);
9350 if (offset >= 0) {
9351 if (offset < max) {
9352 point = xmlUTF8Strpos(to->stringval, offset);
9353 if (point)
9354 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9355 }
9356 } else
9357 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9358
9359 /* Step to next character in input */
9360 cptr++;
9361 if ( ch & 0x80 ) {
9362 /* if not simple ascii, verify proper format */
9363 if ( (ch & 0xc0) != 0xc0 ) {
9364 xmlGenericError(xmlGenericErrorContext,
9365 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9366 /* not asserting an XPath error is probably better */
9367 break;
9368 }
9369 /* then skip over remaining bytes for this char */
9370 while ( (ch <<= 1) & 0x80 )
9371 if ( (*cptr++ & 0xc0) != 0x80 ) {
9372 xmlGenericError(xmlGenericErrorContext,
9373 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9374 /* not asserting an XPath error is probably better */
9375 break;
9376 }
9377 if (ch & 0x80) /* must have had error encountered */
9378 break;
9379 }
9380 }
9381 }
9382 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9383 xmlBufContent(target)));
9384 xmlBufFree(target);
9385 xmlXPathReleaseObject(ctxt->context, str);
9386 xmlXPathReleaseObject(ctxt->context, from);
9387 xmlXPathReleaseObject(ctxt->context, to);
9388}
9389
9390/**
9391 * xmlXPathBooleanFunction:
9392 * @ctxt: the XPath Parser context
9393 * @nargs: the number of arguments
9394 *
9395 * Implement the boolean() XPath function
9396 * boolean boolean(object)
9397 * The boolean function converts its argument to a boolean as follows:
9398 * - a number is true if and only if it is neither positive or
9399 * negative zero nor NaN
9400 * - a node-set is true if and only if it is non-empty
9401 * - a string is true if and only if its length is non-zero
9402 */
9403void
9404xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9405 xmlXPathObjectPtr cur;
9406
9407 CHECK_ARITY(1);
9408 cur = valuePop(ctxt);
9409 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9410 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9411 valuePush(ctxt, cur);
9412}
9413
9414/**
9415 * xmlXPathNotFunction:
9416 * @ctxt: the XPath Parser context
9417 * @nargs: the number of arguments
9418 *
9419 * Implement the not() XPath function
9420 * boolean not(boolean)
9421 * The not function returns true if its argument is false,
9422 * and false otherwise.
9423 */
9424void
9425xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9426 CHECK_ARITY(1);
9427 CAST_TO_BOOLEAN;
9428 CHECK_TYPE(XPATH_BOOLEAN);
9429 ctxt->value->boolval = ! ctxt->value->boolval;
9430}
9431
9432/**
9433 * xmlXPathTrueFunction:
9434 * @ctxt: the XPath Parser context
9435 * @nargs: the number of arguments
9436 *
9437 * Implement the true() XPath function
9438 * boolean true()
9439 */
9440void
9441xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9442 CHECK_ARITY(0);
9443 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9444}
9445
9446/**
9447 * xmlXPathFalseFunction:
9448 * @ctxt: the XPath Parser context
9449 * @nargs: the number of arguments
9450 *
9451 * Implement the false() XPath function
9452 * boolean false()
9453 */
9454void
9455xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9456 CHECK_ARITY(0);
9457 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9458}
9459
9460/**
9461 * xmlXPathLangFunction:
9462 * @ctxt: the XPath Parser context
9463 * @nargs: the number of arguments
9464 *
9465 * Implement the lang() XPath function
9466 * boolean lang(string)
9467 * The lang function returns true or false depending on whether the
9468 * language of the context node as specified by xml:lang attributes
9469 * is the same as or is a sublanguage of the language specified by
9470 * the argument string. The language of the context node is determined
9471 * by the value of the xml:lang attribute on the context node, or, if
9472 * the context node has no xml:lang attribute, by the value of the
9473 * xml:lang attribute on the nearest ancestor of the context node that
9474 * has an xml:lang attribute. If there is no such attribute, then lang
9475 * returns false. If there is such an attribute, then lang returns
9476 * true if the attribute value is equal to the argument ignoring case,
9477 * or if there is some suffix starting with - such that the attribute
9478 * value is equal to the argument ignoring that suffix of the attribute
9479 * value and ignoring case.
9480 */
9481void
9482xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9483 xmlXPathObjectPtr val = NULL;
9484 const xmlChar *theLang = NULL;
9485 const xmlChar *lang;
9486 int ret = 0;
9487 int i;
9488
9489 CHECK_ARITY(1);
9490 CAST_TO_STRING;
9491 CHECK_TYPE(XPATH_STRING);
9492 val = valuePop(ctxt);
9493 lang = val->stringval;
9494 theLang = xmlNodeGetLang(ctxt->context->node);
9495 if ((theLang != NULL) && (lang != NULL)) {
9496 for (i = 0;lang[i] != 0;i++)
9497 if (toupper(lang[i]) != toupper(theLang[i]))
9498 goto not_equal;
9499 if ((theLang[i] == 0) || (theLang[i] == '-'))
9500 ret = 1;
9501 }
9502not_equal:
9503 if (theLang != NULL)
9504 xmlFree((void *)theLang);
9505
9506 xmlXPathReleaseObject(ctxt->context, val);
9507 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9508}
9509
9510/**
9511 * xmlXPathNumberFunction:
9512 * @ctxt: the XPath Parser context
9513 * @nargs: the number of arguments
9514 *
9515 * Implement the number() XPath function
9516 * number number(object?)
9517 */
9518void
9519xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9520 xmlXPathObjectPtr cur;
9521 double res;
9522
9523 if (ctxt == NULL) return;
9524 if (nargs == 0) {
9525 if (ctxt->context->node == NULL) {
9526 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9527 } else {
9528 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9529
9530 res = xmlXPathStringEvalNumber(content);
9531 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9532 xmlFree(content);
9533 }
9534 return;
9535 }
9536
9537 CHECK_ARITY(1);
9538 cur = valuePop(ctxt);
9539 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9540}
9541
9542/**
9543 * xmlXPathSumFunction:
9544 * @ctxt: the XPath Parser context
9545 * @nargs: the number of arguments
9546 *
9547 * Implement the sum() XPath function
9548 * number sum(node-set)
9549 * The sum function returns the sum of the values of the nodes in
9550 * the argument node-set.
9551 */
9552void
9553xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9554 xmlXPathObjectPtr cur;
9555 int i;
9556 double res = 0.0;
9557
9558 CHECK_ARITY(1);
9559 if ((ctxt->value == NULL) ||
9560 ((ctxt->value->type != XPATH_NODESET) &&
9561 (ctxt->value->type != XPATH_XSLT_TREE)))
9562 XP_ERROR(XPATH_INVALID_TYPE);
9563 cur = valuePop(ctxt);
9564
9565 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9566 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9567 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9568 }
9569 }
9570 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9571 xmlXPathReleaseObject(ctxt->context, cur);
9572}
9573
9574/**
9575 * xmlXPathFloorFunction:
9576 * @ctxt: the XPath Parser context
9577 * @nargs: the number of arguments
9578 *
9579 * Implement the floor() XPath function
9580 * number floor(number)
9581 * The floor function returns the largest (closest to positive infinity)
9582 * number that is not greater than the argument and that is an integer.
9583 */
9584void
9585xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9586 CHECK_ARITY(1);
9587 CAST_TO_NUMBER;
9588 CHECK_TYPE(XPATH_NUMBER);
9589
9590 ctxt->value->floatval = floor(ctxt->value->floatval);
9591}
9592
9593/**
9594 * xmlXPathCeilingFunction:
9595 * @ctxt: the XPath Parser context
9596 * @nargs: the number of arguments
9597 *
9598 * Implement the ceiling() XPath function
9599 * number ceiling(number)
9600 * The ceiling function returns the smallest (closest to negative infinity)
9601 * number that is not less than the argument and that is an integer.
9602 */
9603void
9604xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9605 CHECK_ARITY(1);
9606 CAST_TO_NUMBER;
9607 CHECK_TYPE(XPATH_NUMBER);
9608
9609#ifdef _AIX
9610 /* Work around buggy ceil() function on AIX */
9611 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9612#else
9613 ctxt->value->floatval = ceil(ctxt->value->floatval);
9614#endif
9615}
9616
9617/**
9618 * xmlXPathRoundFunction:
9619 * @ctxt: the XPath Parser context
9620 * @nargs: the number of arguments
9621 *
9622 * Implement the round() XPath function
9623 * number round(number)
9624 * The round function returns the number that is closest to the
9625 * argument and that is an integer. If there are two such numbers,
9626 * then the one that is closest to positive infinity is returned.
9627 */
9628void
9629xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9630 double f;
9631
9632 CHECK_ARITY(1);
9633 CAST_TO_NUMBER;
9634 CHECK_TYPE(XPATH_NUMBER);
9635
9636 f = ctxt->value->floatval;
9637
9638 if ((f >= -0.5) && (f < 0.5)) {
9639 /* Handles negative zero. */
9640 ctxt->value->floatval *= 0.0;
9641 }
9642 else {
9643 double rounded = floor(f);
9644 if (f - rounded >= 0.5)
9645 rounded += 1.0;
9646 ctxt->value->floatval = rounded;
9647 }
9648}
9649
9650/************************************************************************
9651 * *
9652 * The Parser *
9653 * *
9654 ************************************************************************/
9655
9656/*
9657 * a few forward declarations since we use a recursive call based
9658 * implementation.
9659 */
9660static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9661static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9662static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9663static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9664static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9665 int qualified);
9666
9667/**
9668 * xmlXPathCurrentChar:
9669 * @ctxt: the XPath parser context
9670 * @cur: pointer to the beginning of the char
9671 * @len: pointer to the length of the char read
9672 *
9673 * The current char value, if using UTF-8 this may actually span multiple
9674 * bytes in the input buffer.
9675 *
9676 * Returns the current char value and its length
9677 */
9678
9679static int
9680xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9681 unsigned char c;
9682 unsigned int val;
9683 const xmlChar *cur;
9684
9685 if (ctxt == NULL)
9686 return(0);
9687 cur = ctxt->cur;
9688
9689 /*
9690 * We are supposed to handle UTF8, check it's valid
9691 * From rfc2044: encoding of the Unicode values on UTF-8:
9692 *
9693 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9694 * 0000 0000-0000 007F 0xxxxxxx
9695 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9696 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9697 *
9698 * Check for the 0x110000 limit too
9699 */
9700 c = *cur;
9701 if (c & 0x80) {
9702 if ((cur[1] & 0xc0) != 0x80)
9703 goto encoding_error;
9704 if ((c & 0xe0) == 0xe0) {
9705
9706 if ((cur[2] & 0xc0) != 0x80)
9707 goto encoding_error;
9708 if ((c & 0xf0) == 0xf0) {
9709 if (((c & 0xf8) != 0xf0) ||
9710 ((cur[3] & 0xc0) != 0x80))
9711 goto encoding_error;
9712 /* 4-byte code */
9713 *len = 4;
9714 val = (cur[0] & 0x7) << 18;
9715 val |= (cur[1] & 0x3f) << 12;
9716 val |= (cur[2] & 0x3f) << 6;
9717 val |= cur[3] & 0x3f;
9718 } else {
9719 /* 3-byte code */
9720 *len = 3;
9721 val = (cur[0] & 0xf) << 12;
9722 val |= (cur[1] & 0x3f) << 6;
9723 val |= cur[2] & 0x3f;
9724 }
9725 } else {
9726 /* 2-byte code */
9727 *len = 2;
9728 val = (cur[0] & 0x1f) << 6;
9729 val |= cur[1] & 0x3f;
9730 }
9731 if (!IS_CHAR(val)) {
9732 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9733 }
9734 return(val);
9735 } else {
9736 /* 1-byte code */
9737 *len = 1;
9738 return((int) *cur);
9739 }
9740encoding_error:
9741 /*
9742 * If we detect an UTF8 error that probably means that the
9743 * input encoding didn't get properly advertised in the
9744 * declaration header. Report the error and switch the encoding
9745 * to ISO-Latin-1 (if you don't like this policy, just declare the
9746 * encoding !)
9747 */
9748 *len = 0;
9749 XP_ERROR0(XPATH_ENCODING_ERROR);
9750}
9751
9752/**
9753 * xmlXPathParseNCName:
9754 * @ctxt: the XPath Parser context
9755 *
9756 * parse an XML namespace non qualified name.
9757 *
9758 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9759 *
9760 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9761 * CombiningChar | Extender
9762 *
9763 * Returns the namespace name or NULL
9764 */
9765
9766xmlChar *
9767xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9768 const xmlChar *in;
9769 xmlChar *ret;
9770 int count = 0;
9771
9772 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9773 /*
9774 * Accelerator for simple ASCII names
9775 */
9776 in = ctxt->cur;
9777 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9778 ((*in >= 0x41) && (*in <= 0x5A)) ||
9779 (*in == '_')) {
9780 in++;
9781 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9782 ((*in >= 0x41) && (*in <= 0x5A)) ||
9783 ((*in >= 0x30) && (*in <= 0x39)) ||
9784 (*in == '_') || (*in == '.') ||
9785 (*in == '-'))
9786 in++;
9787 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9788 (*in == '[') || (*in == ']') || (*in == ':') ||
9789 (*in == '@') || (*in == '*')) {
9790 count = in - ctxt->cur;
9791 if (count == 0)
9792 return(NULL);
9793 ret = xmlStrndup(ctxt->cur, count);
9794 ctxt->cur = in;
9795 return(ret);
9796 }
9797 }
9798 return(xmlXPathParseNameComplex(ctxt, 0));
9799}
9800
9801
9802/**
9803 * xmlXPathParseQName:
9804 * @ctxt: the XPath Parser context
9805 * @prefix: a xmlChar **
9806 *
9807 * parse an XML qualified name
9808 *
9809 * [NS 5] QName ::= (Prefix ':')? LocalPart
9810 *
9811 * [NS 6] Prefix ::= NCName
9812 *
9813 * [NS 7] LocalPart ::= NCName
9814 *
9815 * Returns the function returns the local part, and prefix is updated
9816 * to get the Prefix if any.
9817 */
9818
9819static xmlChar *
9820xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9821 xmlChar *ret = NULL;
9822
9823 *prefix = NULL;
9824 ret = xmlXPathParseNCName(ctxt);
9825 if (ret && CUR == ':') {
9826 *prefix = ret;
9827 NEXT;
9828 ret = xmlXPathParseNCName(ctxt);
9829 }
9830 return(ret);
9831}
9832
9833/**
9834 * xmlXPathParseName:
9835 * @ctxt: the XPath Parser context
9836 *
9837 * parse an XML name
9838 *
9839 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9840 * CombiningChar | Extender
9841 *
9842 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9843 *
9844 * Returns the namespace name or NULL
9845 */
9846
9847xmlChar *
9848xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9849 const xmlChar *in;
9850 xmlChar *ret;
9851 size_t count = 0;
9852
9853 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9854 /*
9855 * Accelerator for simple ASCII names
9856 */
9857 in = ctxt->cur;
9858 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9859 ((*in >= 0x41) && (*in <= 0x5A)) ||
9860 (*in == '_') || (*in == ':')) {
9861 in++;
9862 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9863 ((*in >= 0x41) && (*in <= 0x5A)) ||
9864 ((*in >= 0x30) && (*in <= 0x39)) ||
9865 (*in == '_') || (*in == '-') ||
9866 (*in == ':') || (*in == '.'))
9867 in++;
9868 if ((*in > 0) && (*in < 0x80)) {
9869 count = in - ctxt->cur;
9870 if (count > XML_MAX_NAME_LENGTH) {
9871 ctxt->cur = in;
9872 XP_ERRORNULL(XPATH_EXPR_ERROR);
9873 }
9874 ret = xmlStrndup(ctxt->cur, count);
9875 ctxt->cur = in;
9876 return(ret);
9877 }
9878 }
9879 return(xmlXPathParseNameComplex(ctxt, 1));
9880}
9881
9882static xmlChar *
9883xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9884 xmlChar buf[XML_MAX_NAMELEN + 5];
9885 int len = 0, l;
9886 int c;
9887
9888 /*
9889 * Handler for more complex cases
9890 */
9891 c = CUR_CHAR(l);
9892 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9893 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9894 (c == '*') || /* accelerators */
9895 (!IS_LETTER(c) && (c != '_') &&
9896 ((!qualified) || (c != ':')))) {
9897 return(NULL);
9898 }
9899
9900 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9901 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9902 (c == '.') || (c == '-') ||
9903 (c == '_') || ((qualified) && (c == ':')) ||
9904 (IS_COMBINING(c)) ||
9905 (IS_EXTENDER(c)))) {
9906 COPY_BUF(l,buf,len,c);
9907 NEXTL(l);
9908 c = CUR_CHAR(l);
9909 if (len >= XML_MAX_NAMELEN) {
9910 /*
9911 * Okay someone managed to make a huge name, so he's ready to pay
9912 * for the processing speed.
9913 */
9914 xmlChar *buffer;
9915 int max = len * 2;
9916
9917 if (len > XML_MAX_NAME_LENGTH) {
9918 XP_ERRORNULL(XPATH_EXPR_ERROR);
9919 }
9920 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9921 if (buffer == NULL) {
9922 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9923 }
9924 memcpy(buffer, buf, len);
9925 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9926 (c == '.') || (c == '-') ||
9927 (c == '_') || ((qualified) && (c == ':')) ||
9928 (IS_COMBINING(c)) ||
9929 (IS_EXTENDER(c))) {
9930 if (len + 10 > max) {
9931 xmlChar *tmp;
9932 if (max > XML_MAX_NAME_LENGTH) {
9933 xmlFree(buffer);
9934 XP_ERRORNULL(XPATH_EXPR_ERROR);
9935 }
9936 max *= 2;
9937 tmp = (xmlChar *) xmlRealloc(buffer,
9938 max * sizeof(xmlChar));
9939 if (tmp == NULL) {
9940 xmlFree(buffer);
9941 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9942 }
9943 buffer = tmp;
9944 }
9945 COPY_BUF(l,buffer,len,c);
9946 NEXTL(l);
9947 c = CUR_CHAR(l);
9948 }
9949 buffer[len] = 0;
9950 return(buffer);
9951 }
9952 }
9953 if (len == 0)
9954 return(NULL);
9955 return(xmlStrndup(buf, len));
9956}
9957
9958#define MAX_FRAC 20
9959
9960/**
9961 * xmlXPathStringEvalNumber:
9962 * @str: A string to scan
9963 *
9964 * [30a] Float ::= Number ('e' Digits?)?
9965 *
9966 * [30] Number ::= Digits ('.' Digits?)?
9967 * | '.' Digits
9968 * [31] Digits ::= [0-9]+
9969 *
9970 * Compile a Number in the string
9971 * In complement of the Number expression, this function also handles
9972 * negative values : '-' Number.
9973 *
9974 * Returns the double value.
9975 */
9976double
9977xmlXPathStringEvalNumber(const xmlChar *str) {
9978 const xmlChar *cur = str;
9979 double ret;
9980 int ok = 0;
9981 int isneg = 0;
9982 int exponent = 0;
9983 int is_exponent_negative = 0;
9984#ifdef __GNUC__
9985 unsigned long tmp = 0;
9986 double temp;
9987#endif
9988 if (cur == NULL) return(0);
9989 while (IS_BLANK_CH(*cur)) cur++;
9990 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9991 return(xmlXPathNAN);
9992 }
9993 if (*cur == '-') {
9994 isneg = 1;
9995 cur++;
9996 }
9997
9998#ifdef __GNUC__
9999 /*
10000 * tmp/temp is a workaround against a gcc compiler bug
10001 * http://veillard.com/gcc.bug
10002 */
10003 ret = 0;
10004 while ((*cur >= '0') && (*cur <= '9')) {
10005 ret = ret * 10;
10006 tmp = (*cur - '0');
10007 ok = 1;
10008 cur++;
10009 temp = (double) tmp;
10010 ret = ret + temp;
10011 }
10012#else
10013 ret = 0;
10014 while ((*cur >= '0') && (*cur <= '9')) {
10015 ret = ret * 10 + (*cur - '0');
10016 ok = 1;
10017 cur++;
10018 }
10019#endif
10020
10021 if (*cur == '.') {
10022 int v, frac = 0, max;
10023 double fraction = 0;
10024
10025 cur++;
10026 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10027 return(xmlXPathNAN);
10028 }
10029 while (*cur == '0') {
10030 frac = frac + 1;
10031 cur++;
10032 }
10033 max = frac + MAX_FRAC;
10034 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10035 v = (*cur - '0');
10036 fraction = fraction * 10 + v;
10037 frac = frac + 1;
10038 cur++;
10039 }
10040 fraction /= pow(10.0, frac);
10041 ret = ret + fraction;
10042 while ((*cur >= '0') && (*cur <= '9'))
10043 cur++;
10044 }
10045 if ((*cur == 'e') || (*cur == 'E')) {
10046 cur++;
10047 if (*cur == '-') {
10048 is_exponent_negative = 1;
10049 cur++;
10050 } else if (*cur == '+') {
10051 cur++;
10052 }
10053 while ((*cur >= '0') && (*cur <= '9')) {
10054 if (exponent < 1000000)
10055 exponent = exponent * 10 + (*cur - '0');
10056 cur++;
10057 }
10058 }
10059 while (IS_BLANK_CH(*cur)) cur++;
10060 if (*cur != 0) return(xmlXPathNAN);
10061 if (isneg) ret = -ret;
10062 if (is_exponent_negative) exponent = -exponent;
10063 ret *= pow(10.0, (double)exponent);
10064 return(ret);
10065}
10066
10067/**
10068 * xmlXPathCompNumber:
10069 * @ctxt: the XPath Parser context
10070 *
10071 * [30] Number ::= Digits ('.' Digits?)?
10072 * | '.' Digits
10073 * [31] Digits ::= [0-9]+
10074 *
10075 * Compile a Number, then push it on the stack
10076 *
10077 */
10078static void
10079xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10080{
10081 double ret = 0.0;
10082 int ok = 0;
10083 int exponent = 0;
10084 int is_exponent_negative = 0;
10085 xmlXPathObjectPtr num;
10086#ifdef __GNUC__
10087 unsigned long tmp = 0;
10088 double temp;
10089#endif
10090
10091 CHECK_ERROR;
10092 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10093 XP_ERROR(XPATH_NUMBER_ERROR);
10094 }
10095#ifdef __GNUC__
10096 /*
10097 * tmp/temp is a workaround against a gcc compiler bug
10098 * http://veillard.com/gcc.bug
10099 */
10100 ret = 0;
10101 while ((CUR >= '0') && (CUR <= '9')) {
10102 ret = ret * 10;
10103 tmp = (CUR - '0');
10104 ok = 1;
10105 NEXT;
10106 temp = (double) tmp;
10107 ret = ret + temp;
10108 }
10109#else
10110 ret = 0;
10111 while ((CUR >= '0') && (CUR <= '9')) {
10112 ret = ret * 10 + (CUR - '0');
10113 ok = 1;
10114 NEXT;
10115 }
10116#endif
10117 if (CUR == '.') {
10118 int v, frac = 0, max;
10119 double fraction = 0;
10120
10121 NEXT;
10122 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10123 XP_ERROR(XPATH_NUMBER_ERROR);
10124 }
10125 while (CUR == '0') {
10126 frac = frac + 1;
10127 NEXT;
10128 }
10129 max = frac + MAX_FRAC;
10130 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10131 v = (CUR - '0');
10132 fraction = fraction * 10 + v;
10133 frac = frac + 1;
10134 NEXT;
10135 }
10136 fraction /= pow(10.0, frac);
10137 ret = ret + fraction;
10138 while ((CUR >= '0') && (CUR <= '9'))
10139 NEXT;
10140 }
10141 if ((CUR == 'e') || (CUR == 'E')) {
10142 NEXT;
10143 if (CUR == '-') {
10144 is_exponent_negative = 1;
10145 NEXT;
10146 } else if (CUR == '+') {
10147 NEXT;
10148 }
10149 while ((CUR >= '0') && (CUR <= '9')) {
10150 if (exponent < 1000000)
10151 exponent = exponent * 10 + (CUR - '0');
10152 NEXT;
10153 }
10154 if (is_exponent_negative)
10155 exponent = -exponent;
10156 ret *= pow(10.0, (double) exponent);
10157 }
10158 num = xmlXPathCacheNewFloat(ctxt->context, ret);
10159 if (num == NULL) {
10160 ctxt->error = XPATH_MEMORY_ERROR;
10161 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10162 NULL) == -1) {
10163 xmlXPathReleaseObject(ctxt->context, num);
10164 }
10165}
10166
10167/**
10168 * xmlXPathParseLiteral:
10169 * @ctxt: the XPath Parser context
10170 *
10171 * Parse a Literal
10172 *
10173 * [29] Literal ::= '"' [^"]* '"'
10174 * | "'" [^']* "'"
10175 *
10176 * Returns the value found or NULL in case of error
10177 */
10178static xmlChar *
10179xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10180 const xmlChar *q;
10181 xmlChar *ret = NULL;
10182
10183 if (CUR == '"') {
10184 NEXT;
10185 q = CUR_PTR;
10186 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10187 NEXT;
10188 if (!IS_CHAR_CH(CUR)) {
10189 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10190 } else {
10191 ret = xmlStrndup(q, CUR_PTR - q);
10192 NEXT;
10193 }
10194 } else if (CUR == '\'') {
10195 NEXT;
10196 q = CUR_PTR;
10197 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10198 NEXT;
10199 if (!IS_CHAR_CH(CUR)) {
10200 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10201 } else {
10202 ret = xmlStrndup(q, CUR_PTR - q);
10203 NEXT;
10204 }
10205 } else {
10206 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10207 }
10208 return(ret);
10209}
10210
10211/**
10212 * xmlXPathCompLiteral:
10213 * @ctxt: the XPath Parser context
10214 *
10215 * Parse a Literal and push it on the stack.
10216 *
10217 * [29] Literal ::= '"' [^"]* '"'
10218 * | "'" [^']* "'"
10219 *
10220 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10221 */
10222static void
10223xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10224 const xmlChar *q;
10225 xmlChar *ret = NULL;
10226 xmlXPathObjectPtr lit;
10227
10228 if (CUR == '"') {
10229 NEXT;
10230 q = CUR_PTR;
10231 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10232 NEXT;
10233 if (!IS_CHAR_CH(CUR)) {
10234 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10235 } else {
10236 ret = xmlStrndup(q, CUR_PTR - q);
10237 NEXT;
10238 }
10239 } else if (CUR == '\'') {
10240 NEXT;
10241 q = CUR_PTR;
10242 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10243 NEXT;
10244 if (!IS_CHAR_CH(CUR)) {
10245 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10246 } else {
10247 ret = xmlStrndup(q, CUR_PTR - q);
10248 NEXT;
10249 }
10250 } else {
10251 XP_ERROR(XPATH_START_LITERAL_ERROR);
10252 }
10253 if (ret == NULL) return;
10254 lit = xmlXPathCacheNewString(ctxt->context, ret);
10255 if (lit == NULL) {
10256 ctxt->error = XPATH_MEMORY_ERROR;
10257 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10258 NULL) == -1) {
10259 xmlXPathReleaseObject(ctxt->context, lit);
10260 }
10261 xmlFree(ret);
10262}
10263
10264/**
10265 * xmlXPathCompVariableReference:
10266 * @ctxt: the XPath Parser context
10267 *
10268 * Parse a VariableReference, evaluate it and push it on the stack.
10269 *
10270 * The variable bindings consist of a mapping from variable names
10271 * to variable values. The value of a variable is an object, which can be
10272 * of any of the types that are possible for the value of an expression,
10273 * and may also be of additional types not specified here.
10274 *
10275 * Early evaluation is possible since:
10276 * The variable bindings [...] used to evaluate a subexpression are
10277 * always the same as those used to evaluate the containing expression.
10278 *
10279 * [36] VariableReference ::= '$' QName
10280 */
10281static void
10282xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10283 xmlChar *name;
10284 xmlChar *prefix;
10285
10286 SKIP_BLANKS;
10287 if (CUR != '$') {
10288 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10289 }
10290 NEXT;
10291 name = xmlXPathParseQName(ctxt, &prefix);
10292 if (name == NULL) {
10293 xmlFree(prefix);
10294 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10295 }
10296 ctxt->comp->last = -1;
10297 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10298 xmlFree(prefix);
10299 xmlFree(name);
10300 }
10301 SKIP_BLANKS;
10302 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10303 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10304 }
10305}
10306
10307/**
10308 * xmlXPathIsNodeType:
10309 * @name: a name string
10310 *
10311 * Is the name given a NodeType one.
10312 *
10313 * [38] NodeType ::= 'comment'
10314 * | 'text'
10315 * | 'processing-instruction'
10316 * | 'node'
10317 *
10318 * Returns 1 if true 0 otherwise
10319 */
10320int
10321xmlXPathIsNodeType(const xmlChar *name) {
10322 if (name == NULL)
10323 return(0);
10324
10325 if (xmlStrEqual(name, BAD_CAST "node"))
10326 return(1);
10327 if (xmlStrEqual(name, BAD_CAST "text"))
10328 return(1);
10329 if (xmlStrEqual(name, BAD_CAST "comment"))
10330 return(1);
10331 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10332 return(1);
10333 return(0);
10334}
10335
10336/**
10337 * xmlXPathCompFunctionCall:
10338 * @ctxt: the XPath Parser context
10339 *
10340 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10341 * [17] Argument ::= Expr
10342 *
10343 * Compile a function call, the evaluation of all arguments are
10344 * pushed on the stack
10345 */
10346static void
10347xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10348 xmlChar *name;
10349 xmlChar *prefix;
10350 int nbargs = 0;
10351 int sort = 1;
10352
10353 name = xmlXPathParseQName(ctxt, &prefix);
10354 if (name == NULL) {
10355 xmlFree(prefix);
10356 XP_ERROR(XPATH_EXPR_ERROR);
10357 }
10358 SKIP_BLANKS;
10359#ifdef DEBUG_EXPR
10360 if (prefix == NULL)
10361 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10362 name);
10363 else
10364 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10365 prefix, name);
10366#endif
10367
10368 if (CUR != '(') {
10369 xmlFree(name);
10370 xmlFree(prefix);
10371 XP_ERROR(XPATH_EXPR_ERROR);
10372 }
10373 NEXT;
10374 SKIP_BLANKS;
10375
10376 /*
10377 * Optimization for count(): we don't need the node-set to be sorted.
10378 */
10379 if ((prefix == NULL) && (name[0] == 'c') &&
10380 xmlStrEqual(name, BAD_CAST "count"))
10381 {
10382 sort = 0;
10383 }
10384 ctxt->comp->last = -1;
10385 if (CUR != ')') {
10386 while (CUR != 0) {
10387 int op1 = ctxt->comp->last;
10388 ctxt->comp->last = -1;
10389 xmlXPathCompileExpr(ctxt, sort);
10390 if (ctxt->error != XPATH_EXPRESSION_OK) {
10391 xmlFree(name);
10392 xmlFree(prefix);
10393 return;
10394 }
10395 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10396 nbargs++;
10397 if (CUR == ')') break;
10398 if (CUR != ',') {
10399 xmlFree(name);
10400 xmlFree(prefix);
10401 XP_ERROR(XPATH_EXPR_ERROR);
10402 }
10403 NEXT;
10404 SKIP_BLANKS;
10405 }
10406 }
10407 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10408 xmlFree(prefix);
10409 xmlFree(name);
10410 }
10411 NEXT;
10412 SKIP_BLANKS;
10413}
10414
10415/**
10416 * xmlXPathCompPrimaryExpr:
10417 * @ctxt: the XPath Parser context
10418 *
10419 * [15] PrimaryExpr ::= VariableReference
10420 * | '(' Expr ')'
10421 * | Literal
10422 * | Number
10423 * | FunctionCall
10424 *
10425 * Compile a primary expression.
10426 */
10427static void
10428xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10429 SKIP_BLANKS;
10430 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10431 else if (CUR == '(') {
10432 NEXT;
10433 SKIP_BLANKS;
10434 xmlXPathCompileExpr(ctxt, 1);
10435 CHECK_ERROR;
10436 if (CUR != ')') {
10437 XP_ERROR(XPATH_EXPR_ERROR);
10438 }
10439 NEXT;
10440 SKIP_BLANKS;
10441 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10442 xmlXPathCompNumber(ctxt);
10443 } else if ((CUR == '\'') || (CUR == '"')) {
10444 xmlXPathCompLiteral(ctxt);
10445 } else {
10446 xmlXPathCompFunctionCall(ctxt);
10447 }
10448 SKIP_BLANKS;
10449}
10450
10451/**
10452 * xmlXPathCompFilterExpr:
10453 * @ctxt: the XPath Parser context
10454 *
10455 * [20] FilterExpr ::= PrimaryExpr
10456 * | FilterExpr Predicate
10457 *
10458 * Compile a filter expression.
10459 * Square brackets are used to filter expressions in the same way that
10460 * they are used in location paths. It is an error if the expression to
10461 * be filtered does not evaluate to a node-set. The context node list
10462 * used for evaluating the expression in square brackets is the node-set
10463 * to be filtered listed in document order.
10464 */
10465
10466static void
10467xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10468 xmlXPathCompPrimaryExpr(ctxt);
10469 CHECK_ERROR;
10470 SKIP_BLANKS;
10471
10472 while (CUR == '[') {
10473 xmlXPathCompPredicate(ctxt, 1);
10474 SKIP_BLANKS;
10475 }
10476
10477
10478}
10479
10480/**
10481 * xmlXPathScanName:
10482 * @ctxt: the XPath Parser context
10483 *
10484 * Trickery: parse an XML name but without consuming the input flow
10485 * Needed to avoid insanity in the parser state.
10486 *
10487 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10488 * CombiningChar | Extender
10489 *
10490 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10491 *
10492 * [6] Names ::= Name (S Name)*
10493 *
10494 * Returns the Name parsed or NULL
10495 */
10496
10497static xmlChar *
10498xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10499 int len = 0, l;
10500 int c;
10501 const xmlChar *cur;
10502 xmlChar *ret;
10503
10504 cur = ctxt->cur;
10505
10506 c = CUR_CHAR(l);
10507 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10508 (!IS_LETTER(c) && (c != '_') &&
10509 (c != ':'))) {
10510 return(NULL);
10511 }
10512
10513 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10514 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10515 (c == '.') || (c == '-') ||
10516 (c == '_') || (c == ':') ||
10517 (IS_COMBINING(c)) ||
10518 (IS_EXTENDER(c)))) {
10519 len += l;
10520 NEXTL(l);
10521 c = CUR_CHAR(l);
10522 }
10523 ret = xmlStrndup(cur, ctxt->cur - cur);
10524 ctxt->cur = cur;
10525 return(ret);
10526}
10527
10528/**
10529 * xmlXPathCompPathExpr:
10530 * @ctxt: the XPath Parser context
10531 *
10532 * [19] PathExpr ::= LocationPath
10533 * | FilterExpr
10534 * | FilterExpr '/' RelativeLocationPath
10535 * | FilterExpr '//' RelativeLocationPath
10536 *
10537 * Compile a path expression.
10538 * The / operator and // operators combine an arbitrary expression
10539 * and a relative location path. It is an error if the expression
10540 * does not evaluate to a node-set.
10541 * The / operator does composition in the same way as when / is
10542 * used in a location path. As in location paths, // is short for
10543 * /descendant-or-self::node()/.
10544 */
10545
10546static void
10547xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10548 int lc = 1; /* Should we branch to LocationPath ? */
10549 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10550
10551 SKIP_BLANKS;
10552 if ((CUR == '$') || (CUR == '(') ||
10553 (IS_ASCII_DIGIT(CUR)) ||
10554 (CUR == '\'') || (CUR == '"') ||
10555 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10556 lc = 0;
10557 } else if (CUR == '*') {
10558 /* relative or absolute location path */
10559 lc = 1;
10560 } else if (CUR == '/') {
10561 /* relative or absolute location path */
10562 lc = 1;
10563 } else if (CUR == '@') {
10564 /* relative abbreviated attribute location path */
10565 lc = 1;
10566 } else if (CUR == '.') {
10567 /* relative abbreviated attribute location path */
10568 lc = 1;
10569 } else {
10570 /*
10571 * Problem is finding if we have a name here whether it's:
10572 * - a nodetype
10573 * - a function call in which case it's followed by '('
10574 * - an axis in which case it's followed by ':'
10575 * - a element name
10576 * We do an a priori analysis here rather than having to
10577 * maintain parsed token content through the recursive function
10578 * calls. This looks uglier but makes the code easier to
10579 * read/write/debug.
10580 */
10581 SKIP_BLANKS;
10582 name = xmlXPathScanName(ctxt);
10583 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10584#ifdef DEBUG_STEP
10585 xmlGenericError(xmlGenericErrorContext,
10586 "PathExpr: Axis\n");
10587#endif
10588 lc = 1;
10589 xmlFree(name);
10590 } else if (name != NULL) {
10591 int len =xmlStrlen(name);
10592
10593
10594 while (NXT(len) != 0) {
10595 if (NXT(len) == '/') {
10596 /* element name */
10597#ifdef DEBUG_STEP
10598 xmlGenericError(xmlGenericErrorContext,
10599 "PathExpr: AbbrRelLocation\n");
10600#endif
10601 lc = 1;
10602 break;
10603 } else if (IS_BLANK_CH(NXT(len))) {
10604 /* ignore blanks */
10605 ;
10606 } else if (NXT(len) == ':') {
10607#ifdef DEBUG_STEP
10608 xmlGenericError(xmlGenericErrorContext,
10609 "PathExpr: AbbrRelLocation\n");
10610#endif
10611 lc = 1;
10612 break;
10613 } else if ((NXT(len) == '(')) {
10614 /* Node Type or Function */
10615 if (xmlXPathIsNodeType(name)) {
10616#ifdef DEBUG_STEP
10617 xmlGenericError(xmlGenericErrorContext,
10618 "PathExpr: Type search\n");
10619#endif
10620 lc = 1;
10621#ifdef LIBXML_XPTR_ENABLED
10622 } else if (ctxt->xptr &&
10623 xmlStrEqual(name, BAD_CAST "range-to")) {
10624 lc = 1;
10625#endif
10626 } else {
10627#ifdef DEBUG_STEP
10628 xmlGenericError(xmlGenericErrorContext,
10629 "PathExpr: function call\n");
10630#endif
10631 lc = 0;
10632 }
10633 break;
10634 } else if ((NXT(len) == '[')) {
10635 /* element name */
10636#ifdef DEBUG_STEP
10637 xmlGenericError(xmlGenericErrorContext,
10638 "PathExpr: AbbrRelLocation\n");
10639#endif
10640 lc = 1;
10641 break;
10642 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10643 (NXT(len) == '=')) {
10644 lc = 1;
10645 break;
10646 } else {
10647 lc = 1;
10648 break;
10649 }
10650 len++;
10651 }
10652 if (NXT(len) == 0) {
10653#ifdef DEBUG_STEP
10654 xmlGenericError(xmlGenericErrorContext,
10655 "PathExpr: AbbrRelLocation\n");
10656#endif
10657 /* element name */
10658 lc = 1;
10659 }
10660 xmlFree(name);
10661 } else {
10662 /* make sure all cases are covered explicitly */
10663 XP_ERROR(XPATH_EXPR_ERROR);
10664 }
10665 }
10666
10667 if (lc) {
10668 if (CUR == '/') {
10669 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10670 } else {
10671 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10672 }
10673 xmlXPathCompLocationPath(ctxt);
10674 } else {
10675 xmlXPathCompFilterExpr(ctxt);
10676 CHECK_ERROR;
10677 if ((CUR == '/') && (NXT(1) == '/')) {
10678 SKIP(2);
10679 SKIP_BLANKS;
10680
10681 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10682 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10683
10684 xmlXPathCompRelativeLocationPath(ctxt);
10685 } else if (CUR == '/') {
10686 xmlXPathCompRelativeLocationPath(ctxt);
10687 }
10688 }
10689 SKIP_BLANKS;
10690}
10691
10692/**
10693 * xmlXPathCompUnionExpr:
10694 * @ctxt: the XPath Parser context
10695 *
10696 * [18] UnionExpr ::= PathExpr
10697 * | UnionExpr '|' PathExpr
10698 *
10699 * Compile an union expression.
10700 */
10701
10702static void
10703xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10704 xmlXPathCompPathExpr(ctxt);
10705 CHECK_ERROR;
10706 SKIP_BLANKS;
10707 while (CUR == '|') {
10708 int op1 = ctxt->comp->last;
10709 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10710
10711 NEXT;
10712 SKIP_BLANKS;
10713 xmlXPathCompPathExpr(ctxt);
10714
10715 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10716
10717 SKIP_BLANKS;
10718 }
10719}
10720
10721/**
10722 * xmlXPathCompUnaryExpr:
10723 * @ctxt: the XPath Parser context
10724 *
10725 * [27] UnaryExpr ::= UnionExpr
10726 * | '-' UnaryExpr
10727 *
10728 * Compile an unary expression.
10729 */
10730
10731static void
10732xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10733 int minus = 0;
10734 int found = 0;
10735
10736 SKIP_BLANKS;
10737 while (CUR == '-') {
10738 minus = 1 - minus;
10739 found = 1;
10740 NEXT;
10741 SKIP_BLANKS;
10742 }
10743
10744 xmlXPathCompUnionExpr(ctxt);
10745 CHECK_ERROR;
10746 if (found) {
10747 if (minus)
10748 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10749 else
10750 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10751 }
10752}
10753
10754/**
10755 * xmlXPathCompMultiplicativeExpr:
10756 * @ctxt: the XPath Parser context
10757 *
10758 * [26] MultiplicativeExpr ::= UnaryExpr
10759 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10760 * | MultiplicativeExpr 'div' UnaryExpr
10761 * | MultiplicativeExpr 'mod' UnaryExpr
10762 * [34] MultiplyOperator ::= '*'
10763 *
10764 * Compile an Additive expression.
10765 */
10766
10767static void
10768xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10769 xmlXPathCompUnaryExpr(ctxt);
10770 CHECK_ERROR;
10771 SKIP_BLANKS;
10772 while ((CUR == '*') ||
10773 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10774 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10775 int op = -1;
10776 int op1 = ctxt->comp->last;
10777
10778 if (CUR == '*') {
10779 op = 0;
10780 NEXT;
10781 } else if (CUR == 'd') {
10782 op = 1;
10783 SKIP(3);
10784 } else if (CUR == 'm') {
10785 op = 2;
10786 SKIP(3);
10787 }
10788 SKIP_BLANKS;
10789 xmlXPathCompUnaryExpr(ctxt);
10790 CHECK_ERROR;
10791 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10792 SKIP_BLANKS;
10793 }
10794}
10795
10796/**
10797 * xmlXPathCompAdditiveExpr:
10798 * @ctxt: the XPath Parser context
10799 *
10800 * [25] AdditiveExpr ::= MultiplicativeExpr
10801 * | AdditiveExpr '+' MultiplicativeExpr
10802 * | AdditiveExpr '-' MultiplicativeExpr
10803 *
10804 * Compile an Additive expression.
10805 */
10806
10807static void
10808xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10809
10810 xmlXPathCompMultiplicativeExpr(ctxt);
10811 CHECK_ERROR;
10812 SKIP_BLANKS;
10813 while ((CUR == '+') || (CUR == '-')) {
10814 int plus;
10815 int op1 = ctxt->comp->last;
10816
10817 if (CUR == '+') plus = 1;
10818 else plus = 0;
10819 NEXT;
10820 SKIP_BLANKS;
10821 xmlXPathCompMultiplicativeExpr(ctxt);
10822 CHECK_ERROR;
10823 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10824 SKIP_BLANKS;
10825 }
10826}
10827
10828/**
10829 * xmlXPathCompRelationalExpr:
10830 * @ctxt: the XPath Parser context
10831 *
10832 * [24] RelationalExpr ::= AdditiveExpr
10833 * | RelationalExpr '<' AdditiveExpr
10834 * | RelationalExpr '>' AdditiveExpr
10835 * | RelationalExpr '<=' AdditiveExpr
10836 * | RelationalExpr '>=' AdditiveExpr
10837 *
10838 * A <= B > C is allowed ? Answer from James, yes with
10839 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10840 * which is basically what got implemented.
10841 *
10842 * Compile a Relational expression, then push the result
10843 * on the stack
10844 */
10845
10846static void
10847xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10848 xmlXPathCompAdditiveExpr(ctxt);
10849 CHECK_ERROR;
10850 SKIP_BLANKS;
10851 while ((CUR == '<') || (CUR == '>')) {
10852 int inf, strict;
10853 int op1 = ctxt->comp->last;
10854
10855 if (CUR == '<') inf = 1;
10856 else inf = 0;
10857 if (NXT(1) == '=') strict = 0;
10858 else strict = 1;
10859 NEXT;
10860 if (!strict) NEXT;
10861 SKIP_BLANKS;
10862 xmlXPathCompAdditiveExpr(ctxt);
10863 CHECK_ERROR;
10864 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10865 SKIP_BLANKS;
10866 }
10867}
10868
10869/**
10870 * xmlXPathCompEqualityExpr:
10871 * @ctxt: the XPath Parser context
10872 *
10873 * [23] EqualityExpr ::= RelationalExpr
10874 * | EqualityExpr '=' RelationalExpr
10875 * | EqualityExpr '!=' RelationalExpr
10876 *
10877 * A != B != C is allowed ? Answer from James, yes with
10878 * (RelationalExpr = RelationalExpr) = RelationalExpr
10879 * (RelationalExpr != RelationalExpr) != RelationalExpr
10880 * which is basically what got implemented.
10881 *
10882 * Compile an Equality expression.
10883 *
10884 */
10885static void
10886xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10887 xmlXPathCompRelationalExpr(ctxt);
10888 CHECK_ERROR;
10889 SKIP_BLANKS;
10890 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10891 int eq;
10892 int op1 = ctxt->comp->last;
10893
10894 if (CUR == '=') eq = 1;
10895 else eq = 0;
10896 NEXT;
10897 if (!eq) NEXT;
10898 SKIP_BLANKS;
10899 xmlXPathCompRelationalExpr(ctxt);
10900 CHECK_ERROR;
10901 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10902 SKIP_BLANKS;
10903 }
10904}
10905
10906/**
10907 * xmlXPathCompAndExpr:
10908 * @ctxt: the XPath Parser context
10909 *
10910 * [22] AndExpr ::= EqualityExpr
10911 * | AndExpr 'and' EqualityExpr
10912 *
10913 * Compile an AND expression.
10914 *
10915 */
10916static void
10917xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10918 xmlXPathCompEqualityExpr(ctxt);
10919 CHECK_ERROR;
10920 SKIP_BLANKS;
10921 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10922 int op1 = ctxt->comp->last;
10923 SKIP(3);
10924 SKIP_BLANKS;
10925 xmlXPathCompEqualityExpr(ctxt);
10926 CHECK_ERROR;
10927 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10928 SKIP_BLANKS;
10929 }
10930}
10931
10932/**
10933 * xmlXPathCompileExpr:
10934 * @ctxt: the XPath Parser context
10935 *
10936 * [14] Expr ::= OrExpr
10937 * [21] OrExpr ::= AndExpr
10938 * | OrExpr 'or' AndExpr
10939 *
10940 * Parse and compile an expression
10941 */
10942static void
10943xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10944 xmlXPathContextPtr xpctxt = ctxt->context;
10945
10946 if (xpctxt != NULL) {
10947 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10948 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10949 /*
10950 * Parsing a single '(' pushes about 10 functions on the call stack
10951 * before recursing!
10952 */
10953 xpctxt->depth += 10;
10954 }
10955
10956 xmlXPathCompAndExpr(ctxt);
10957 CHECK_ERROR;
10958 SKIP_BLANKS;
10959 while ((CUR == 'o') && (NXT(1) == 'r')) {
10960 int op1 = ctxt->comp->last;
10961 SKIP(2);
10962 SKIP_BLANKS;
10963 xmlXPathCompAndExpr(ctxt);
10964 CHECK_ERROR;
10965 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10966 SKIP_BLANKS;
10967 }
10968 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10969 /* more ops could be optimized too */
10970 /*
10971 * This is the main place to eliminate sorting for
10972 * operations which don't require a sorted node-set.
10973 * E.g. count().
10974 */
10975 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10976 }
10977
10978 if (xpctxt != NULL)
10979 xpctxt->depth -= 10;
10980}
10981
10982/**
10983 * xmlXPathCompPredicate:
10984 * @ctxt: the XPath Parser context
10985 * @filter: act as a filter
10986 *
10987 * [8] Predicate ::= '[' PredicateExpr ']'
10988 * [9] PredicateExpr ::= Expr
10989 *
10990 * Compile a predicate expression
10991 */
10992static void
10993xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10994 int op1 = ctxt->comp->last;
10995
10996 SKIP_BLANKS;
10997 if (CUR != '[') {
10998 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10999 }
11000 NEXT;
11001 SKIP_BLANKS;
11002
11003 ctxt->comp->last = -1;
11004 /*
11005 * This call to xmlXPathCompileExpr() will deactivate sorting
11006 * of the predicate result.
11007 * TODO: Sorting is still activated for filters, since I'm not
11008 * sure if needed. Normally sorting should not be needed, since
11009 * a filter can only diminish the number of items in a sequence,
11010 * but won't change its order; so if the initial sequence is sorted,
11011 * subsequent sorting is not needed.
11012 */
11013 if (! filter)
11014 xmlXPathCompileExpr(ctxt, 0);
11015 else
11016 xmlXPathCompileExpr(ctxt, 1);
11017 CHECK_ERROR;
11018
11019 if (CUR != ']') {
11020 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11021 }
11022
11023 if (filter)
11024 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11025 else
11026 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11027
11028 NEXT;
11029 SKIP_BLANKS;
11030}
11031
11032/**
11033 * xmlXPathCompNodeTest:
11034 * @ctxt: the XPath Parser context
11035 * @test: pointer to a xmlXPathTestVal
11036 * @type: pointer to a xmlXPathTypeVal
11037 * @prefix: placeholder for a possible name prefix
11038 *
11039 * [7] NodeTest ::= NameTest
11040 * | NodeType '(' ')'
11041 * | 'processing-instruction' '(' Literal ')'
11042 *
11043 * [37] NameTest ::= '*'
11044 * | NCName ':' '*'
11045 * | QName
11046 * [38] NodeType ::= 'comment'
11047 * | 'text'
11048 * | 'processing-instruction'
11049 * | 'node'
11050 *
11051 * Returns the name found and updates @test, @type and @prefix appropriately
11052 */
11053static xmlChar *
11054xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11055 xmlXPathTypeVal *type, xmlChar **prefix,
11056 xmlChar *name) {
11057 int blanks;
11058
11059 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11060 STRANGE;
11061 return(NULL);
11062 }
11063 *type = (xmlXPathTypeVal) 0;
11064 *test = (xmlXPathTestVal) 0;
11065 *prefix = NULL;
11066 SKIP_BLANKS;
11067
11068 if ((name == NULL) && (CUR == '*')) {
11069 /*
11070 * All elements
11071 */
11072 NEXT;
11073 *test = NODE_TEST_ALL;
11074 return(NULL);
11075 }
11076
11077 if (name == NULL)
11078 name = xmlXPathParseNCName(ctxt);
11079 if (name == NULL) {
11080 XP_ERRORNULL(XPATH_EXPR_ERROR);
11081 }
11082
11083 blanks = IS_BLANK_CH(CUR);
11084 SKIP_BLANKS;
11085 if (CUR == '(') {
11086 NEXT;
11087 /*
11088 * NodeType or PI search
11089 */
11090 if (xmlStrEqual(name, BAD_CAST "comment"))
11091 *type = NODE_TYPE_COMMENT;
11092 else if (xmlStrEqual(name, BAD_CAST "node"))
11093 *type = NODE_TYPE_NODE;
11094 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11095 *type = NODE_TYPE_PI;
11096 else if (xmlStrEqual(name, BAD_CAST "text"))
11097 *type = NODE_TYPE_TEXT;
11098 else {
11099 if (name != NULL)
11100 xmlFree(name);
11101 XP_ERRORNULL(XPATH_EXPR_ERROR);
11102 }
11103
11104 *test = NODE_TEST_TYPE;
11105
11106 SKIP_BLANKS;
11107 if (*type == NODE_TYPE_PI) {
11108 /*
11109 * Specific case: search a PI by name.
11110 */
11111 if (name != NULL)
11112 xmlFree(name);
11113 name = NULL;
11114 if (CUR != ')') {
11115 name = xmlXPathParseLiteral(ctxt);
11116 if (name == NULL) {
11117 XP_ERRORNULL(XPATH_EXPR_ERROR);
11118 }
11119 *test = NODE_TEST_PI;
11120 SKIP_BLANKS;
11121 }
11122 }
11123 if (CUR != ')') {
11124 if (name != NULL)
11125 xmlFree(name);
11126 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11127 }
11128 NEXT;
11129 return(name);
11130 }
11131 *test = NODE_TEST_NAME;
11132 if ((!blanks) && (CUR == ':')) {
11133 NEXT;
11134
11135 /*
11136 * Since currently the parser context don't have a
11137 * namespace list associated:
11138 * The namespace name for this prefix can be computed
11139 * only at evaluation time. The compilation is done
11140 * outside of any context.
11141 */
11142#if 0
11143 *prefix = xmlXPathNsLookup(ctxt->context, name);
11144 if (name != NULL)
11145 xmlFree(name);
11146 if (*prefix == NULL) {
11147 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11148 }
11149#else
11150 *prefix = name;
11151#endif
11152
11153 if (CUR == '*') {
11154 /*
11155 * All elements
11156 */
11157 NEXT;
11158 *test = NODE_TEST_ALL;
11159 return(NULL);
11160 }
11161
11162 name = xmlXPathParseNCName(ctxt);
11163 if (name == NULL) {
11164 XP_ERRORNULL(XPATH_EXPR_ERROR);
11165 }
11166 }
11167 return(name);
11168}
11169
11170/**
11171 * xmlXPathIsAxisName:
11172 * @name: a preparsed name token
11173 *
11174 * [6] AxisName ::= 'ancestor'
11175 * | 'ancestor-or-self'
11176 * | 'attribute'
11177 * | 'child'
11178 * | 'descendant'
11179 * | 'descendant-or-self'
11180 * | 'following'
11181 * | 'following-sibling'
11182 * | 'namespace'
11183 * | 'parent'
11184 * | 'preceding'
11185 * | 'preceding-sibling'
11186 * | 'self'
11187 *
11188 * Returns the axis or 0
11189 */
11190static xmlXPathAxisVal
11191xmlXPathIsAxisName(const xmlChar *name) {
11192 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11193 switch (name[0]) {
11194 case 'a':
11195 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11196 ret = AXIS_ANCESTOR;
11197 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11198 ret = AXIS_ANCESTOR_OR_SELF;
11199 if (xmlStrEqual(name, BAD_CAST "attribute"))
11200 ret = AXIS_ATTRIBUTE;
11201 break;
11202 case 'c':
11203 if (xmlStrEqual(name, BAD_CAST "child"))
11204 ret = AXIS_CHILD;
11205 break;
11206 case 'd':
11207 if (xmlStrEqual(name, BAD_CAST "descendant"))
11208 ret = AXIS_DESCENDANT;
11209 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11210 ret = AXIS_DESCENDANT_OR_SELF;
11211 break;
11212 case 'f':
11213 if (xmlStrEqual(name, BAD_CAST "following"))
11214 ret = AXIS_FOLLOWING;
11215 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11216 ret = AXIS_FOLLOWING_SIBLING;
11217 break;
11218 case 'n':
11219 if (xmlStrEqual(name, BAD_CAST "namespace"))
11220 ret = AXIS_NAMESPACE;
11221 break;
11222 case 'p':
11223 if (xmlStrEqual(name, BAD_CAST "parent"))
11224 ret = AXIS_PARENT;
11225 if (xmlStrEqual(name, BAD_CAST "preceding"))
11226 ret = AXIS_PRECEDING;
11227 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11228 ret = AXIS_PRECEDING_SIBLING;
11229 break;
11230 case 's':
11231 if (xmlStrEqual(name, BAD_CAST "self"))
11232 ret = AXIS_SELF;
11233 break;
11234 }
11235 return(ret);
11236}
11237
11238/**
11239 * xmlXPathCompStep:
11240 * @ctxt: the XPath Parser context
11241 *
11242 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11243 * | AbbreviatedStep
11244 *
11245 * [12] AbbreviatedStep ::= '.' | '..'
11246 *
11247 * [5] AxisSpecifier ::= AxisName '::'
11248 * | AbbreviatedAxisSpecifier
11249 *
11250 * [13] AbbreviatedAxisSpecifier ::= '@'?
11251 *
11252 * Modified for XPtr range support as:
11253 *
11254 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11255 * | AbbreviatedStep
11256 * | 'range-to' '(' Expr ')' Predicate*
11257 *
11258 * Compile one step in a Location Path
11259 * A location step of . is short for self::node(). This is
11260 * particularly useful in conjunction with //. For example, the
11261 * location path .//para is short for
11262 * self::node()/descendant-or-self::node()/child::para
11263 * and so will select all para descendant elements of the context
11264 * node.
11265 * Similarly, a location step of .. is short for parent::node().
11266 * For example, ../title is short for parent::node()/child::title
11267 * and so will select the title children of the parent of the context
11268 * node.
11269 */
11270static void
11271xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11272#ifdef LIBXML_XPTR_ENABLED
11273 int rangeto = 0;
11274 int op2 = -1;
11275#endif
11276
11277 SKIP_BLANKS;
11278 if ((CUR == '.') && (NXT(1) == '.')) {
11279 SKIP(2);
11280 SKIP_BLANKS;
11281 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11282 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11283 } else if (CUR == '.') {
11284 NEXT;
11285 SKIP_BLANKS;
11286 } else {
11287 xmlChar *name = NULL;
11288 xmlChar *prefix = NULL;
11289 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11290 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11291 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11292 int op1;
11293
11294 /*
11295 * The modification needed for XPointer change to the production
11296 */
11297#ifdef LIBXML_XPTR_ENABLED
11298 if (ctxt->xptr) {
11299 name = xmlXPathParseNCName(ctxt);
11300 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11301 op2 = ctxt->comp->last;
11302 xmlFree(name);
11303 SKIP_BLANKS;
11304 if (CUR != '(') {
11305 XP_ERROR(XPATH_EXPR_ERROR);
11306 }
11307 NEXT;
11308 SKIP_BLANKS;
11309
11310 xmlXPathCompileExpr(ctxt, 1);
11311 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11312 CHECK_ERROR;
11313
11314 SKIP_BLANKS;
11315 if (CUR != ')') {
11316 XP_ERROR(XPATH_EXPR_ERROR);
11317 }
11318 NEXT;
11319 rangeto = 1;
11320 goto eval_predicates;
11321 }
11322 }
11323#endif
11324 if (CUR == '*') {
11325 axis = AXIS_CHILD;
11326 } else {
11327 if (name == NULL)
11328 name = xmlXPathParseNCName(ctxt);
11329 if (name != NULL) {
11330 axis = xmlXPathIsAxisName(name);
11331 if (axis != 0) {
11332 SKIP_BLANKS;
11333 if ((CUR == ':') && (NXT(1) == ':')) {
11334 SKIP(2);
11335 xmlFree(name);
11336 name = NULL;
11337 } else {
11338 /* an element name can conflict with an axis one :-\ */
11339 axis = AXIS_CHILD;
11340 }
11341 } else {
11342 axis = AXIS_CHILD;
11343 }
11344 } else if (CUR == '@') {
11345 NEXT;
11346 axis = AXIS_ATTRIBUTE;
11347 } else {
11348 axis = AXIS_CHILD;
11349 }
11350 }
11351
11352 if (ctxt->error != XPATH_EXPRESSION_OK) {
11353 xmlFree(name);
11354 return;
11355 }
11356
11357 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11358 if (test == 0)
11359 return;
11360
11361 if ((prefix != NULL) && (ctxt->context != NULL) &&
11362 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11363 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11364 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11365 }
11366 }
11367#ifdef DEBUG_STEP
11368 xmlGenericError(xmlGenericErrorContext,
11369 "Basis : computing new set\n");
11370#endif
11371
11372#ifdef DEBUG_STEP
11373 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11374 if (ctxt->value == NULL)
11375 xmlGenericError(xmlGenericErrorContext, "no value\n");
11376 else if (ctxt->value->nodesetval == NULL)
11377 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11378 else
11379 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11380#endif
11381
11382#ifdef LIBXML_XPTR_ENABLED
11383eval_predicates:
11384#endif
11385 op1 = ctxt->comp->last;
11386 ctxt->comp->last = -1;
11387
11388 SKIP_BLANKS;
11389 while (CUR == '[') {
11390 xmlXPathCompPredicate(ctxt, 0);
11391 }
11392
11393#ifdef LIBXML_XPTR_ENABLED
11394 if (rangeto) {
11395 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11396 } else
11397#endif
11398 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11399 test, type, (void *)prefix, (void *)name) == -1) {
11400 xmlFree(prefix);
11401 xmlFree(name);
11402 }
11403 }
11404#ifdef DEBUG_STEP
11405 xmlGenericError(xmlGenericErrorContext, "Step : ");
11406 if (ctxt->value == NULL)
11407 xmlGenericError(xmlGenericErrorContext, "no value\n");
11408 else if (ctxt->value->nodesetval == NULL)
11409 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11410 else
11411 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11412 ctxt->value->nodesetval);
11413#endif
11414}
11415
11416/**
11417 * xmlXPathCompRelativeLocationPath:
11418 * @ctxt: the XPath Parser context
11419 *
11420 * [3] RelativeLocationPath ::= Step
11421 * | RelativeLocationPath '/' Step
11422 * | AbbreviatedRelativeLocationPath
11423 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11424 *
11425 * Compile a relative location path.
11426 */
11427static void
11428xmlXPathCompRelativeLocationPath
11429(xmlXPathParserContextPtr ctxt) {
11430 SKIP_BLANKS;
11431 if ((CUR == '/') && (NXT(1) == '/')) {
11432 SKIP(2);
11433 SKIP_BLANKS;
11434 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11435 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11436 } else if (CUR == '/') {
11437 NEXT;
11438 SKIP_BLANKS;
11439 }
11440 xmlXPathCompStep(ctxt);
11441 CHECK_ERROR;
11442 SKIP_BLANKS;
11443 while (CUR == '/') {
11444 if ((CUR == '/') && (NXT(1) == '/')) {
11445 SKIP(2);
11446 SKIP_BLANKS;
11447 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11448 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11449 xmlXPathCompStep(ctxt);
11450 } else if (CUR == '/') {
11451 NEXT;
11452 SKIP_BLANKS;
11453 xmlXPathCompStep(ctxt);
11454 }
11455 SKIP_BLANKS;
11456 }
11457}
11458
11459/**
11460 * xmlXPathCompLocationPath:
11461 * @ctxt: the XPath Parser context
11462 *
11463 * [1] LocationPath ::= RelativeLocationPath
11464 * | AbsoluteLocationPath
11465 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11466 * | AbbreviatedAbsoluteLocationPath
11467 * [10] AbbreviatedAbsoluteLocationPath ::=
11468 * '//' RelativeLocationPath
11469 *
11470 * Compile a location path
11471 *
11472 * // is short for /descendant-or-self::node()/. For example,
11473 * //para is short for /descendant-or-self::node()/child::para and
11474 * so will select any para element in the document (even a para element
11475 * that is a document element will be selected by //para since the
11476 * document element node is a child of the root node); div//para is
11477 * short for div/descendant-or-self::node()/child::para and so will
11478 * select all para descendants of div children.
11479 */
11480static void
11481xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11482 SKIP_BLANKS;
11483 if (CUR != '/') {
11484 xmlXPathCompRelativeLocationPath(ctxt);
11485 } else {
11486 while (CUR == '/') {
11487 if ((CUR == '/') && (NXT(1) == '/')) {
11488 SKIP(2);
11489 SKIP_BLANKS;
11490 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11491 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11492 xmlXPathCompRelativeLocationPath(ctxt);
11493 } else if (CUR == '/') {
11494 NEXT;
11495 SKIP_BLANKS;
11496 if ((CUR != 0 ) &&
11497 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11498 (CUR == '@') || (CUR == '*')))
11499 xmlXPathCompRelativeLocationPath(ctxt);
11500 }
11501 CHECK_ERROR;
11502 }
11503 }
11504}
11505
11506/************************************************************************
11507 * *
11508 * XPath precompiled expression evaluation *
11509 * *
11510 ************************************************************************/
11511
11512static int
11513xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11514
11515#ifdef DEBUG_STEP
11516static void
11517xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11518 int nbNodes)
11519{
11520 xmlGenericError(xmlGenericErrorContext, "new step : ");
11521 switch (op->value) {
11522 case AXIS_ANCESTOR:
11523 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11524 break;
11525 case AXIS_ANCESTOR_OR_SELF:
11526 xmlGenericError(xmlGenericErrorContext,
11527 "axis 'ancestors-or-self' ");
11528 break;
11529 case AXIS_ATTRIBUTE:
11530 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11531 break;
11532 case AXIS_CHILD:
11533 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11534 break;
11535 case AXIS_DESCENDANT:
11536 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11537 break;
11538 case AXIS_DESCENDANT_OR_SELF:
11539 xmlGenericError(xmlGenericErrorContext,
11540 "axis 'descendant-or-self' ");
11541 break;
11542 case AXIS_FOLLOWING:
11543 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11544 break;
11545 case AXIS_FOLLOWING_SIBLING:
11546 xmlGenericError(xmlGenericErrorContext,
11547 "axis 'following-siblings' ");
11548 break;
11549 case AXIS_NAMESPACE:
11550 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11551 break;
11552 case AXIS_PARENT:
11553 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11554 break;
11555 case AXIS_PRECEDING:
11556 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11557 break;
11558 case AXIS_PRECEDING_SIBLING:
11559 xmlGenericError(xmlGenericErrorContext,
11560 "axis 'preceding-sibling' ");
11561 break;
11562 case AXIS_SELF:
11563 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11564 break;
11565 }
11566 xmlGenericError(xmlGenericErrorContext,
11567 " context contains %d nodes\n", nbNodes);
11568 switch (op->value2) {
11569 case NODE_TEST_NONE:
11570 xmlGenericError(xmlGenericErrorContext,
11571 " searching for none !!!\n");
11572 break;
11573 case NODE_TEST_TYPE:
11574 xmlGenericError(xmlGenericErrorContext,
11575 " searching for type %d\n", op->value3);
11576 break;
11577 case NODE_TEST_PI:
11578 xmlGenericError(xmlGenericErrorContext,
11579 " searching for PI !!!\n");
11580 break;
11581 case NODE_TEST_ALL:
11582 xmlGenericError(xmlGenericErrorContext,
11583 " searching for *\n");
11584 break;
11585 case NODE_TEST_NS:
11586 xmlGenericError(xmlGenericErrorContext,
11587 " searching for namespace %s\n",
11588 op->value5);
11589 break;
11590 case NODE_TEST_NAME:
11591 xmlGenericError(xmlGenericErrorContext,
11592 " searching for name %s\n", op->value5);
11593 if (op->value4)
11594 xmlGenericError(xmlGenericErrorContext,
11595 " with namespace %s\n", op->value4);
11596 break;
11597 }
11598 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11599}
11600#endif /* DEBUG_STEP */
11601
11602/**
11603 * xmlXPathNodeSetFilter:
11604 * @ctxt: the XPath Parser context
11605 * @set: the node set to filter
11606 * @filterOpIndex: the index of the predicate/filter op
11607 * @minPos: minimum position in the filtered set (1-based)
11608 * @maxPos: maximum position in the filtered set (1-based)
11609 * @hasNsNodes: true if the node set may contain namespace nodes
11610 *
11611 * Filter a node set, keeping only nodes for which the predicate expression
11612 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11613 * filtered result.
11614 */
11615static void
11616xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11617 xmlNodeSetPtr set,
11618 int filterOpIndex,
11619 int minPos, int maxPos,
11620 int hasNsNodes)
11621{
11622 xmlXPathContextPtr xpctxt;
11623 xmlNodePtr oldnode;
11624 xmlDocPtr olddoc;
11625 xmlXPathStepOpPtr filterOp;
11626 int oldcs, oldpp;
11627 int i, j, pos;
11628
11629 if ((set == NULL) || (set->nodeNr == 0))
11630 return;
11631
11632 /*
11633 * Check if the node set contains a sufficient number of nodes for
11634 * the requested range.
11635 */
11636 if (set->nodeNr < minPos) {
11637 xmlXPathNodeSetClear(set, hasNsNodes);
11638 return;
11639 }
11640
11641 xpctxt = ctxt->context;
11642 oldnode = xpctxt->node;
11643 olddoc = xpctxt->doc;
11644 oldcs = xpctxt->contextSize;
11645 oldpp = xpctxt->proximityPosition;
11646 filterOp = &ctxt->comp->steps[filterOpIndex];
11647
11648 xpctxt->contextSize = set->nodeNr;
11649
11650 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11651 xmlNodePtr node = set->nodeTab[i];
11652 int res;
11653
11654 xpctxt->node = node;
11655 xpctxt->proximityPosition = i + 1;
11656
11657 /*
11658 * Also set the xpath document in case things like
11659 * key() are evaluated in the predicate.
11660 *
11661 * TODO: Get real doc for namespace nodes.
11662 */
11663 if ((node->type != XML_NAMESPACE_DECL) &&
11664 (node->doc != NULL))
11665 xpctxt->doc = node->doc;
11666
11667 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11668
11669 if (ctxt->error != XPATH_EXPRESSION_OK)
11670 break;
11671 if (res < 0) {
11672 /* Shouldn't happen */
11673 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11674 break;
11675 }
11676
11677 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11678 if (i != j) {
11679 set->nodeTab[j] = node;
11680 set->nodeTab[i] = NULL;
11681 }
11682
11683 j += 1;
11684 } else {
11685 /* Remove the entry from the initial node set. */
11686 set->nodeTab[i] = NULL;
11687 if (node->type == XML_NAMESPACE_DECL)
11688 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11689 }
11690
11691 if (res != 0) {
11692 if (pos == maxPos) {
11693 i += 1;
11694 break;
11695 }
11696
11697 pos += 1;
11698 }
11699 }
11700
11701 /* Free remaining nodes. */
11702 if (hasNsNodes) {
11703 for (; i < set->nodeNr; i++) {
11704 xmlNodePtr node = set->nodeTab[i];
11705 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11706 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11707 }
11708 }
11709
11710 set->nodeNr = j;
11711
11712 /* If too many elements were removed, shrink table to preserve memory. */
11713 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11714 (set->nodeNr < set->nodeMax / 2)) {
11715 xmlNodePtr *tmp;
11716 int nodeMax = set->nodeNr;
11717
11718 if (nodeMax < XML_NODESET_DEFAULT)
11719 nodeMax = XML_NODESET_DEFAULT;
11720 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11721 nodeMax * sizeof(xmlNodePtr));
11722 if (tmp == NULL) {
11723 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11724 } else {
11725 set->nodeTab = tmp;
11726 set->nodeMax = nodeMax;
11727 }
11728 }
11729
11730 xpctxt->node = oldnode;
11731 xpctxt->doc = olddoc;
11732 xpctxt->contextSize = oldcs;
11733 xpctxt->proximityPosition = oldpp;
11734}
11735
11736#ifdef LIBXML_XPTR_ENABLED
11737/**
11738 * xmlXPathLocationSetFilter:
11739 * @ctxt: the XPath Parser context
11740 * @locset: the location set to filter
11741 * @filterOpIndex: the index of the predicate/filter op
11742 * @minPos: minimum position in the filtered set (1-based)
11743 * @maxPos: maximum position in the filtered set (1-based)
11744 *
11745 * Filter a location set, keeping only nodes for which the predicate
11746 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11747 * in the filtered result.
11748 */
11749static void
11750xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11751 xmlLocationSetPtr locset,
11752 int filterOpIndex,
11753 int minPos, int maxPos)
11754{
11755 xmlXPathContextPtr xpctxt;
11756 xmlNodePtr oldnode;
11757 xmlDocPtr olddoc;
11758 xmlXPathStepOpPtr filterOp;
11759 int oldcs, oldpp;
11760 int i, j, pos;
11761
11762 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11763 return;
11764
11765 xpctxt = ctxt->context;
11766 oldnode = xpctxt->node;
11767 olddoc = xpctxt->doc;
11768 oldcs = xpctxt->contextSize;
11769 oldpp = xpctxt->proximityPosition;
11770 filterOp = &ctxt->comp->steps[filterOpIndex];
11771
11772 xpctxt->contextSize = locset->locNr;
11773
11774 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11775 xmlNodePtr contextNode = locset->locTab[i]->user;
11776 int res;
11777
11778 xpctxt->node = contextNode;
11779 xpctxt->proximityPosition = i + 1;
11780
11781 /*
11782 * Also set the xpath document in case things like
11783 * key() are evaluated in the predicate.
11784 *
11785 * TODO: Get real doc for namespace nodes.
11786 */
11787 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11788 (contextNode->doc != NULL))
11789 xpctxt->doc = contextNode->doc;
11790
11791 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11792
11793 if (ctxt->error != XPATH_EXPRESSION_OK)
11794 break;
11795 if (res < 0) {
11796 /* Shouldn't happen */
11797 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11798 break;
11799 }
11800
11801 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11802 if (i != j) {
11803 locset->locTab[j] = locset->locTab[i];
11804 locset->locTab[i] = NULL;
11805 }
11806
11807 j += 1;
11808 } else {
11809 /* Remove the entry from the initial location set. */
11810 xmlXPathFreeObject(locset->locTab[i]);
11811 locset->locTab[i] = NULL;
11812 }
11813
11814 if (res != 0) {
11815 if (pos == maxPos) {
11816 i += 1;
11817 break;
11818 }
11819
11820 pos += 1;
11821 }
11822 }
11823
11824 /* Free remaining nodes. */
11825 for (; i < locset->locNr; i++)
11826 xmlXPathFreeObject(locset->locTab[i]);
11827
11828 locset->locNr = j;
11829
11830 /* If too many elements were removed, shrink table to preserve memory. */
11831 if ((locset->locMax > XML_NODESET_DEFAULT) &&
11832 (locset->locNr < locset->locMax / 2)) {
11833 xmlXPathObjectPtr *tmp;
11834 int locMax = locset->locNr;
11835
11836 if (locMax < XML_NODESET_DEFAULT)
11837 locMax = XML_NODESET_DEFAULT;
11838 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11839 locMax * sizeof(xmlXPathObjectPtr));
11840 if (tmp == NULL) {
11841 xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11842 } else {
11843 locset->locTab = tmp;
11844 locset->locMax = locMax;
11845 }
11846 }
11847
11848 xpctxt->node = oldnode;
11849 xpctxt->doc = olddoc;
11850 xpctxt->contextSize = oldcs;
11851 xpctxt->proximityPosition = oldpp;
11852}
11853#endif /* LIBXML_XPTR_ENABLED */
11854
11855/**
11856 * xmlXPathCompOpEvalPredicate:
11857 * @ctxt: the XPath Parser context
11858 * @op: the predicate op
11859 * @set: the node set to filter
11860 * @minPos: minimum position in the filtered set (1-based)
11861 * @maxPos: maximum position in the filtered set (1-based)
11862 * @hasNsNodes: true if the node set may contain namespace nodes
11863 *
11864 * Filter a node set, keeping only nodes for which the sequence of predicate
11865 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11866 * in the filtered result.
11867 */
11868static void
11869xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11870 xmlXPathStepOpPtr op,
11871 xmlNodeSetPtr set,
11872 int minPos, int maxPos,
11873 int hasNsNodes)
11874{
11875 if (op->ch1 != -1) {
11876 xmlXPathCompExprPtr comp = ctxt->comp;
11877 /*
11878 * Process inner predicates first.
11879 */
11880 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11881 xmlGenericError(xmlGenericErrorContext,
11882 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11883 XP_ERROR(XPATH_INVALID_OPERAND);
11884 }
11885 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11886 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11887 ctxt->context->depth += 1;
11888 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11889 1, set->nodeNr, hasNsNodes);
11890 ctxt->context->depth -= 1;
11891 CHECK_ERROR;
11892 }
11893
11894 if (op->ch2 != -1)
11895 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11896}
11897
11898static int
11899xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11900 xmlXPathStepOpPtr op,
11901 int *maxPos)
11902{
11903
11904 xmlXPathStepOpPtr exprOp;
11905
11906 /*
11907 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11908 */
11909
11910 /*
11911 * If not -1, then ch1 will point to:
11912 * 1) For predicates (XPATH_OP_PREDICATE):
11913 * - an inner predicate operator
11914 * 2) For filters (XPATH_OP_FILTER):
11915 * - an inner filter operator OR
11916 * - an expression selecting the node set.
11917 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11918 */
11919 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11920 return(0);
11921
11922 if (op->ch2 != -1) {
11923 exprOp = &ctxt->comp->steps[op->ch2];
11924 } else
11925 return(0);
11926
11927 if ((exprOp != NULL) &&
11928 (exprOp->op == XPATH_OP_VALUE) &&
11929 (exprOp->value4 != NULL) &&
11930 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11931 {
11932 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11933
11934 /*
11935 * We have a "[n]" predicate here.
11936 * TODO: Unfortunately this simplistic test here is not
11937 * able to detect a position() predicate in compound
11938 * expressions like "[@attr = 'a" and position() = 1],
11939 * and even not the usage of position() in
11940 * "[position() = 1]"; thus - obviously - a position-range,
11941 * like it "[position() < 5]", is also not detected.
11942 * Maybe we could rewrite the AST to ease the optimization.
11943 */
11944
11945 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11946 *maxPos = (int) floatval;
11947 if (floatval == (double) *maxPos)
11948 return(1);
11949 }
11950 }
11951 return(0);
11952}
11953
11954static int
11955xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11956 xmlXPathStepOpPtr op,
11957 xmlNodePtr * first, xmlNodePtr * last,
11958 int toBool)
11959{
11960
11961#define XP_TEST_HIT \
11962 if (hasAxisRange != 0) { \
11963 if (++pos == maxPos) { \
11964 if (addNode(seq, cur) < 0) \
11965 ctxt->error = XPATH_MEMORY_ERROR; \
11966 goto axis_range_end; } \
11967 } else { \
11968 if (addNode(seq, cur) < 0) \
11969 ctxt->error = XPATH_MEMORY_ERROR; \
11970 if (breakOnFirstHit) goto first_hit; }
11971
11972#define XP_TEST_HIT_NS \
11973 if (hasAxisRange != 0) { \
11974 if (++pos == maxPos) { \
11975 hasNsNodes = 1; \
11976 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11977 ctxt->error = XPATH_MEMORY_ERROR; \
11978 goto axis_range_end; } \
11979 } else { \
11980 hasNsNodes = 1; \
11981 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11982 ctxt->error = XPATH_MEMORY_ERROR; \
11983 if (breakOnFirstHit) goto first_hit; }
11984
11985 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11986 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11987 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11988 const xmlChar *prefix = op->value4;
11989 const xmlChar *name = op->value5;
11990 const xmlChar *URI = NULL;
11991
11992#ifdef DEBUG_STEP
11993 int nbMatches = 0, prevMatches = 0;
11994#endif
11995 int total = 0, hasNsNodes = 0;
11996 /* The popped object holding the context nodes */
11997 xmlXPathObjectPtr obj;
11998 /* The set of context nodes for the node tests */
11999 xmlNodeSetPtr contextSeq;
12000 int contextIdx;
12001 xmlNodePtr contextNode;
12002 /* The final resulting node set wrt to all context nodes */
12003 xmlNodeSetPtr outSeq;
12004 /*
12005 * The temporary resulting node set wrt 1 context node.
12006 * Used to feed predicate evaluation.
12007 */
12008 xmlNodeSetPtr seq;
12009 xmlNodePtr cur;
12010 /* First predicate operator */
12011 xmlXPathStepOpPtr predOp;
12012 int maxPos; /* The requested position() (when a "[n]" predicate) */
12013 int hasPredicateRange, hasAxisRange, pos;
12014 int breakOnFirstHit;
12015
12016 xmlXPathTraversalFunction next = NULL;
12017 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12018 xmlXPathNodeSetMergeFunction mergeAndClear;
12019 xmlNodePtr oldContextNode;
12020 xmlXPathContextPtr xpctxt = ctxt->context;
12021
12022
12023 CHECK_TYPE0(XPATH_NODESET);
12024 obj = valuePop(ctxt);
12025 /*
12026 * Setup namespaces.
12027 */
12028 if (prefix != NULL) {
12029 URI = xmlXPathNsLookup(xpctxt, prefix);
12030 if (URI == NULL) {
12031 xmlXPathReleaseObject(xpctxt, obj);
12032 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12033 }
12034 }
12035 /*
12036 * Setup axis.
12037 *
12038 * MAYBE FUTURE TODO: merging optimizations:
12039 * - If the nodes to be traversed wrt to the initial nodes and
12040 * the current axis cannot overlap, then we could avoid searching
12041 * for duplicates during the merge.
12042 * But the question is how/when to evaluate if they cannot overlap.
12043 * Example: if we know that for two initial nodes, the one is
12044 * not in the ancestor-or-self axis of the other, then we could safely
12045 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12046 * the descendant-or-self axis.
12047 */
12048 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12049 switch (axis) {
12050 case AXIS_ANCESTOR:
12051 first = NULL;
12052 next = xmlXPathNextAncestor;
12053 break;
12054 case AXIS_ANCESTOR_OR_SELF:
12055 first = NULL;
12056 next = xmlXPathNextAncestorOrSelf;
12057 break;
12058 case AXIS_ATTRIBUTE:
12059 first = NULL;
12060 last = NULL;
12061 next = xmlXPathNextAttribute;
12062 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12063 break;
12064 case AXIS_CHILD:
12065 last = NULL;
12066 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12067 (type == NODE_TYPE_NODE))
12068 {
12069 /*
12070 * Optimization if an element node type is 'element'.
12071 */
12072 next = xmlXPathNextChildElement;
12073 } else
12074 next = xmlXPathNextChild;
12075 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12076 break;
12077 case AXIS_DESCENDANT:
12078 last = NULL;
12079 next = xmlXPathNextDescendant;
12080 break;
12081 case AXIS_DESCENDANT_OR_SELF:
12082 last = NULL;
12083 next = xmlXPathNextDescendantOrSelf;
12084 break;
12085 case AXIS_FOLLOWING:
12086 last = NULL;
12087 next = xmlXPathNextFollowing;
12088 break;
12089 case AXIS_FOLLOWING_SIBLING:
12090 last = NULL;
12091 next = xmlXPathNextFollowingSibling;
12092 break;
12093 case AXIS_NAMESPACE:
12094 first = NULL;
12095 last = NULL;
12096 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12097 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12098 break;
12099 case AXIS_PARENT:
12100 first = NULL;
12101 next = xmlXPathNextParent;
12102 break;
12103 case AXIS_PRECEDING:
12104 first = NULL;
12105 next = xmlXPathNextPrecedingInternal;
12106 break;
12107 case AXIS_PRECEDING_SIBLING:
12108 first = NULL;
12109 next = xmlXPathNextPrecedingSibling;
12110 break;
12111 case AXIS_SELF:
12112 first = NULL;
12113 last = NULL;
12114 next = xmlXPathNextSelf;
12115 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12116 break;
12117 }
12118
12119#ifdef DEBUG_STEP
12120 xmlXPathDebugDumpStepAxis(op,
12121 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12122#endif
12123
12124 if (next == NULL) {
12125 xmlXPathReleaseObject(xpctxt, obj);
12126 return(0);
12127 }
12128 contextSeq = obj->nodesetval;
12129 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12130 xmlXPathReleaseObject(xpctxt, obj);
12131 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12132 return(0);
12133 }
12134 /*
12135 * Predicate optimization ---------------------------------------------
12136 * If this step has a last predicate, which contains a position(),
12137 * then we'll optimize (although not exactly "position()", but only
12138 * the short-hand form, i.e., "[n]".
12139 *
12140 * Example - expression "/foo[parent::bar][1]":
12141 *
12142 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12143 * ROOT -- op->ch1
12144 * PREDICATE -- op->ch2 (predOp)
12145 * PREDICATE -- predOp->ch1 = [parent::bar]
12146 * SORT
12147 * COLLECT 'parent' 'name' 'node' bar
12148 * NODE
12149 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12150 *
12151 */
12152 maxPos = 0;
12153 predOp = NULL;
12154 hasPredicateRange = 0;
12155 hasAxisRange = 0;
12156 if (op->ch2 != -1) {
12157 /*
12158 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12159 */
12160 predOp = &ctxt->comp->steps[op->ch2];
12161 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12162 if (predOp->ch1 != -1) {
12163 /*
12164 * Use the next inner predicate operator.
12165 */
12166 predOp = &ctxt->comp->steps[predOp->ch1];
12167 hasPredicateRange = 1;
12168 } else {
12169 /*
12170 * There's no other predicate than the [n] predicate.
12171 */
12172 predOp = NULL;
12173 hasAxisRange = 1;
12174 }
12175 }
12176 }
12177 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12178 /*
12179 * Axis traversal -----------------------------------------------------
12180 */
12181 /*
12182 * 2.3 Node Tests
12183 * - For the attribute axis, the principal node type is attribute.
12184 * - For the namespace axis, the principal node type is namespace.
12185 * - For other axes, the principal node type is element.
12186 *
12187 * A node test * is true for any node of the
12188 * principal node type. For example, child::* will
12189 * select all element children of the context node
12190 */
12191 oldContextNode = xpctxt->node;
12192 addNode = xmlXPathNodeSetAddUnique;
12193 outSeq = NULL;
12194 seq = NULL;
12195 contextNode = NULL;
12196 contextIdx = 0;
12197
12198
12199 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12200 (ctxt->error == XPATH_EXPRESSION_OK)) {
12201 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12202
12203 if (seq == NULL) {
12204 seq = xmlXPathNodeSetCreate(NULL);
12205 if (seq == NULL) {
12206 /* TODO: Propagate memory error. */
12207 total = 0;
12208 goto error;
12209 }
12210 }
12211 /*
12212 * Traverse the axis and test the nodes.
12213 */
12214 pos = 0;
12215 cur = NULL;
12216 hasNsNodes = 0;
12217 do {
12218 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12219 goto error;
12220
12221 cur = next(ctxt, cur);
12222 if (cur == NULL)
12223 break;
12224
12225 /*
12226 * QUESTION TODO: What does the "first" and "last" stuff do?
12227 */
12228 if ((first != NULL) && (*first != NULL)) {
12229 if (*first == cur)
12230 break;
12231 if (((total % 256) == 0) &&
12232#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12233 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12234#else
12235 (xmlXPathCmpNodes(*first, cur) >= 0))
12236#endif
12237 {
12238 break;
12239 }
12240 }
12241 if ((last != NULL) && (*last != NULL)) {
12242 if (*last == cur)
12243 break;
12244 if (((total % 256) == 0) &&
12245#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12246 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12247#else
12248 (xmlXPathCmpNodes(cur, *last) >= 0))
12249#endif
12250 {
12251 break;
12252 }
12253 }
12254
12255 total++;
12256
12257#ifdef DEBUG_STEP
12258 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12259#endif
12260
12261 switch (test) {
12262 case NODE_TEST_NONE:
12263 total = 0;
12264 STRANGE
12265 goto error;
12266 case NODE_TEST_TYPE:
12267 if (type == NODE_TYPE_NODE) {
12268 switch (cur->type) {
12269 case XML_DOCUMENT_NODE:
12270 case XML_HTML_DOCUMENT_NODE:
12271#ifdef LIBXML_DOCB_ENABLED
12272 case XML_DOCB_DOCUMENT_NODE:
12273#endif
12274 case XML_ELEMENT_NODE:
12275 case XML_ATTRIBUTE_NODE:
12276 case XML_PI_NODE:
12277 case XML_COMMENT_NODE:
12278 case XML_CDATA_SECTION_NODE:
12279 case XML_TEXT_NODE:
12280 XP_TEST_HIT
12281 break;
12282 case XML_NAMESPACE_DECL: {
12283 if (axis == AXIS_NAMESPACE) {
12284 XP_TEST_HIT_NS
12285 } else {
12286 hasNsNodes = 1;
12287 XP_TEST_HIT
12288 }
12289 break;
12290 }
12291 default:
12292 break;
12293 }
12294 } else if (cur->type == (xmlElementType) type) {
12295 if (cur->type == XML_NAMESPACE_DECL)
12296 XP_TEST_HIT_NS
12297 else
12298 XP_TEST_HIT
12299 } else if ((type == NODE_TYPE_TEXT) &&
12300 (cur->type == XML_CDATA_SECTION_NODE))
12301 {
12302 XP_TEST_HIT
12303 }
12304 break;
12305 case NODE_TEST_PI:
12306 if ((cur->type == XML_PI_NODE) &&
12307 ((name == NULL) || xmlStrEqual(name, cur->name)))
12308 {
12309 XP_TEST_HIT
12310 }
12311 break;
12312 case NODE_TEST_ALL:
12313 if (axis == AXIS_ATTRIBUTE) {
12314 if (cur->type == XML_ATTRIBUTE_NODE)
12315 {
12316 if (prefix == NULL)
12317 {
12318 XP_TEST_HIT
12319 } else if ((cur->ns != NULL) &&
12320 (xmlStrEqual(URI, cur->ns->href)))
12321 {
12322 XP_TEST_HIT
12323 }
12324 }
12325 } else if (axis == AXIS_NAMESPACE) {
12326 if (cur->type == XML_NAMESPACE_DECL)
12327 {
12328 XP_TEST_HIT_NS
12329 }
12330 } else {
12331 if (cur->type == XML_ELEMENT_NODE) {
12332 if (prefix == NULL)
12333 {
12334 XP_TEST_HIT
12335
12336 } else if ((cur->ns != NULL) &&
12337 (xmlStrEqual(URI, cur->ns->href)))
12338 {
12339 XP_TEST_HIT
12340 }
12341 }
12342 }
12343 break;
12344 case NODE_TEST_NS:{
12345 TODO;
12346 break;
12347 }
12348 case NODE_TEST_NAME:
12349 if (axis == AXIS_ATTRIBUTE) {
12350 if (cur->type != XML_ATTRIBUTE_NODE)
12351 break;
12352 } else if (axis == AXIS_NAMESPACE) {
12353 if (cur->type != XML_NAMESPACE_DECL)
12354 break;
12355 } else {
12356 if (cur->type != XML_ELEMENT_NODE)
12357 break;
12358 }
12359 switch (cur->type) {
12360 case XML_ELEMENT_NODE:
12361 if (xmlStrEqual(name, cur->name)) {
12362 if (prefix == NULL) {
12363 if (cur->ns == NULL)
12364 {
12365 XP_TEST_HIT
12366 }
12367 } else {
12368 if ((cur->ns != NULL) &&
12369 (xmlStrEqual(URI, cur->ns->href)))
12370 {
12371 XP_TEST_HIT
12372 }
12373 }
12374 }
12375 break;
12376 case XML_ATTRIBUTE_NODE:{
12377 xmlAttrPtr attr = (xmlAttrPtr) cur;
12378
12379 if (xmlStrEqual(name, attr->name)) {
12380 if (prefix == NULL) {
12381 if ((attr->ns == NULL) ||
12382 (attr->ns->prefix == NULL))
12383 {
12384 XP_TEST_HIT
12385 }
12386 } else {
12387 if ((attr->ns != NULL) &&
12388 (xmlStrEqual(URI,
12389 attr->ns->href)))
12390 {
12391 XP_TEST_HIT
12392 }
12393 }
12394 }
12395 break;
12396 }
12397 case XML_NAMESPACE_DECL:
12398 if (cur->type == XML_NAMESPACE_DECL) {
12399 xmlNsPtr ns = (xmlNsPtr) cur;
12400
12401 if ((ns->prefix != NULL) && (name != NULL)
12402 && (xmlStrEqual(ns->prefix, name)))
12403 {
12404 XP_TEST_HIT_NS
12405 }
12406 }
12407 break;
12408 default:
12409 break;
12410 }
12411 break;
12412 } /* switch(test) */
12413 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12414
12415 goto apply_predicates;
12416
12417axis_range_end: /* ----------------------------------------------------- */
12418 /*
12419 * We have a "/foo[n]", and position() = n was reached.
12420 * Note that we can have as well "/foo/::parent::foo[1]", so
12421 * a duplicate-aware merge is still needed.
12422 * Merge with the result.
12423 */
12424 if (outSeq == NULL) {
12425 outSeq = seq;
12426 seq = NULL;
12427 } else
12428 /* TODO: Check memory error. */
12429 outSeq = mergeAndClear(outSeq, seq);
12430 /*
12431 * Break if only a true/false result was requested.
12432 */
12433 if (toBool)
12434 break;
12435 continue;
12436
12437first_hit: /* ---------------------------------------------------------- */
12438 /*
12439 * Break if only a true/false result was requested and
12440 * no predicates existed and a node test succeeded.
12441 */
12442 if (outSeq == NULL) {
12443 outSeq = seq;
12444 seq = NULL;
12445 } else
12446 /* TODO: Check memory error. */
12447 outSeq = mergeAndClear(outSeq, seq);
12448 break;
12449
12450#ifdef DEBUG_STEP
12451 if (seq != NULL)
12452 nbMatches += seq->nodeNr;
12453#endif
12454
12455apply_predicates: /* --------------------------------------------------- */
12456 if (ctxt->error != XPATH_EXPRESSION_OK)
12457 goto error;
12458
12459 /*
12460 * Apply predicates.
12461 */
12462 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12463 /*
12464 * E.g. when we have a "/foo[some expression][n]".
12465 */
12466 /*
12467 * QUESTION TODO: The old predicate evaluation took into
12468 * account location-sets.
12469 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12470 * Do we expect such a set here?
12471 * All what I learned now from the evaluation semantics
12472 * does not indicate that a location-set will be processed
12473 * here, so this looks OK.
12474 */
12475 /*
12476 * Iterate over all predicates, starting with the outermost
12477 * predicate.
12478 * TODO: Problem: we cannot execute the inner predicates first
12479 * since we cannot go back *up* the operator tree!
12480 * Options we have:
12481 * 1) Use of recursive functions (like is it currently done
12482 * via xmlXPathCompOpEval())
12483 * 2) Add a predicate evaluation information stack to the
12484 * context struct
12485 * 3) Change the way the operators are linked; we need a
12486 * "parent" field on xmlXPathStepOp
12487 *
12488 * For the moment, I'll try to solve this with a recursive
12489 * function: xmlXPathCompOpEvalPredicate().
12490 */
12491 if (hasPredicateRange != 0)
12492 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12493 hasNsNodes);
12494 else
12495 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12496 hasNsNodes);
12497
12498 if (ctxt->error != XPATH_EXPRESSION_OK) {
12499 total = 0;
12500 goto error;
12501 }
12502 }
12503
12504 if (seq->nodeNr > 0) {
12505 /*
12506 * Add to result set.
12507 */
12508 if (outSeq == NULL) {
12509 outSeq = seq;
12510 seq = NULL;
12511 } else {
12512 /* TODO: Check memory error. */
12513 outSeq = mergeAndClear(outSeq, seq);
12514 }
12515
12516 if (toBool)
12517 break;
12518 }
12519 }
12520
12521error:
12522 if ((obj->boolval) && (obj->user != NULL)) {
12523 /*
12524 * QUESTION TODO: What does this do and why?
12525 * TODO: Do we have to do this also for the "error"
12526 * cleanup further down?
12527 */
12528 ctxt->value->boolval = 1;
12529 ctxt->value->user = obj->user;
12530 obj->user = NULL;
12531 obj->boolval = 0;
12532 }
12533 xmlXPathReleaseObject(xpctxt, obj);
12534
12535 /*
12536 * Ensure we return at least an empty set.
12537 */
12538 if (outSeq == NULL) {
12539 if ((seq != NULL) && (seq->nodeNr == 0))
12540 outSeq = seq;
12541 else
12542 /* TODO: Check memory error. */
12543 outSeq = xmlXPathNodeSetCreate(NULL);
12544 }
12545 if ((seq != NULL) && (seq != outSeq)) {
12546 xmlXPathFreeNodeSet(seq);
12547 }
12548 /*
12549 * Hand over the result. Better to push the set also in
12550 * case of errors.
12551 */
12552 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12553 /*
12554 * Reset the context node.
12555 */
12556 xpctxt->node = oldContextNode;
12557 /*
12558 * When traversing the namespace axis in "toBool" mode, it's
12559 * possible that tmpNsList wasn't freed.
12560 */
12561 if (xpctxt->tmpNsList != NULL) {
12562 xmlFree(xpctxt->tmpNsList);
12563 xpctxt->tmpNsList = NULL;
12564 }
12565
12566#ifdef DEBUG_STEP
12567 xmlGenericError(xmlGenericErrorContext,
12568 "\nExamined %d nodes, found %d nodes at that step\n",
12569 total, nbMatches);
12570#endif
12571
12572 return(total);
12573}
12574
12575static int
12576xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12577 xmlXPathStepOpPtr op, xmlNodePtr * first);
12578
12579/**
12580 * xmlXPathCompOpEvalFirst:
12581 * @ctxt: the XPath parser context with the compiled expression
12582 * @op: an XPath compiled operation
12583 * @first: the first elem found so far
12584 *
12585 * Evaluate the Precompiled XPath operation searching only the first
12586 * element in document order
12587 *
12588 * Returns the number of examined objects.
12589 */
12590static int
12591xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12592 xmlXPathStepOpPtr op, xmlNodePtr * first)
12593{
12594 int total = 0, cur;
12595 xmlXPathCompExprPtr comp;
12596 xmlXPathObjectPtr arg1, arg2;
12597
12598 CHECK_ERROR0;
12599 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12600 return(0);
12601 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12602 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12603 ctxt->context->depth += 1;
12604 comp = ctxt->comp;
12605 switch (op->op) {
12606 case XPATH_OP_END:
12607 break;
12608 case XPATH_OP_UNION:
12609 total =
12610 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12611 first);
12612 CHECK_ERROR0;
12613 if ((ctxt->value != NULL)
12614 && (ctxt->value->type == XPATH_NODESET)
12615 && (ctxt->value->nodesetval != NULL)
12616 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12617 /*
12618 * limit tree traversing to first node in the result
12619 */
12620 /*
12621 * OPTIMIZE TODO: This implicitly sorts
12622 * the result, even if not needed. E.g. if the argument
12623 * of the count() function, no sorting is needed.
12624 * OPTIMIZE TODO: How do we know if the node-list wasn't
12625 * already sorted?
12626 */
12627 if (ctxt->value->nodesetval->nodeNr > 1)
12628 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12629 *first = ctxt->value->nodesetval->nodeTab[0];
12630 }
12631 cur =
12632 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12633 first);
12634 CHECK_ERROR0;
12635
12636 arg2 = valuePop(ctxt);
12637 arg1 = valuePop(ctxt);
12638 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12639 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12640 xmlXPathReleaseObject(ctxt->context, arg1);
12641 xmlXPathReleaseObject(ctxt->context, arg2);
12642 XP_ERROR0(XPATH_INVALID_TYPE);
12643 }
12644 if ((ctxt->context->opLimit != 0) &&
12645 (((arg1->nodesetval != NULL) &&
12646 (xmlXPathCheckOpLimit(ctxt,
12647 arg1->nodesetval->nodeNr) < 0)) ||
12648 ((arg2->nodesetval != NULL) &&
12649 (xmlXPathCheckOpLimit(ctxt,
12650 arg2->nodesetval->nodeNr) < 0)))) {
12651 xmlXPathReleaseObject(ctxt->context, arg1);
12652 xmlXPathReleaseObject(ctxt->context, arg2);
12653 break;
12654 }
12655
12656 /* TODO: Check memory error. */
12657 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12658 arg2->nodesetval);
12659 valuePush(ctxt, arg1);
12660 xmlXPathReleaseObject(ctxt->context, arg2);
12661 /* optimizer */
12662 if (total > cur)
12663 xmlXPathCompSwap(op);
12664 total += cur;
12665 break;
12666 case XPATH_OP_ROOT:
12667 xmlXPathRoot(ctxt);
12668 break;
12669 case XPATH_OP_NODE:
12670 if (op->ch1 != -1)
12671 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12672 CHECK_ERROR0;
12673 if (op->ch2 != -1)
12674 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12675 CHECK_ERROR0;
12676 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12677 ctxt->context->node));
12678 break;
12679 case XPATH_OP_COLLECT:{
12680 if (op->ch1 == -1)
12681 break;
12682
12683 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12684 CHECK_ERROR0;
12685
12686 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12687 break;
12688 }
12689 case XPATH_OP_VALUE:
12690 valuePush(ctxt,
12691 xmlXPathCacheObjectCopy(ctxt->context,
12692 (xmlXPathObjectPtr) op->value4));
12693 break;
12694 case XPATH_OP_SORT:
12695 if (op->ch1 != -1)
12696 total +=
12697 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12698 first);
12699 CHECK_ERROR0;
12700 if ((ctxt->value != NULL)
12701 && (ctxt->value->type == XPATH_NODESET)
12702 && (ctxt->value->nodesetval != NULL)
12703 && (ctxt->value->nodesetval->nodeNr > 1))
12704 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12705 break;
12706#ifdef XP_OPTIMIZED_FILTER_FIRST
12707 case XPATH_OP_FILTER:
12708 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12709 break;
12710#endif
12711 default:
12712 total += xmlXPathCompOpEval(ctxt, op);
12713 break;
12714 }
12715
12716 ctxt->context->depth -= 1;
12717 return(total);
12718}
12719
12720/**
12721 * xmlXPathCompOpEvalLast:
12722 * @ctxt: the XPath parser context with the compiled expression
12723 * @op: an XPath compiled operation
12724 * @last: the last elem found so far
12725 *
12726 * Evaluate the Precompiled XPath operation searching only the last
12727 * element in document order
12728 *
12729 * Returns the number of nodes traversed
12730 */
12731static int
12732xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12733 xmlNodePtr * last)
12734{
12735 int total = 0, cur;
12736 xmlXPathCompExprPtr comp;
12737 xmlXPathObjectPtr arg1, arg2;
12738
12739 CHECK_ERROR0;
12740 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12741 return(0);
12742 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12743 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12744 ctxt->context->depth += 1;
12745 comp = ctxt->comp;
12746 switch (op->op) {
12747 case XPATH_OP_END:
12748 break;
12749 case XPATH_OP_UNION:
12750 total =
12751 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12752 CHECK_ERROR0;
12753 if ((ctxt->value != NULL)
12754 && (ctxt->value->type == XPATH_NODESET)
12755 && (ctxt->value->nodesetval != NULL)
12756 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12757 /*
12758 * limit tree traversing to first node in the result
12759 */
12760 if (ctxt->value->nodesetval->nodeNr > 1)
12761 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12762 *last =
12763 ctxt->value->nodesetval->nodeTab[ctxt->value->
12764 nodesetval->nodeNr -
12765 1];
12766 }
12767 cur =
12768 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12769 CHECK_ERROR0;
12770 if ((ctxt->value != NULL)
12771 && (ctxt->value->type == XPATH_NODESET)
12772 && (ctxt->value->nodesetval != NULL)
12773 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12774 }
12775
12776 arg2 = valuePop(ctxt);
12777 arg1 = valuePop(ctxt);
12778 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12779 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12780 xmlXPathReleaseObject(ctxt->context, arg1);
12781 xmlXPathReleaseObject(ctxt->context, arg2);
12782 XP_ERROR0(XPATH_INVALID_TYPE);
12783 }
12784 if ((ctxt->context->opLimit != 0) &&
12785 (((arg1->nodesetval != NULL) &&
12786 (xmlXPathCheckOpLimit(ctxt,
12787 arg1->nodesetval->nodeNr) < 0)) ||
12788 ((arg2->nodesetval != NULL) &&
12789 (xmlXPathCheckOpLimit(ctxt,
12790 arg2->nodesetval->nodeNr) < 0)))) {
12791 xmlXPathReleaseObject(ctxt->context, arg1);
12792 xmlXPathReleaseObject(ctxt->context, arg2);
12793 break;
12794 }
12795
12796 /* TODO: Check memory error. */
12797 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12798 arg2->nodesetval);
12799 valuePush(ctxt, arg1);
12800 xmlXPathReleaseObject(ctxt->context, arg2);
12801 /* optimizer */
12802 if (total > cur)
12803 xmlXPathCompSwap(op);
12804 total += cur;
12805 break;
12806 case XPATH_OP_ROOT:
12807 xmlXPathRoot(ctxt);
12808 break;
12809 case XPATH_OP_NODE:
12810 if (op->ch1 != -1)
12811 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12812 CHECK_ERROR0;
12813 if (op->ch2 != -1)
12814 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12815 CHECK_ERROR0;
12816 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12817 ctxt->context->node));
12818 break;
12819 case XPATH_OP_COLLECT:{
12820 if (op->ch1 == -1)
12821 break;
12822
12823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12824 CHECK_ERROR0;
12825
12826 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12827 break;
12828 }
12829 case XPATH_OP_VALUE:
12830 valuePush(ctxt,
12831 xmlXPathCacheObjectCopy(ctxt->context,
12832 (xmlXPathObjectPtr) op->value4));
12833 break;
12834 case XPATH_OP_SORT:
12835 if (op->ch1 != -1)
12836 total +=
12837 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12838 last);
12839 CHECK_ERROR0;
12840 if ((ctxt->value != NULL)
12841 && (ctxt->value->type == XPATH_NODESET)
12842 && (ctxt->value->nodesetval != NULL)
12843 && (ctxt->value->nodesetval->nodeNr > 1))
12844 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12845 break;
12846 default:
12847 total += xmlXPathCompOpEval(ctxt, op);
12848 break;
12849 }
12850
12851 ctxt->context->depth -= 1;
12852 return (total);
12853}
12854
12855#ifdef XP_OPTIMIZED_FILTER_FIRST
12856static int
12857xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12858 xmlXPathStepOpPtr op, xmlNodePtr * first)
12859{
12860 int total = 0;
12861 xmlXPathCompExprPtr comp;
12862 xmlNodeSetPtr set;
12863
12864 CHECK_ERROR0;
12865 comp = ctxt->comp;
12866 /*
12867 * Optimization for ()[last()] selection i.e. the last elem
12868 */
12869 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12870 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12871 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12872 int f = comp->steps[op->ch2].ch1;
12873
12874 if ((f != -1) &&
12875 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12876 (comp->steps[f].value5 == NULL) &&
12877 (comp->steps[f].value == 0) &&
12878 (comp->steps[f].value4 != NULL) &&
12879 (xmlStrEqual
12880 (comp->steps[f].value4, BAD_CAST "last"))) {
12881 xmlNodePtr last = NULL;
12882
12883 total +=
12884 xmlXPathCompOpEvalLast(ctxt,
12885 &comp->steps[op->ch1],
12886 &last);
12887 CHECK_ERROR0;
12888 /*
12889 * The nodeset should be in document order,
12890 * Keep only the last value
12891 */
12892 if ((ctxt->value != NULL) &&
12893 (ctxt->value->type == XPATH_NODESET) &&
12894 (ctxt->value->nodesetval != NULL) &&
12895 (ctxt->value->nodesetval->nodeTab != NULL) &&
12896 (ctxt->value->nodesetval->nodeNr > 1)) {
12897 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12898 *first = *(ctxt->value->nodesetval->nodeTab);
12899 }
12900 return (total);
12901 }
12902 }
12903
12904 if (op->ch1 != -1)
12905 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12906 CHECK_ERROR0;
12907 if (op->ch2 == -1)
12908 return (total);
12909 if (ctxt->value == NULL)
12910 return (total);
12911
12912#ifdef LIBXML_XPTR_ENABLED
12913 /*
12914 * Hum are we filtering the result of an XPointer expression
12915 */
12916 if (ctxt->value->type == XPATH_LOCATIONSET) {
12917 xmlLocationSetPtr locset = ctxt->value->user;
12918
12919 if (locset != NULL) {
12920 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12921 if (locset->locNr > 0)
12922 *first = (xmlNodePtr) locset->locTab[0]->user;
12923 }
12924
12925 return (total);
12926 }
12927#endif /* LIBXML_XPTR_ENABLED */
12928
12929 CHECK_TYPE0(XPATH_NODESET);
12930 set = ctxt->value->nodesetval;
12931 if (set != NULL) {
12932 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12933 if (set->nodeNr > 0)
12934 *first = set->nodeTab[0];
12935 }
12936
12937 return (total);
12938}
12939#endif /* XP_OPTIMIZED_FILTER_FIRST */
12940
12941/**
12942 * xmlXPathCompOpEval:
12943 * @ctxt: the XPath parser context with the compiled expression
12944 * @op: an XPath compiled operation
12945 *
12946 * Evaluate the Precompiled XPath operation
12947 * Returns the number of nodes traversed
12948 */
12949static int
12950xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12951{
12952 int total = 0;
12953 int equal, ret;
12954 xmlXPathCompExprPtr comp;
12955 xmlXPathObjectPtr arg1, arg2;
12956
12957 CHECK_ERROR0;
12958 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12959 return(0);
12960 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12961 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12962 ctxt->context->depth += 1;
12963 comp = ctxt->comp;
12964 switch (op->op) {
12965 case XPATH_OP_END:
12966 break;
12967 case XPATH_OP_AND:
12968 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12969 CHECK_ERROR0;
12970 xmlXPathBooleanFunction(ctxt, 1);
12971 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12972 break;
12973 arg2 = valuePop(ctxt);
12974 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12975 if (ctxt->error) {
12976 xmlXPathFreeObject(arg2);
12977 break;
12978 }
12979 xmlXPathBooleanFunction(ctxt, 1);
12980 if (ctxt->value != NULL)
12981 ctxt->value->boolval &= arg2->boolval;
12982 xmlXPathReleaseObject(ctxt->context, arg2);
12983 break;
12984 case XPATH_OP_OR:
12985 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12986 CHECK_ERROR0;
12987 xmlXPathBooleanFunction(ctxt, 1);
12988 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12989 break;
12990 arg2 = valuePop(ctxt);
12991 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12992 if (ctxt->error) {
12993 xmlXPathFreeObject(arg2);
12994 break;
12995 }
12996 xmlXPathBooleanFunction(ctxt, 1);
12997 if (ctxt->value != NULL)
12998 ctxt->value->boolval |= arg2->boolval;
12999 xmlXPathReleaseObject(ctxt->context, arg2);
13000 break;
13001 case XPATH_OP_EQUAL:
13002 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13003 CHECK_ERROR0;
13004 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13005 CHECK_ERROR0;
13006 if (op->value)
13007 equal = xmlXPathEqualValues(ctxt);
13008 else
13009 equal = xmlXPathNotEqualValues(ctxt);
13010 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13011 break;
13012 case XPATH_OP_CMP:
13013 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13014 CHECK_ERROR0;
13015 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13016 CHECK_ERROR0;
13017 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13018 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13019 break;
13020 case XPATH_OP_PLUS:
13021 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13022 CHECK_ERROR0;
13023 if (op->ch2 != -1) {
13024 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13025 }
13026 CHECK_ERROR0;
13027 if (op->value == 0)
13028 xmlXPathSubValues(ctxt);
13029 else if (op->value == 1)
13030 xmlXPathAddValues(ctxt);
13031 else if (op->value == 2)
13032 xmlXPathValueFlipSign(ctxt);
13033 else if (op->value == 3) {
13034 CAST_TO_NUMBER;
13035 CHECK_TYPE0(XPATH_NUMBER);
13036 }
13037 break;
13038 case XPATH_OP_MULT:
13039 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13040 CHECK_ERROR0;
13041 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13042 CHECK_ERROR0;
13043 if (op->value == 0)
13044 xmlXPathMultValues(ctxt);
13045 else if (op->value == 1)
13046 xmlXPathDivValues(ctxt);
13047 else if (op->value == 2)
13048 xmlXPathModValues(ctxt);
13049 break;
13050 case XPATH_OP_UNION:
13051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13052 CHECK_ERROR0;
13053 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13054 CHECK_ERROR0;
13055
13056 arg2 = valuePop(ctxt);
13057 arg1 = valuePop(ctxt);
13058 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13059 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13060 xmlXPathReleaseObject(ctxt->context, arg1);
13061 xmlXPathReleaseObject(ctxt->context, arg2);
13062 XP_ERROR0(XPATH_INVALID_TYPE);
13063 }
13064 if ((ctxt->context->opLimit != 0) &&
13065 (((arg1->nodesetval != NULL) &&
13066 (xmlXPathCheckOpLimit(ctxt,
13067 arg1->nodesetval->nodeNr) < 0)) ||
13068 ((arg2->nodesetval != NULL) &&
13069 (xmlXPathCheckOpLimit(ctxt,
13070 arg2->nodesetval->nodeNr) < 0)))) {
13071 xmlXPathReleaseObject(ctxt->context, arg1);
13072 xmlXPathReleaseObject(ctxt->context, arg2);
13073 break;
13074 }
13075
13076 if ((arg1->nodesetval == NULL) ||
13077 ((arg2->nodesetval != NULL) &&
13078 (arg2->nodesetval->nodeNr != 0)))
13079 {
13080 /* TODO: Check memory error. */
13081 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13082 arg2->nodesetval);
13083 }
13084
13085 valuePush(ctxt, arg1);
13086 xmlXPathReleaseObject(ctxt->context, arg2);
13087 break;
13088 case XPATH_OP_ROOT:
13089 xmlXPathRoot(ctxt);
13090 break;
13091 case XPATH_OP_NODE:
13092 if (op->ch1 != -1)
13093 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13094 CHECK_ERROR0;
13095 if (op->ch2 != -1)
13096 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13097 CHECK_ERROR0;
13098 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13099 ctxt->context->node));
13100 break;
13101 case XPATH_OP_COLLECT:{
13102 if (op->ch1 == -1)
13103 break;
13104
13105 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13106 CHECK_ERROR0;
13107
13108 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13109 break;
13110 }
13111 case XPATH_OP_VALUE:
13112 valuePush(ctxt,
13113 xmlXPathCacheObjectCopy(ctxt->context,
13114 (xmlXPathObjectPtr) op->value4));
13115 break;
13116 case XPATH_OP_VARIABLE:{
13117 xmlXPathObjectPtr val;
13118
13119 if (op->ch1 != -1)
13120 total +=
13121 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13122 if (op->value5 == NULL) {
13123 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13124 if (val == NULL)
13125 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13126 valuePush(ctxt, val);
13127 } else {
13128 const xmlChar *URI;
13129
13130 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13131 if (URI == NULL) {
13132 xmlGenericError(xmlGenericErrorContext,
13133 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13134 (char *) op->value4, (char *)op->value5);
13135 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13136 break;
13137 }
13138 val = xmlXPathVariableLookupNS(ctxt->context,
13139 op->value4, URI);
13140 if (val == NULL)
13141 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13142 valuePush(ctxt, val);
13143 }
13144 break;
13145 }
13146 case XPATH_OP_FUNCTION:{
13147 xmlXPathFunction func;
13148 const xmlChar *oldFunc, *oldFuncURI;
13149 int i;
13150 int frame;
13151
13152 frame = xmlXPathSetFrame(ctxt);
13153 if (op->ch1 != -1) {
13154 total +=
13155 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13156 if (ctxt->error != XPATH_EXPRESSION_OK) {
13157 xmlXPathPopFrame(ctxt, frame);
13158 break;
13159 }
13160 }
13161 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13162 xmlGenericError(xmlGenericErrorContext,
13163 "xmlXPathCompOpEval: parameter error\n");
13164 ctxt->error = XPATH_INVALID_OPERAND;
13165 xmlXPathPopFrame(ctxt, frame);
13166 break;
13167 }
13168 for (i = 0; i < op->value; i++) {
13169 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13170 xmlGenericError(xmlGenericErrorContext,
13171 "xmlXPathCompOpEval: parameter error\n");
13172 ctxt->error = XPATH_INVALID_OPERAND;
13173 xmlXPathPopFrame(ctxt, frame);
13174 break;
13175 }
13176 }
13177 if (op->cache != NULL)
13178 func = op->cache;
13179 else {
13180 const xmlChar *URI = NULL;
13181
13182 if (op->value5 == NULL)
13183 func =
13184 xmlXPathFunctionLookup(ctxt->context,
13185 op->value4);
13186 else {
13187 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13188 if (URI == NULL) {
13189 xmlGenericError(xmlGenericErrorContext,
13190 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13191 (char *)op->value4, (char *)op->value5);
13192 xmlXPathPopFrame(ctxt, frame);
13193 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13194 break;
13195 }
13196 func = xmlXPathFunctionLookupNS(ctxt->context,
13197 op->value4, URI);
13198 }
13199 if (func == NULL) {
13200 xmlGenericError(xmlGenericErrorContext,
13201 "xmlXPathCompOpEval: function %s not found\n",
13202 (char *)op->value4);
13203 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13204 }
13205 op->cache = func;
13206 op->cacheURI = (void *) URI;
13207 }
13208 oldFunc = ctxt->context->function;
13209 oldFuncURI = ctxt->context->functionURI;
13210 ctxt->context->function = op->value4;
13211 ctxt->context->functionURI = op->cacheURI;
13212 func(ctxt, op->value);
13213 ctxt->context->function = oldFunc;
13214 ctxt->context->functionURI = oldFuncURI;
13215 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13216 (ctxt->valueNr != ctxt->valueFrame + 1))
13217 XP_ERROR0(XPATH_STACK_ERROR);
13218 xmlXPathPopFrame(ctxt, frame);
13219 break;
13220 }
13221 case XPATH_OP_ARG:
13222 if (op->ch1 != -1) {
13223 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13224 CHECK_ERROR0;
13225 }
13226 if (op->ch2 != -1) {
13227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13228 CHECK_ERROR0;
13229 }
13230 break;
13231 case XPATH_OP_PREDICATE:
13232 case XPATH_OP_FILTER:{
13233 xmlNodeSetPtr set;
13234
13235 /*
13236 * Optimization for ()[1] selection i.e. the first elem
13237 */
13238 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13239#ifdef XP_OPTIMIZED_FILTER_FIRST
13240 /*
13241 * FILTER TODO: Can we assume that the inner processing
13242 * will result in an ordered list if we have an
13243 * XPATH_OP_FILTER?
13244 * What about an additional field or flag on
13245 * xmlXPathObject like @sorted ? This way we wouldn't need
13246 * to assume anything, so it would be more robust and
13247 * easier to optimize.
13248 */
13249 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13250 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13251#else
13252 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13253#endif
13254 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13255 xmlXPathObjectPtr val;
13256
13257 val = comp->steps[op->ch2].value4;
13258 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13259 (val->floatval == 1.0)) {
13260 xmlNodePtr first = NULL;
13261
13262 total +=
13263 xmlXPathCompOpEvalFirst(ctxt,
13264 &comp->steps[op->ch1],
13265 &first);
13266 CHECK_ERROR0;
13267 /*
13268 * The nodeset should be in document order,
13269 * Keep only the first value
13270 */
13271 if ((ctxt->value != NULL) &&
13272 (ctxt->value->type == XPATH_NODESET) &&
13273 (ctxt->value->nodesetval != NULL) &&
13274 (ctxt->value->nodesetval->nodeNr > 1))
13275 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13276 1, 1);
13277 break;
13278 }
13279 }
13280 /*
13281 * Optimization for ()[last()] selection i.e. the last elem
13282 */
13283 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13284 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13285 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13286 int f = comp->steps[op->ch2].ch1;
13287
13288 if ((f != -1) &&
13289 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13290 (comp->steps[f].value5 == NULL) &&
13291 (comp->steps[f].value == 0) &&
13292 (comp->steps[f].value4 != NULL) &&
13293 (xmlStrEqual
13294 (comp->steps[f].value4, BAD_CAST "last"))) {
13295 xmlNodePtr last = NULL;
13296
13297 total +=
13298 xmlXPathCompOpEvalLast(ctxt,
13299 &comp->steps[op->ch1],
13300 &last);
13301 CHECK_ERROR0;
13302 /*
13303 * The nodeset should be in document order,
13304 * Keep only the last value
13305 */
13306 if ((ctxt->value != NULL) &&
13307 (ctxt->value->type == XPATH_NODESET) &&
13308 (ctxt->value->nodesetval != NULL) &&
13309 (ctxt->value->nodesetval->nodeTab != NULL) &&
13310 (ctxt->value->nodesetval->nodeNr > 1))
13311 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13312 break;
13313 }
13314 }
13315 /*
13316 * Process inner predicates first.
13317 * Example "index[parent::book][1]":
13318 * ...
13319 * PREDICATE <-- we are here "[1]"
13320 * PREDICATE <-- process "[parent::book]" first
13321 * SORT
13322 * COLLECT 'parent' 'name' 'node' book
13323 * NODE
13324 * ELEM Object is a number : 1
13325 */
13326 if (op->ch1 != -1)
13327 total +=
13328 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13329 CHECK_ERROR0;
13330 if (op->ch2 == -1)
13331 break;
13332 if (ctxt->value == NULL)
13333 break;
13334
13335#ifdef LIBXML_XPTR_ENABLED
13336 /*
13337 * Hum are we filtering the result of an XPointer expression
13338 */
13339 if (ctxt->value->type == XPATH_LOCATIONSET) {
13340 xmlLocationSetPtr locset = ctxt->value->user;
13341 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13342 1, locset->locNr);
13343 break;
13344 }
13345#endif /* LIBXML_XPTR_ENABLED */
13346
13347 CHECK_TYPE0(XPATH_NODESET);
13348 set = ctxt->value->nodesetval;
13349 if (set != NULL)
13350 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13351 1, set->nodeNr, 1);
13352 break;
13353 }
13354 case XPATH_OP_SORT:
13355 if (op->ch1 != -1)
13356 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13357 CHECK_ERROR0;
13358 if ((ctxt->value != NULL) &&
13359 (ctxt->value->type == XPATH_NODESET) &&
13360 (ctxt->value->nodesetval != NULL) &&
13361 (ctxt->value->nodesetval->nodeNr > 1))
13362 {
13363 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13364 }
13365 break;
13366#ifdef LIBXML_XPTR_ENABLED
13367 case XPATH_OP_RANGETO:{
13368 xmlXPathObjectPtr range;
13369 xmlXPathObjectPtr res, obj;
13370 xmlXPathObjectPtr tmp;
13371 xmlLocationSetPtr newlocset = NULL;
13372 xmlLocationSetPtr oldlocset;
13373 xmlNodeSetPtr oldset;
13374 xmlNodePtr oldnode = ctxt->context->node;
13375 int oldcs = ctxt->context->contextSize;
13376 int oldpp = ctxt->context->proximityPosition;
13377 int i, j;
13378
13379 if (op->ch1 != -1) {
13380 total +=
13381 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13382 CHECK_ERROR0;
13383 }
13384 if (ctxt->value == NULL) {
13385 XP_ERROR0(XPATH_INVALID_OPERAND);
13386 }
13387 if (op->ch2 == -1)
13388 break;
13389
13390 if (ctxt->value->type == XPATH_LOCATIONSET) {
13391 /*
13392 * Extract the old locset, and then evaluate the result of the
13393 * expression for all the element in the locset. use it to grow
13394 * up a new locset.
13395 */
13396 CHECK_TYPE0(XPATH_LOCATIONSET);
13397
13398 if ((ctxt->value->user == NULL) ||
13399 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13400 break;
13401
13402 obj = valuePop(ctxt);
13403 oldlocset = obj->user;
13404
13405 newlocset = xmlXPtrLocationSetCreate(NULL);
13406
13407 for (i = 0; i < oldlocset->locNr; i++) {
13408 /*
13409 * Run the evaluation with a node list made of a
13410 * single item in the nodelocset.
13411 */
13412 ctxt->context->node = oldlocset->locTab[i]->user;
13413 ctxt->context->contextSize = oldlocset->locNr;
13414 ctxt->context->proximityPosition = i + 1;
13415 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13416 ctxt->context->node);
13417 valuePush(ctxt, tmp);
13418
13419 if (op->ch2 != -1)
13420 total +=
13421 xmlXPathCompOpEval(ctxt,
13422 &comp->steps[op->ch2]);
13423 if (ctxt->error != XPATH_EXPRESSION_OK) {
13424 xmlXPtrFreeLocationSet(newlocset);
13425 goto rangeto_error;
13426 }
13427
13428 res = valuePop(ctxt);
13429 if (res->type == XPATH_LOCATIONSET) {
13430 xmlLocationSetPtr rloc =
13431 (xmlLocationSetPtr)res->user;
13432 for (j=0; j<rloc->locNr; j++) {
13433 range = xmlXPtrNewRange(
13434 oldlocset->locTab[i]->user,
13435 oldlocset->locTab[i]->index,
13436 rloc->locTab[j]->user2,
13437 rloc->locTab[j]->index2);
13438 if (range != NULL) {
13439 xmlXPtrLocationSetAdd(newlocset, range);
13440 }
13441 }
13442 } else {
13443 range = xmlXPtrNewRangeNodeObject(
13444 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13445 if (range != NULL) {
13446 xmlXPtrLocationSetAdd(newlocset,range);
13447 }
13448 }
13449
13450 /*
13451 * Cleanup
13452 */
13453 if (res != NULL) {
13454 xmlXPathReleaseObject(ctxt->context, res);
13455 }
13456 if (ctxt->value == tmp) {
13457 res = valuePop(ctxt);
13458 xmlXPathReleaseObject(ctxt->context, res);
13459 }
13460 }
13461 } else { /* Not a location set */
13462 CHECK_TYPE0(XPATH_NODESET);
13463 obj = valuePop(ctxt);
13464 oldset = obj->nodesetval;
13465
13466 newlocset = xmlXPtrLocationSetCreate(NULL);
13467
13468 if (oldset != NULL) {
13469 for (i = 0; i < oldset->nodeNr; i++) {
13470 /*
13471 * Run the evaluation with a node list made of a single item
13472 * in the nodeset.
13473 */
13474 ctxt->context->node = oldset->nodeTab[i];
13475 /*
13476 * OPTIMIZE TODO: Avoid recreation for every iteration.
13477 */
13478 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13479 ctxt->context->node);
13480 valuePush(ctxt, tmp);
13481
13482 if (op->ch2 != -1)
13483 total +=
13484 xmlXPathCompOpEval(ctxt,
13485 &comp->steps[op->ch2]);
13486 if (ctxt->error != XPATH_EXPRESSION_OK) {
13487 xmlXPtrFreeLocationSet(newlocset);
13488 goto rangeto_error;
13489 }
13490
13491 res = valuePop(ctxt);
13492 range =
13493 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13494 res);
13495 if (range != NULL) {
13496 xmlXPtrLocationSetAdd(newlocset, range);
13497 }
13498
13499 /*
13500 * Cleanup
13501 */
13502 if (res != NULL) {
13503 xmlXPathReleaseObject(ctxt->context, res);
13504 }
13505 if (ctxt->value == tmp) {
13506 res = valuePop(ctxt);
13507 xmlXPathReleaseObject(ctxt->context, res);
13508 }
13509 }
13510 }
13511 }
13512
13513 /*
13514 * The result is used as the new evaluation set.
13515 */
13516 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13517rangeto_error:
13518 xmlXPathReleaseObject(ctxt->context, obj);
13519 ctxt->context->node = oldnode;
13520 ctxt->context->contextSize = oldcs;
13521 ctxt->context->proximityPosition = oldpp;
13522 break;
13523 }
13524#endif /* LIBXML_XPTR_ENABLED */
13525 default:
13526 xmlGenericError(xmlGenericErrorContext,
13527 "XPath: unknown precompiled operation %d\n", op->op);
13528 ctxt->error = XPATH_INVALID_OPERAND;
13529 break;
13530 }
13531
13532 ctxt->context->depth -= 1;
13533 return (total);
13534}
13535
13536/**
13537 * xmlXPathCompOpEvalToBoolean:
13538 * @ctxt: the XPath parser context
13539 *
13540 * Evaluates if the expression evaluates to true.
13541 *
13542 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13543 */
13544static int
13545xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13546 xmlXPathStepOpPtr op,
13547 int isPredicate)
13548{
13549 xmlXPathObjectPtr resObj = NULL;
13550
13551start:
13552 if (OP_LIMIT_EXCEEDED(ctxt, 1))
13553 return(0);
13554 /* comp = ctxt->comp; */
13555 switch (op->op) {
13556 case XPATH_OP_END:
13557 return (0);
13558 case XPATH_OP_VALUE:
13559 resObj = (xmlXPathObjectPtr) op->value4;
13560 if (isPredicate)
13561 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13562 return(xmlXPathCastToBoolean(resObj));
13563 case XPATH_OP_SORT:
13564 /*
13565 * We don't need sorting for boolean results. Skip this one.
13566 */
13567 if (op->ch1 != -1) {
13568 op = &ctxt->comp->steps[op->ch1];
13569 goto start;
13570 }
13571 return(0);
13572 case XPATH_OP_COLLECT:
13573 if (op->ch1 == -1)
13574 return(0);
13575
13576 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13577 if (ctxt->error != XPATH_EXPRESSION_OK)
13578 return(-1);
13579
13580 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13581 if (ctxt->error != XPATH_EXPRESSION_OK)
13582 return(-1);
13583
13584 resObj = valuePop(ctxt);
13585 if (resObj == NULL)
13586 return(-1);
13587 break;
13588 default:
13589 /*
13590 * Fallback to call xmlXPathCompOpEval().
13591 */
13592 xmlXPathCompOpEval(ctxt, op);
13593 if (ctxt->error != XPATH_EXPRESSION_OK)
13594 return(-1);
13595
13596 resObj = valuePop(ctxt);
13597 if (resObj == NULL)
13598 return(-1);
13599 break;
13600 }
13601
13602 if (resObj) {
13603 int res;
13604
13605 if (resObj->type == XPATH_BOOLEAN) {
13606 res = resObj->boolval;
13607 } else if (isPredicate) {
13608 /*
13609 * For predicates a result of type "number" is handled
13610 * differently:
13611 * SPEC XPath 1.0:
13612 * "If the result is a number, the result will be converted
13613 * to true if the number is equal to the context position
13614 * and will be converted to false otherwise;"
13615 */
13616 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13617 } else {
13618 res = xmlXPathCastToBoolean(resObj);
13619 }
13620 xmlXPathReleaseObject(ctxt->context, resObj);
13621 return(res);
13622 }
13623
13624 return(0);
13625}
13626
13627#ifdef XPATH_STREAMING
13628/**
13629 * xmlXPathRunStreamEval:
13630 * @ctxt: the XPath parser context with the compiled expression
13631 *
13632 * Evaluate the Precompiled Streamable XPath expression in the given context.
13633 */
13634static int
13635xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13636 xmlXPathObjectPtr *resultSeq, int toBool)
13637{
13638 int max_depth, min_depth;
13639 int from_root;
13640 int ret, depth;
13641 int eval_all_nodes;
13642 xmlNodePtr cur = NULL, limit = NULL;
13643 xmlStreamCtxtPtr patstream = NULL;
13644
13645 int nb_nodes = 0;
13646
13647 if ((ctxt == NULL) || (comp == NULL))
13648 return(-1);
13649 max_depth = xmlPatternMaxDepth(comp);
13650 if (max_depth == -1)
13651 return(-1);
13652 if (max_depth == -2)
13653 max_depth = 10000;
13654 min_depth = xmlPatternMinDepth(comp);
13655 if (min_depth == -1)
13656 return(-1);
13657 from_root = xmlPatternFromRoot(comp);
13658 if (from_root < 0)
13659 return(-1);
13660#if 0
13661 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13662#endif
13663
13664 if (! toBool) {
13665 if (resultSeq == NULL)
13666 return(-1);
13667 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13668 if (*resultSeq == NULL)
13669 return(-1);
13670 }
13671
13672 /*
13673 * handle the special cases of "/" amd "." being matched
13674 */
13675 if (min_depth == 0) {
13676 if (from_root) {
13677 /* Select "/" */
13678 if (toBool)
13679 return(1);
13680 /* TODO: Check memory error. */
13681 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13682 (xmlNodePtr) ctxt->doc);
13683 } else {
13684 /* Select "self::node()" */
13685 if (toBool)
13686 return(1);
13687 /* TODO: Check memory error. */
13688 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13689 }
13690 }
13691 if (max_depth == 0) {
13692 return(0);
13693 }
13694
13695 if (from_root) {
13696 cur = (xmlNodePtr)ctxt->doc;
13697 } else if (ctxt->node != NULL) {
13698 switch (ctxt->node->type) {
13699 case XML_ELEMENT_NODE:
13700 case XML_DOCUMENT_NODE:
13701 case XML_DOCUMENT_FRAG_NODE:
13702 case XML_HTML_DOCUMENT_NODE:
13703#ifdef LIBXML_DOCB_ENABLED
13704 case XML_DOCB_DOCUMENT_NODE:
13705#endif
13706 cur = ctxt->node;
13707 break;
13708 case XML_ATTRIBUTE_NODE:
13709 case XML_TEXT_NODE:
13710 case XML_CDATA_SECTION_NODE:
13711 case XML_ENTITY_REF_NODE:
13712 case XML_ENTITY_NODE:
13713 case XML_PI_NODE:
13714 case XML_COMMENT_NODE:
13715 case XML_NOTATION_NODE:
13716 case XML_DTD_NODE:
13717 case XML_DOCUMENT_TYPE_NODE:
13718 case XML_ELEMENT_DECL:
13719 case XML_ATTRIBUTE_DECL:
13720 case XML_ENTITY_DECL:
13721 case XML_NAMESPACE_DECL:
13722 case XML_XINCLUDE_START:
13723 case XML_XINCLUDE_END:
13724 break;
13725 }
13726 limit = cur;
13727 }
13728 if (cur == NULL) {
13729 return(0);
13730 }
13731
13732 patstream = xmlPatternGetStreamCtxt(comp);
13733 if (patstream == NULL) {
13734 /*
13735 * QUESTION TODO: Is this an error?
13736 */
13737 return(0);
13738 }
13739
13740 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13741
13742 if (from_root) {
13743 ret = xmlStreamPush(patstream, NULL, NULL);
13744 if (ret < 0) {
13745 } else if (ret == 1) {
13746 if (toBool)
13747 goto return_1;
13748 /* TODO: Check memory error. */
13749 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13750 }
13751 }
13752 depth = 0;
13753 goto scan_children;
13754next_node:
13755 do {
13756 if (ctxt->opLimit != 0) {
13757 if (ctxt->opCount >= ctxt->opLimit) {
13758 xmlGenericError(xmlGenericErrorContext,
13759 "XPath operation limit exceeded\n");
13760 xmlFreeStreamCtxt(patstream);
13761 return(-1);
13762 }
13763 ctxt->opCount++;
13764 }
13765
13766 nb_nodes++;
13767
13768 switch (cur->type) {
13769 case XML_ELEMENT_NODE:
13770 case XML_TEXT_NODE:
13771 case XML_CDATA_SECTION_NODE:
13772 case XML_COMMENT_NODE:
13773 case XML_PI_NODE:
13774 if (cur->type == XML_ELEMENT_NODE) {
13775 ret = xmlStreamPush(patstream, cur->name,
13776 (cur->ns ? cur->ns->href : NULL));
13777 } else if (eval_all_nodes)
13778 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13779 else
13780 break;
13781
13782 if (ret < 0) {
13783 /* NOP. */
13784 } else if (ret == 1) {
13785 if (toBool)
13786 goto return_1;
13787 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13788 < 0) {
13789 ctxt->lastError.domain = XML_FROM_XPATH;
13790 ctxt->lastError.code = XML_ERR_NO_MEMORY;
13791 }
13792 }
13793 if ((cur->children == NULL) || (depth >= max_depth)) {
13794 ret = xmlStreamPop(patstream);
13795 while (cur->next != NULL) {
13796 cur = cur->next;
13797 if ((cur->type != XML_ENTITY_DECL) &&
13798 (cur->type != XML_DTD_NODE))
13799 goto next_node;
13800 }
13801 }
13802 default:
13803 break;
13804 }
13805
13806scan_children:
13807 if (cur->type == XML_NAMESPACE_DECL) break;
13808 if ((cur->children != NULL) && (depth < max_depth)) {
13809 /*
13810 * Do not descend on entities declarations
13811 */
13812 if (cur->children->type != XML_ENTITY_DECL) {
13813 cur = cur->children;
13814 depth++;
13815 /*
13816 * Skip DTDs
13817 */
13818 if (cur->type != XML_DTD_NODE)
13819 continue;
13820 }
13821 }
13822
13823 if (cur == limit)
13824 break;
13825
13826 while (cur->next != NULL) {
13827 cur = cur->next;
13828 if ((cur->type != XML_ENTITY_DECL) &&
13829 (cur->type != XML_DTD_NODE))
13830 goto next_node;
13831 }
13832
13833 do {
13834 cur = cur->parent;
13835 depth--;
13836 if ((cur == NULL) || (cur == limit) ||
13837 (cur->type == XML_DOCUMENT_NODE))
13838 goto done;
13839 if (cur->type == XML_ELEMENT_NODE) {
13840 ret = xmlStreamPop(patstream);
13841 } else if ((eval_all_nodes) &&
13842 ((cur->type == XML_TEXT_NODE) ||
13843 (cur->type == XML_CDATA_SECTION_NODE) ||
13844 (cur->type == XML_COMMENT_NODE) ||
13845 (cur->type == XML_PI_NODE)))
13846 {
13847 ret = xmlStreamPop(patstream);
13848 }
13849 if (cur->next != NULL) {
13850 cur = cur->next;
13851 break;
13852 }
13853 } while (cur != NULL);
13854
13855 } while ((cur != NULL) && (depth >= 0));
13856
13857done:
13858
13859#if 0
13860 printf("stream eval: checked %d nodes selected %d\n",
13861 nb_nodes, retObj->nodesetval->nodeNr);
13862#endif
13863
13864 if (patstream)
13865 xmlFreeStreamCtxt(patstream);
13866 return(0);
13867
13868return_1:
13869 if (patstream)
13870 xmlFreeStreamCtxt(patstream);
13871 return(1);
13872}
13873#endif /* XPATH_STREAMING */
13874
13875/**
13876 * xmlXPathRunEval:
13877 * @ctxt: the XPath parser context with the compiled expression
13878 * @toBool: evaluate to a boolean result
13879 *
13880 * Evaluate the Precompiled XPath expression in the given context.
13881 */
13882static int
13883xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13884{
13885 xmlXPathCompExprPtr comp;
13886
13887 if ((ctxt == NULL) || (ctxt->comp == NULL))
13888 return(-1);
13889
13890 ctxt->context->depth = 0;
13891
13892 if (ctxt->valueTab == NULL) {
13893 /* Allocate the value stack */
13894 ctxt->valueTab = (xmlXPathObjectPtr *)
13895 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13896 if (ctxt->valueTab == NULL) {
13897 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13898 xmlFree(ctxt);
13899 }
13900 ctxt->valueNr = 0;
13901 ctxt->valueMax = 10;
13902 ctxt->value = NULL;
13903 ctxt->valueFrame = 0;
13904 }
13905#ifdef XPATH_STREAMING
13906 if (ctxt->comp->stream) {
13907 int res;
13908
13909 if (toBool) {
13910 /*
13911 * Evaluation to boolean result.
13912 */
13913 res = xmlXPathRunStreamEval(ctxt->context,
13914 ctxt->comp->stream, NULL, 1);
13915 if (res != -1)
13916 return(res);
13917 } else {
13918 xmlXPathObjectPtr resObj = NULL;
13919
13920 /*
13921 * Evaluation to a sequence.
13922 */
13923 res = xmlXPathRunStreamEval(ctxt->context,
13924 ctxt->comp->stream, &resObj, 0);
13925
13926 if ((res != -1) && (resObj != NULL)) {
13927 valuePush(ctxt, resObj);
13928 return(0);
13929 }
13930 if (resObj != NULL)
13931 xmlXPathReleaseObject(ctxt->context, resObj);
13932 }
13933 /*
13934 * QUESTION TODO: This falls back to normal XPath evaluation
13935 * if res == -1. Is this intended?
13936 */
13937 }
13938#endif
13939 comp = ctxt->comp;
13940 if (comp->last < 0) {
13941 xmlGenericError(xmlGenericErrorContext,
13942 "xmlXPathRunEval: last is less than zero\n");
13943 return(-1);
13944 }
13945 if (toBool)
13946 return(xmlXPathCompOpEvalToBoolean(ctxt,
13947 &comp->steps[comp->last], 0));
13948 else
13949 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13950
13951 return(0);
13952}
13953
13954/************************************************************************
13955 * *
13956 * Public interfaces *
13957 * *
13958 ************************************************************************/
13959
13960/**
13961 * xmlXPathEvalPredicate:
13962 * @ctxt: the XPath context
13963 * @res: the Predicate Expression evaluation result
13964 *
13965 * Evaluate a predicate result for the current node.
13966 * A PredicateExpr is evaluated by evaluating the Expr and converting
13967 * the result to a boolean. If the result is a number, the result will
13968 * be converted to true if the number is equal to the position of the
13969 * context node in the context node list (as returned by the position
13970 * function) and will be converted to false otherwise; if the result
13971 * is not a number, then the result will be converted as if by a call
13972 * to the boolean function.
13973 *
13974 * Returns 1 if predicate is true, 0 otherwise
13975 */
13976int
13977xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13978 if ((ctxt == NULL) || (res == NULL)) return(0);
13979 switch (res->type) {
13980 case XPATH_BOOLEAN:
13981 return(res->boolval);
13982 case XPATH_NUMBER:
13983 return(res->floatval == ctxt->proximityPosition);
13984 case XPATH_NODESET:
13985 case XPATH_XSLT_TREE:
13986 if (res->nodesetval == NULL)
13987 return(0);
13988 return(res->nodesetval->nodeNr != 0);
13989 case XPATH_STRING:
13990 return((res->stringval != NULL) &&
13991 (xmlStrlen(res->stringval) != 0));
13992 default:
13993 STRANGE
13994 }
13995 return(0);
13996}
13997
13998/**
13999 * xmlXPathEvaluatePredicateResult:
14000 * @ctxt: the XPath Parser context
14001 * @res: the Predicate Expression evaluation result
14002 *
14003 * Evaluate a predicate result for the current node.
14004 * A PredicateExpr is evaluated by evaluating the Expr and converting
14005 * the result to a boolean. If the result is a number, the result will
14006 * be converted to true if the number is equal to the position of the
14007 * context node in the context node list (as returned by the position
14008 * function) and will be converted to false otherwise; if the result
14009 * is not a number, then the result will be converted as if by a call
14010 * to the boolean function.
14011 *
14012 * Returns 1 if predicate is true, 0 otherwise
14013 */
14014int
14015xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14016 xmlXPathObjectPtr res) {
14017 if ((ctxt == NULL) || (res == NULL)) return(0);
14018 switch (res->type) {
14019 case XPATH_BOOLEAN:
14020 return(res->boolval);
14021 case XPATH_NUMBER:
14022#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14023 return((res->floatval == ctxt->context->proximityPosition) &&
14024 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14025#else
14026 return(res->floatval == ctxt->context->proximityPosition);
14027#endif
14028 case XPATH_NODESET:
14029 case XPATH_XSLT_TREE:
14030 if (res->nodesetval == NULL)
14031 return(0);
14032 return(res->nodesetval->nodeNr != 0);
14033 case XPATH_STRING:
14034 return((res->stringval != NULL) && (res->stringval[0] != 0));
14035#ifdef LIBXML_XPTR_ENABLED
14036 case XPATH_LOCATIONSET:{
14037 xmlLocationSetPtr ptr = res->user;
14038 if (ptr == NULL)
14039 return(0);
14040 return (ptr->locNr != 0);
14041 }
14042#endif
14043 default:
14044 STRANGE
14045 }
14046 return(0);
14047}
14048
14049#ifdef XPATH_STREAMING
14050/**
14051 * xmlXPathTryStreamCompile:
14052 * @ctxt: an XPath context
14053 * @str: the XPath expression
14054 *
14055 * Try to compile the XPath expression as a streamable subset.
14056 *
14057 * Returns the compiled expression or NULL if failed to compile.
14058 */
14059static xmlXPathCompExprPtr
14060xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14061 /*
14062 * Optimization: use streaming patterns when the XPath expression can
14063 * be compiled to a stream lookup
14064 */
14065 xmlPatternPtr stream;
14066 xmlXPathCompExprPtr comp;
14067 xmlDictPtr dict = NULL;
14068 const xmlChar **namespaces = NULL;
14069 xmlNsPtr ns;
14070 int i, j;
14071
14072 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14073 (!xmlStrchr(str, '@'))) {
14074 const xmlChar *tmp;
14075
14076 /*
14077 * We don't try to handle expressions using the verbose axis
14078 * specifiers ("::"), just the simplified form at this point.
14079 * Additionally, if there is no list of namespaces available and
14080 * there's a ":" in the expression, indicating a prefixed QName,
14081 * then we won't try to compile either. xmlPatterncompile() needs
14082 * to have a list of namespaces at compilation time in order to
14083 * compile prefixed name tests.
14084 */
14085 tmp = xmlStrchr(str, ':');
14086 if ((tmp != NULL) &&
14087 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14088 return(NULL);
14089
14090 if (ctxt != NULL) {
14091 dict = ctxt->dict;
14092 if (ctxt->nsNr > 0) {
14093 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14094 if (namespaces == NULL) {
14095 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14096 return(NULL);
14097 }
14098 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14099 ns = ctxt->namespaces[j];
14100 namespaces[i++] = ns->href;
14101 namespaces[i++] = ns->prefix;
14102 }
14103 namespaces[i++] = NULL;
14104 namespaces[i] = NULL;
14105 }
14106 }
14107
14108 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14109 if (namespaces != NULL) {
14110 xmlFree((xmlChar **)namespaces);
14111 }
14112 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14113 comp = xmlXPathNewCompExpr();
14114 if (comp == NULL) {
14115 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14116 return(NULL);
14117 }
14118 comp->stream = stream;
14119 comp->dict = dict;
14120 if (comp->dict)
14121 xmlDictReference(comp->dict);
14122 return(comp);
14123 }
14124 xmlFreePattern(stream);
14125 }
14126 return(NULL);
14127}
14128#endif /* XPATH_STREAMING */
14129
14130static void
14131xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14132 xmlXPathStepOpPtr op)
14133{
14134 xmlXPathCompExprPtr comp = pctxt->comp;
14135 xmlXPathContextPtr ctxt;
14136
14137 /*
14138 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14139 * internal representation.
14140 */
14141
14142 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14143 (op->ch1 != -1) &&
14144 (op->ch2 == -1 /* no predicate */))
14145 {
14146 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14147
14148 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14149 ((xmlXPathAxisVal) prevop->value ==
14150 AXIS_DESCENDANT_OR_SELF) &&
14151 (prevop->ch2 == -1) &&
14152 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14153 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14154 {
14155 /*
14156 * This is a "descendant-or-self::node()" without predicates.
14157 * Try to eliminate it.
14158 */
14159
14160 switch ((xmlXPathAxisVal) op->value) {
14161 case AXIS_CHILD:
14162 case AXIS_DESCENDANT:
14163 /*
14164 * Convert "descendant-or-self::node()/child::" or
14165 * "descendant-or-self::node()/descendant::" to
14166 * "descendant::"
14167 */
14168 op->ch1 = prevop->ch1;
14169 op->value = AXIS_DESCENDANT;
14170 break;
14171 case AXIS_SELF:
14172 case AXIS_DESCENDANT_OR_SELF:
14173 /*
14174 * Convert "descendant-or-self::node()/self::" or
14175 * "descendant-or-self::node()/descendant-or-self::" to
14176 * to "descendant-or-self::"
14177 */
14178 op->ch1 = prevop->ch1;
14179 op->value = AXIS_DESCENDANT_OR_SELF;
14180 break;
14181 default:
14182 break;
14183 }
14184 }
14185 }
14186
14187 /* OP_VALUE has invalid ch1. */
14188 if (op->op == XPATH_OP_VALUE)
14189 return;
14190
14191 /* Recurse */
14192 ctxt = pctxt->context;
14193 if (ctxt != NULL) {
14194 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14195 return;
14196 ctxt->depth += 1;
14197 }
14198 if (op->ch1 != -1)
14199 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14200 if (op->ch2 != -1)
14201 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14202 if (ctxt != NULL)
14203 ctxt->depth -= 1;
14204}
14205
14206/**
14207 * xmlXPathCtxtCompile:
14208 * @ctxt: an XPath context
14209 * @str: the XPath expression
14210 *
14211 * Compile an XPath expression
14212 *
14213 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14214 * the caller has to free the object.
14215 */
14216xmlXPathCompExprPtr
14217xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14218 xmlXPathParserContextPtr pctxt;
14219 xmlXPathCompExprPtr comp;
14220
14221#ifdef XPATH_STREAMING
14222 comp = xmlXPathTryStreamCompile(ctxt, str);
14223 if (comp != NULL)
14224 return(comp);
14225#endif
14226
14227 xmlInitParser();
14228
14229 pctxt = xmlXPathNewParserContext(str, ctxt);
14230 if (pctxt == NULL)
14231 return NULL;
14232 if (ctxt != NULL)
14233 ctxt->depth = 0;
14234 xmlXPathCompileExpr(pctxt, 1);
14235
14236 if( pctxt->error != XPATH_EXPRESSION_OK )
14237 {
14238 xmlXPathFreeParserContext(pctxt);
14239 return(NULL);
14240 }
14241
14242 if (*pctxt->cur != 0) {
14243 /*
14244 * aleksey: in some cases this line prints *second* error message
14245 * (see bug #78858) and probably this should be fixed.
14246 * However, we are not sure that all error messages are printed
14247 * out in other places. It's not critical so we leave it as-is for now
14248 */
14249 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14250 comp = NULL;
14251 } else {
14252 comp = pctxt->comp;
14253 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14254 if (ctxt != NULL)
14255 ctxt->depth = 0;
14256 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14257 }
14258 pctxt->comp = NULL;
14259 }
14260 xmlXPathFreeParserContext(pctxt);
14261
14262 if (comp != NULL) {
14263 comp->expr = xmlStrdup(str);
14264#ifdef DEBUG_EVAL_COUNTS
14265 comp->string = xmlStrdup(str);
14266 comp->nb = 0;
14267#endif
14268 }
14269 return(comp);
14270}
14271
14272/**
14273 * xmlXPathCompile:
14274 * @str: the XPath expression
14275 *
14276 * Compile an XPath expression
14277 *
14278 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14279 * the caller has to free the object.
14280 */
14281xmlXPathCompExprPtr
14282xmlXPathCompile(const xmlChar *str) {
14283 return(xmlXPathCtxtCompile(NULL, str));
14284}
14285
14286/**
14287 * xmlXPathCompiledEvalInternal:
14288 * @comp: the compiled XPath expression
14289 * @ctxt: the XPath context
14290 * @resObj: the resulting XPath object or NULL
14291 * @toBool: 1 if only a boolean result is requested
14292 *
14293 * Evaluate the Precompiled XPath expression in the given context.
14294 * The caller has to free @resObj.
14295 *
14296 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14297 * the caller has to free the object.
14298 */
14299static int
14300xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14301 xmlXPathContextPtr ctxt,
14302 xmlXPathObjectPtr *resObjPtr,
14303 int toBool)
14304{
14305 xmlXPathParserContextPtr pctxt;
14306 xmlXPathObjectPtr resObj;
14307#ifndef LIBXML_THREAD_ENABLED
14308 static int reentance = 0;
14309#endif
14310 int res;
14311
14312 CHECK_CTXT_NEG(ctxt)
14313
14314 if (comp == NULL)
14315 return(-1);
14316 xmlInitParser();
14317
14318#ifndef LIBXML_THREAD_ENABLED
14319 reentance++;
14320 if (reentance > 1)
14321 xmlXPathDisableOptimizer = 1;
14322#endif
14323
14324#ifdef DEBUG_EVAL_COUNTS
14325 comp->nb++;
14326 if ((comp->string != NULL) && (comp->nb > 100)) {
14327 fprintf(stderr, "100 x %s\n", comp->string);
14328 comp->nb = 0;
14329 }
14330#endif
14331 pctxt = xmlXPathCompParserContext(comp, ctxt);
14332 res = xmlXPathRunEval(pctxt, toBool);
14333
14334 if (pctxt->error != XPATH_EXPRESSION_OK) {
14335 resObj = NULL;
14336 } else {
14337 resObj = valuePop(pctxt);
14338 if (resObj == NULL) {
14339 if (!toBool)
14340 xmlGenericError(xmlGenericErrorContext,
14341 "xmlXPathCompiledEval: No result on the stack.\n");
14342 } else if (pctxt->valueNr > 0) {
14343 xmlGenericError(xmlGenericErrorContext,
14344 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14345 pctxt->valueNr);
14346 }
14347 }
14348
14349 if (resObjPtr)
14350 *resObjPtr = resObj;
14351 else
14352 xmlXPathReleaseObject(ctxt, resObj);
14353
14354 pctxt->comp = NULL;
14355 xmlXPathFreeParserContext(pctxt);
14356#ifndef LIBXML_THREAD_ENABLED
14357 reentance--;
14358#endif
14359
14360 return(res);
14361}
14362
14363/**
14364 * xmlXPathCompiledEval:
14365 * @comp: the compiled XPath expression
14366 * @ctx: the XPath context
14367 *
14368 * Evaluate the Precompiled XPath expression in the given context.
14369 *
14370 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14371 * the caller has to free the object.
14372 */
14373xmlXPathObjectPtr
14374xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14375{
14376 xmlXPathObjectPtr res = NULL;
14377
14378 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14379 return(res);
14380}
14381
14382/**
14383 * xmlXPathCompiledEvalToBoolean:
14384 * @comp: the compiled XPath expression
14385 * @ctxt: the XPath context
14386 *
14387 * Applies the XPath boolean() function on the result of the given
14388 * compiled expression.
14389 *
14390 * Returns 1 if the expression evaluated to true, 0 if to false and
14391 * -1 in API and internal errors.
14392 */
14393int
14394xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14395 xmlXPathContextPtr ctxt)
14396{
14397 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14398}
14399
14400/**
14401 * xmlXPathEvalExpr:
14402 * @ctxt: the XPath Parser context
14403 *
14404 * Parse and evaluate an XPath expression in the given context,
14405 * then push the result on the context stack
14406 */
14407void
14408xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14409#ifdef XPATH_STREAMING
14410 xmlXPathCompExprPtr comp;
14411#endif
14412
14413 if (ctxt == NULL) return;
14414
14415#ifdef XPATH_STREAMING
14416 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14417 if (comp != NULL) {
14418 if (ctxt->comp != NULL)
14419 xmlXPathFreeCompExpr(ctxt->comp);
14420 ctxt->comp = comp;
14421 } else
14422#endif
14423 {
14424 if (ctxt->context != NULL)
14425 ctxt->context->depth = 0;
14426 xmlXPathCompileExpr(ctxt, 1);
14427 CHECK_ERROR;
14428
14429 /* Check for trailing characters. */
14430 if (*ctxt->cur != 0)
14431 XP_ERROR(XPATH_EXPR_ERROR);
14432
14433 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14434 if (ctxt->context != NULL)
14435 ctxt->context->depth = 0;
14436 xmlXPathOptimizeExpression(ctxt,
14437 &ctxt->comp->steps[ctxt->comp->last]);
14438 }
14439 }
14440
14441 xmlXPathRunEval(ctxt, 0);
14442}
14443
14444/**
14445 * xmlXPathEval:
14446 * @str: the XPath expression
14447 * @ctx: the XPath context
14448 *
14449 * Evaluate the XPath Location Path in the given context.
14450 *
14451 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14452 * the caller has to free the object.
14453 */
14454xmlXPathObjectPtr
14455xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14456 xmlXPathParserContextPtr ctxt;
14457 xmlXPathObjectPtr res;
14458
14459 CHECK_CTXT(ctx)
14460
14461 xmlInitParser();
14462
14463 ctxt = xmlXPathNewParserContext(str, ctx);
14464 if (ctxt == NULL)
14465 return NULL;
14466 xmlXPathEvalExpr(ctxt);
14467
14468 if (ctxt->error != XPATH_EXPRESSION_OK) {
14469 res = NULL;
14470 } else {
14471 res = valuePop(ctxt);
14472 if (res == NULL) {
14473 xmlGenericError(xmlGenericErrorContext,
14474 "xmlXPathCompiledEval: No result on the stack.\n");
14475 } else if (ctxt->valueNr > 0) {
14476 xmlGenericError(xmlGenericErrorContext,
14477 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14478 ctxt->valueNr);
14479 }
14480 }
14481
14482 xmlXPathFreeParserContext(ctxt);
14483 return(res);
14484}
14485
14486/**
14487 * xmlXPathSetContextNode:
14488 * @node: the node to to use as the context node
14489 * @ctx: the XPath context
14490 *
14491 * Sets 'node' as the context node. The node must be in the same
14492 * document as that associated with the context.
14493 *
14494 * Returns -1 in case of error or 0 if successful
14495 */
14496int
14497xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14498 if ((node == NULL) || (ctx == NULL))
14499 return(-1);
14500
14501 if (node->doc == ctx->doc) {
14502 ctx->node = node;
14503 return(0);
14504 }
14505 return(-1);
14506}
14507
14508/**
14509 * xmlXPathNodeEval:
14510 * @node: the node to to use as the context node
14511 * @str: the XPath expression
14512 * @ctx: the XPath context
14513 *
14514 * Evaluate the XPath Location Path in the given context. The node 'node'
14515 * is set as the context node. The context node is not restored.
14516 *
14517 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14518 * the caller has to free the object.
14519 */
14520xmlXPathObjectPtr
14521xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14522 if (str == NULL)
14523 return(NULL);
14524 if (xmlXPathSetContextNode(node, ctx) < 0)
14525 return(NULL);
14526 return(xmlXPathEval(str, ctx));
14527}
14528
14529/**
14530 * xmlXPathEvalExpression:
14531 * @str: the XPath expression
14532 * @ctxt: the XPath context
14533 *
14534 * Alias for xmlXPathEval().
14535 *
14536 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14537 * the caller has to free the object.
14538 */
14539xmlXPathObjectPtr
14540xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14541 return(xmlXPathEval(str, ctxt));
14542}
14543
14544/************************************************************************
14545 * *
14546 * Extra functions not pertaining to the XPath spec *
14547 * *
14548 ************************************************************************/
14549/**
14550 * xmlXPathEscapeUriFunction:
14551 * @ctxt: the XPath Parser context
14552 * @nargs: the number of arguments
14553 *
14554 * Implement the escape-uri() XPath function
14555 * string escape-uri(string $str, bool $escape-reserved)
14556 *
14557 * This function applies the URI escaping rules defined in section 2 of [RFC
14558 * 2396] to the string supplied as $uri-part, which typically represents all
14559 * or part of a URI. The effect of the function is to replace any special
14560 * character in the string by an escape sequence of the form %xx%yy...,
14561 * where xxyy... is the hexadecimal representation of the octets used to
14562 * represent the character in UTF-8.
14563 *
14564 * The set of characters that are escaped depends on the setting of the
14565 * boolean argument $escape-reserved.
14566 *
14567 * If $escape-reserved is true, all characters are escaped other than lower
14568 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14569 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14570 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14571 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14572 * A-F).
14573 *
14574 * If $escape-reserved is false, the behavior differs in that characters
14575 * referred to in [RFC 2396] as reserved characters are not escaped. These
14576 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14577 *
14578 * [RFC 2396] does not define whether escaped URIs should use lower case or
14579 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14580 * compared using string comparison functions, this function must always use
14581 * the upper-case letters A-F.
14582 *
14583 * Generally, $escape-reserved should be set to true when escaping a string
14584 * that is to form a single part of a URI, and to false when escaping an
14585 * entire URI or URI reference.
14586 *
14587 * In the case of non-ascii characters, the string is encoded according to
14588 * utf-8 and then converted according to RFC 2396.
14589 *
14590 * Examples
14591 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14592 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14593 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14594 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14595 *
14596 */
14597static void
14598xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14599 xmlXPathObjectPtr str;
14600 int escape_reserved;
14601 xmlBufPtr target;
14602 xmlChar *cptr;
14603 xmlChar escape[4];
14604
14605 CHECK_ARITY(2);
14606
14607 escape_reserved = xmlXPathPopBoolean(ctxt);
14608
14609 CAST_TO_STRING;
14610 str = valuePop(ctxt);
14611
14612 target = xmlBufCreate();
14613
14614 escape[0] = '%';
14615 escape[3] = 0;
14616
14617 if (target) {
14618 for (cptr = str->stringval; *cptr; cptr++) {
14619 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14620 (*cptr >= 'a' && *cptr <= 'z') ||
14621 (*cptr >= '0' && *cptr <= '9') ||
14622 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14623 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14624 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14625 (*cptr == '%' &&
14626 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14627 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14628 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14629 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14630 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14631 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14632 (!escape_reserved &&
14633 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14634 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14635 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14636 *cptr == ','))) {
14637 xmlBufAdd(target, cptr, 1);
14638 } else {
14639 if ((*cptr >> 4) < 10)
14640 escape[1] = '0' + (*cptr >> 4);
14641 else
14642 escape[1] = 'A' - 10 + (*cptr >> 4);
14643 if ((*cptr & 0xF) < 10)
14644 escape[2] = '0' + (*cptr & 0xF);
14645 else
14646 escape[2] = 'A' - 10 + (*cptr & 0xF);
14647
14648 xmlBufAdd(target, &escape[0], 3);
14649 }
14650 }
14651 }
14652 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14653 xmlBufContent(target)));
14654 xmlBufFree(target);
14655 xmlXPathReleaseObject(ctxt->context, str);
14656}
14657
14658/**
14659 * xmlXPathRegisterAllFunctions:
14660 * @ctxt: the XPath context
14661 *
14662 * Registers all default XPath functions in this context
14663 */
14664void
14665xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14666{
14667 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14668 xmlXPathBooleanFunction);
14669 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14670 xmlXPathCeilingFunction);
14671 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14672 xmlXPathCountFunction);
14673 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14674 xmlXPathConcatFunction);
14675 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14676 xmlXPathContainsFunction);
14677 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14678 xmlXPathIdFunction);
14679 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14680 xmlXPathFalseFunction);
14681 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14682 xmlXPathFloorFunction);
14683 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14684 xmlXPathLastFunction);
14685 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14686 xmlXPathLangFunction);
14687 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14688 xmlXPathLocalNameFunction);
14689 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14690 xmlXPathNotFunction);
14691 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14692 xmlXPathNameFunction);
14693 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14694 xmlXPathNamespaceURIFunction);
14695 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14696 xmlXPathNormalizeFunction);
14697 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14698 xmlXPathNumberFunction);
14699 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14700 xmlXPathPositionFunction);
14701 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14702 xmlXPathRoundFunction);
14703 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14704 xmlXPathStringFunction);
14705 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14706 xmlXPathStringLengthFunction);
14707 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14708 xmlXPathStartsWithFunction);
14709 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14710 xmlXPathSubstringFunction);
14711 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14712 xmlXPathSubstringBeforeFunction);
14713 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14714 xmlXPathSubstringAfterFunction);
14715 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14716 xmlXPathSumFunction);
14717 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14718 xmlXPathTrueFunction);
14719 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14720 xmlXPathTranslateFunction);
14721
14722 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14723 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14724 xmlXPathEscapeUriFunction);
14725}
14726
14727#endif /* LIBXML_XPATH_ENABLED */
14728#define bottom_xpath
14729#include "elfgcchack.h"
Note: See TracBrowser for help on using the repository browser.

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